OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:16 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: Implementation of assert() in kernel space
PostPosted: Sat Jan 01, 2005 6:44 pm 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
Quote:
this thread is referenced in the FAQ


I want to add some debugging & error-handling facilities to my kernel, and I'm curious about how other people have tackled assert().

For example, let's say some code in a low-level part of the kernel (like the kernel-mode C run-time library) detects a logic error in a debug build and wants to report it via assert(). Here are the choices as I see them (assuming the assertion failed):
  • 1. assert() prints out the file and line number, then panics.
  • 2. assert() tries to capture the current register contents and a kernel stack dump itself, then prints out the file and line number, then panics.
  • 3. assert() prints out the file and line number, then triggers one of the kernel's exception handlers (by executing int 3 maybe), which in turn dumps the machine state that it has already collected, and then panics.

Option 1 is easy to do, but doesn't include machine state in the output. Option 2 seems hard to do (at least to me... maybe I'm missing something?). Option 3 leverages the existing code I have for capturing the context of the current task, but are there any risks associated with this approach?

As an aside, how important is machine state for debugging anyway? My feeling is that it's less important for assert(), since you have file & line numbers available, but it's important for all other cases... If I could probably do without it, I may just go for option 1.
Quote:

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Sun Jan 02, 2005 6:17 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 2:31 am
Posts: 5964
Location: In a galaxy, far, far away
register state may help you figuring out the value of some variable. Probably the result of the assert() computation makes more sense, though.

Eg:
Code:
kassert(ptr->next==p2->next,4,ptr,p2,ptr->next,p2->next);

that would output
"assertion failed at file.c:line X, 8004260, 8004280, 0, 8004280"

_________________
Image May the source be with you.


Top
 Profile  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Sun Jan 02, 2005 12:40 pm 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
That makes sense, and should be easy to do...

I had another thought about making assert trigger a breakpoint exception -- would it be the right way to allow future integration with a remote kernel debugger?

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Tue Jan 04, 2005 12:57 am 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
I did a bit of research... In case anyone is interested, Linux takes the approach I mentioned in its BUG() macro (which is called from at least one version of assert()). It uses the reserved opcode ud2 to defer panicking to the central trap-dispatching mechanism.

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Wed Jan 05, 2005 10:36 am 
i did a VERY basic assert():
Code:
#define assert(check, condition) if (check != condition) kSystem_Halt();


I'll put the full thing once it is tested ;P


Top
  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Wed Jan 05, 2005 2:52 pm 
your assert has a problem (even as simple as it is...) in some cases it can break scoping.. like this:

Code:
   if (foo)
      assert( yabba, dabba );
   else
      something_else( );


this will expand to..

Code:
   if (foo)
      if(yabba != dabba)
         kSystem_Halt;;
      else
         something_else( );


and thus you have a dangling else problem...

to fix this is simple define your assert liek this:

Code:
#define assert(check, condition) do { if(check != condition) kSystem_Halt(); } while(0)


also.... another issue

you shoudl ALWAYS put params of a macro in parethesis to make sure it expands properly for example..suppose i do:

Code:
assert(a & 3, 0);


this will expand to:

Code:
if(a & 3 != 0) kSystem_Halt();


well != has higher priority than & so this acts like this...

Code:
if(a & (3 != 0)) kSystem_Halt();


no bueno...

best is like this:

Code:
#define assert(check, condition) do { if((check) != (condition)) kSystem_Halt(); } while(0)


if EVEN better :) is like this..

Code:
#define assert(check) do { if(!(check)) kSystem_Halt(); } while(0)


this way you can make any comparison you want (not just != ....)

good luck :)

proxy


Top
  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Sun Jan 09, 2005 3:46 pm 
oh ya? I'll study that. Thanks.


Top
  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Sun Jan 09, 2005 6:18 pm 
I think it's better to avoid do{...}while() blocks when you can avoid them. You can write a conditional in a macro in a way that it can be used inside anything, as long as you don't need loops. In fact, you can also do sequence of things if you want too. You can't loop without a block, but then again I don't think looping in macros is that good of a thing anyway, and you can always call a function that does loop.

Code:
#define assert(test) \
  ((test) \
    ? (kprint("assertion failed, " __FILE__ ":" __LINE__ ": " #test), panic()) \
    : 0)


Top
  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Mon Jan 10, 2005 12:48 am 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
I think the loop in this case is necessary though -- as a safeguard in case kSystem_halt fails for some reason and doesn't actually halt the CPU.

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Mon Jan 10, 2005 1:44 am 
Offline
Member
Member
User avatar

Joined: Thu Nov 16, 2006 12:01 pm
Posts: 7612
Location: Germany
Erm... do { } while ( 0 ) does not loop!

The assert() implementation recommended by P.J. Plauger (author of the Dinkumware library and member of the C committee) is indeed the trinary operator though.

What follows is a ripaway from how I implemented assert() in the PDCLib, provided as Public Domain.

assert.h:

Code:
#ifndef _KERNEL_ASSERT
#define _KERNEL_ASSERT
#if __STDC_VERSION__ == 199901L
void _Kassert_99( char const * const, char const * const, char const * const );
#else
void _Kassert( char const * const );
#endif
#define __symbol2value( x ) #x
#define __symbol2string( x ) __symbol2value( x )
#endif

/* re-including assert.h results in assert() being redefined */
#undef assert

#ifdef NDEBUG
#define assert( ignore ) ( (void) 0 )
#else
#if __STDC_VERSION__ == 199901L
#define assert( expression ) ( ( expression ) ? (void) 0 \
        : _Kassert( "Assertion failed: " #expression \
                          ", function ", __func__, \
                          ", file " __FILE__ \
                          ", line " __symbol2string( __LINE__ ) \
                          "." ) )
#else
#define assert( expression ) ( ( expression ) ? (void) 0 \
        : _Kassert( "Assertion failed: " #expression \
                          ", file " __FILE__ \
                          ", line " __symbol2string( __LINE__ ) \
                          "." ) )
#endif
#endif


Implement _Kassert() and _Kassert_99() to do whatever you like. The char* contain e.g.:

"Assertion failed: x == 0, file mykernel.c, line 385." for _Kassert(), and

"Assertion failed: x == 0, function "
"mykernel_map_table"
", file mykernel.c, line 285." for _Kassert_99(), respectively.

Only C99 does have __func__ specified, hence the __STDC_VERSION__ check. Above implementation allows you to use this assert() in exactly the way described by the C standard (i.e., you may include assert.h multiple times, the macro is defined to nothing when NDEBUG is set etc.)

Hope this helps.

_________________
Every good solution is obvious once you've found it.


Top
 Profile  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Mon Jan 10, 2005 9:52 am 
as solar mentioned the "do { } while(0)" is not ment to be a loop at all, it is ment to avoid scope issues (which i gave an example of...) keep in mind that the compiler (even older ones) is smart enough to know not to emit loop related code for this one. it is a VERY common way to properly implement assert.

proxy


Top
  
 
 Post subject: Re:Implementation of assert() in kernel space
PostPosted: Mon Jan 10, 2005 2:06 pm 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
0... 1... Damn those off-by-one errors. ;)

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], rdos, thewrongchristian and 77 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group