debug.c

Go to the documentation of this file.
00001 
00006 #include <stdio.h>
00007 #include <stdarg.h>
00008 #include <ctype.h>
00009 #define DEBUG_C
00010 #include "ctl/ctldef.h"
00011 #include "ctl/debug.h"
00012 
00014 static unsigned debug_logmask = ~0u;
00015 
00017 static debug_vlog_t pdebug_vlog = vprintf;
00018 
00019 ppDebug(static int debug_printf( const char* fmt, ... );)
00020 
00022 ppDebug(debug_trace_t debug_trace = debug_printf;)
00023 
00029 void debug_log( unsigned mask, const char* fmt, ... )
00030 {
00031     assertconst(fmt,1);
00032     assertcodeptr(pdebug_vlog);
00033     if( (mask & debug_logmask) || 0 == mask )
00034     {
00035         va_list args;
00036         va_start( args, fmt );
00037         pdebug_vlog( fmt, args );
00038         fflush(stdout);
00039     }
00040 }
00041 
00048 void debug_vlog( unsigned mask, const char* fmt, va_list args )
00049 {
00050     if( (mask & debug_logmask) || 0 == mask )
00051     {
00052         assertconst(fmt,1);
00053         assertcodeptr(pdebug_vlog);
00054         pdebug_vlog( fmt, args );
00055     }
00056 }
00057 
00062 void debug_logalways(const char* fmt, ... )
00063 {
00064     va_list args;
00065     va_start( args, fmt );
00066     assertconst(fmt,1);
00067     assertcodeptr(pdebug_vlog);
00068     pdebug_vlog( fmt, args );
00069 }
00070 
00076 void debug_vlogalways(const char* fmt, va_list args )
00077 {
00078     assertconst(fmt,1);
00079     assertcodeptr(pdebug_vlog);
00080     pdebug_vlog( fmt, args );
00081 }
00082 
00087 void debug_setvlog( debug_vlog_t debug_vlog )
00088 {
00089     if( NULL == debug_vlog )
00090     {
00091         pdebug_vlog = vprintf;
00092     }
00093     else
00094     {
00095         pdebug_vlog =  debug_vlog;
00096     }
00097     assertcodeptr(pdebug_vlog);
00098 }
00099 
00104 void debug_setlogmask( unsigned mask )
00105 {
00106     debug_logmask = mask;
00107 }
00108 
00113 unsigned debug_getlogmask(void)
00114 {
00115     return debug_logmask;
00116 }
00117 
00124 void debug_loghex( unsigned mask, const void* ptr, size_t size )
00125 {
00126     assertconst(ptr,size);
00127     if( (mask & debug_logmask) || 0 == mask )
00128     {
00129         char printable[16];
00130         const unsigned char* pBuff = (const unsigned char*)ptr;
00131         size_t curr = 0;
00132         while( curr < size )
00133         {
00134             unsigned ch = *pBuff++;
00135             if( 0 == (curr & 0xf) )
00136             {
00137                 debug_logalways( "%08x: ", curr );
00138             }
00139             debug_logalways( "%02x ", ch );
00140             printable[curr&0xf] = isprint(ch) ? ch : '.';
00141             if( 0xf == (curr++ & 0xf) )
00142             {
00143                 debug_logalways( " | %16.16s\n", printable );
00144             }
00145         }
00146         /* Leftovers */
00147         if( 0 != (size & 0xf) )
00148         {
00149             for( curr = curr & 0xf; curr < 16; ++curr )
00150             {
00151                 debug_logalways( "-- " );
00152                 printable[curr] = ' ';
00153             }
00154             debug_logalways( " | %16.16s\n", printable );
00155         }
00156     }
00157 }
00158 
00159 
00160 #ifndef NDEBUG
00161 
00162 /*
00163  * Printf to flush stdout every time; trace functions often mean crashes which 
00164  * could mean output from a recent printf never gets seen while debugging.
00165  */
00166 static int debug_printf( const char* fmt, ... )
00167 {
00168     int ret;
00169     va_list args;
00170     va_start( args, fmt );
00171     ret = vprintf( fmt, args );
00172     fflush(stdout);
00173     return ret;
00174 }
00175 
00180 void debug_settrace( debug_trace_t trace )
00181 {
00182     debug_trace = NULL == trace ? debug_printf : trace;
00183     assertcodeptr(debug_trace);
00184 }
00185 
00186 /* Define this if you have a really sucky memory problem */
00187 /*#define CTL_DELUXE_POINTER_CHECKS*/
00188 
00189 #ifdef WIN32
00190 #include <windows.h>
00191 /*
00192  * For assertions: Check that a pointer 'looks' writable
00193  * \param p Pointer to check
00194  * \param len Length of memory at p to check 
00195  * \param align What alignment pointer should have, '1' if none
00196  * \return true if the pointer looks valid (no guarantee it is), false if invalid
00197  */
00198 int _checkptr( void* p, size_t len, size_t align )
00199 {
00200     /* See if pointer is NULL or a NULL->mbr */
00201     if( (size_t)p < 0x10000 )
00202         return false;
00203     /* See if pointer is odd-aligned */
00204     if( 0 != (((size_t)p)%align) )
00205         return false;
00206 #ifdef CTL_DELUXE_POINTER_CHECKS
00207     /* See if function would blindly succeed */
00208     if( 0 == len )
00209         return true;
00210     /* VirtualQuery would tell, but 'security' doesn't report certain blocks */
00211     /* There are articles that state this is 'unsafe', and I'd probably agree
00212      * except this is for an assertion; we don't try to 'fix' the problem, we 
00213      * only detect it a little earlier than the middle of the function. */
00214     return !IsBadWritePtr( p, len );
00215 #else
00216     return true;
00217 #endif
00218 }
00219 /*
00220  * For assertions: Check that a pointer 'looks' readable
00221  * \param p Pointer to check
00222  * \param len Length of memory at p to check 
00223  * \param align What alignment pointer should have, '1' if none
00224  * \return true if the pointer looks valid (no guarantee it is), false if invalid
00225  */
00226 int _checkconst( const void* p, size_t len, size_t align )
00227 {
00228     /* See if pointer is NULL or a NULL->mbr */
00229     if( (size_t)p < 0x10000 )
00230         return false;
00231     /* See if pointer is odd-aligned */
00232     if( 0 != (((size_t)p)%align) )
00233         return false;
00234 #ifdef CTL_DELUXE_POINTER_CHECKS
00235     /* See if function would blindly succeed */
00236     if( 0 == len )
00237         return true;
00238     /* VirtualQuery would tell, but 'security' doesn't report certain blocks */
00239     /* There are articles that state this is 'unsafe', and I'd probably agree
00240      * except this is for an assertion; we don't try to 'fix' the problem, we 
00241      * only detect it a little earlier than the middle of the function. */
00242     return !IsBadReadPtr( p, len );
00243 #else
00244     return true;
00245 #endif
00246 }
00247 /*
00248  * For assertions: Check that a function pointer 'looks' executable
00249  * \param p Pointer to check
00250  * \param len Length of memory at p to check 
00251  * \param align What alignment pointer should have, '1' if none
00252  * \return true if the pointer looks valid (no guarantee it is), false if invalid
00253  */
00254 int _checkcall( const void* p )
00255 {
00256     if( (size_t)p < 0x10000 )
00257         return false;
00258 #ifdef CTL_DELUXE_POINTER_CHECKS
00259     /* VirtualQuery would tell, but 'security' doesn't report certain blocks */
00260     /* There are articles that state this is 'unsafe', and I'd probably agree
00261      * except this is for an assertion; we don't try to 'fix' the problem, we 
00262      * only detect it a little earlier than the middle of the function. */
00263     return !IsBadCodePtr((FARPROC)(p));
00264 #else
00265     return true;
00266 #endif
00267 }
00268 /*
00269  * Return non-zero if debugger is attached
00270  */
00271 int _isdebugging(void)
00272 {
00273     return false;//IsDebuggerPresent();
00274 }
00275 #else /* not WIN32 */
00276 
00277 #include <setjmp.h>
00278 #include <signal.h>
00279 // globals
00280 jmp_buf g_pBuf;
00281 void segv_handler( int nSig)
00282 {
00283     longjmp( g_pBuf, 1 );
00284 }
00285   
00286 int _checkptr( void* p, size_t len, size_t align )
00287 {
00288     /* See if pointer is NULL or a NULL->mbr */
00289     if( (size_t)p < 0x10000 )
00290         return false;
00291     /* See if pointer is odd-aligned */
00292     if( 0 != (((size_t)p)%align) )
00293         return false;
00294 #ifdef CTL_DELUXE_POINTER_CHECKS
00295     /* See if function would blindly succeed */
00296     if( 0 != len )
00297     {
00298         /* 
00299          * This brute-force approach is unsafe, especially in a multithreaded 
00300          * environment where a crash in a different thread could jump right into 
00301          * the middle of this test.  ALSO, this is obscenely time-consuming.  
00302          */
00303         void (*sigprev)( int sig);
00304         if(setjmp(g_pBuf))
00305         {   /* Something 'bad' happened */
00306             signal( SIGSEGV, sigprev );
00307             return false;
00308         }
00309         sigprev = signal( SIGSEGV, segv_handler );
00310         {   /* Non-destructively write all the locations */
00311             uint8* ptr = (uint8*)p;
00312             uint32* dwptr;
00313             uint8* end = ptr + len;
00314             /* Optimization might spot that ^= 0 is an elaborate NOP but this is 
00315              * for a DEBUGGING build, not release mode build. */
00316             /* Align to dw boundary */
00317             while( ((size_t)p & 3) && ptr < end )
00318                 *ptr++ ^= 0;
00319             /* Scan 32 bits at a time */
00320             dwptr = (uint32*)ptr;
00321             while( dwptr < (uint32*)end )
00322                 *dwptr++ ^= 0;
00323             /* Finish off any leftovers */
00324             ptr = (uint8*)dwptr;
00325             while( ptr < end )
00326                 *ptr++ ^= 0;
00327         }
00328         signal( SIGSEGV, sigprev );
00329     }
00330 #endif
00331     return true;
00332 }
00333 int _checkconst( const void* p, size_t len, size_t align )
00334 {
00335     /* See if pointer is NULL or a NULL->mbr */
00336     if( (size_t)p < 0x10000 )
00337         return false;
00338     /* See if pointer is odd-aligned */
00339     if( 0 != (((size_t)p)%align) )
00340         return false;
00341 #ifdef CTL_DELUXE_POINTER_CHECKS
00342     /* See if function would blindly succeed */
00343     if( 0 != len )
00344     {
00345         /* 
00346          * This brute-force approach is unsafe, especially in a multithreaded 
00347          * environment where a crash in a different thread could jump right into 
00348          * the middle of this test.  ALSO, this is obscenely time-consuming.  
00349          */
00350         void (*sigprev)( int sig);
00351         if(setjmp ( g_pBuf))
00352         {   /* Something 'bad' happened */
00353             signal( SIGSEGV, sigprev );
00354             return false;
00355         }
00356         sigprev = signal( SIGSEGV, segv_handler );
00357         {   /* Read all the locations */
00358             const uint8* ptr = (const uint8*)p;
00359             const uint32* dwptr;
00360             const uint8* end = ptr + len;
00361             /* Brilliant optimization might spot that tmp is unused, 
00362              * but this is for a DEBUGGING build, not release mode build */
00363             uint8 tmp = 0;  
00364             /* Align to dw boundary */
00365             while( ((size_t)p & 3) && ptr < end )
00366                 tmp += *ptr++;
00367             /* Scan 32 bits at a time */
00368             dwptr = (uint32*)ptr;
00369             while( dwptr < (const uint32*)end )
00370                 tmp += *dwptr++;
00371             /* Finish off any leftovers */
00372             ptr = (const uint8*)dwptr;
00373             while( ptr < end )
00374                 tmp += *ptr++;
00375         }
00376         signal( SIGSEGV, sigprev );
00377     }
00378 #endif
00379     return true;
00380 }
00381 int _checkcall( const void* p )
00382 {
00383     return (size_t)p > 0x10000;
00384 }
00385 int _isdebugging(void)
00386 {
00387     return false;
00388 }
00389 
00390 #endif /*WIN32*/
00391 
00392 #endif /* DEBUG */

Generated on Fri Jan 2 15:28:34 2009 for Squat by  doxygen 1.5.6