/*** *validate.cpp - Routines to validate the data structures. * * Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved. * *Purpose: * Routines to validate the Exception Handling data structures. * * Entry points: * * Error reporting: * * EHRuntimeError - reports the error with * a popup or print to stderr, then quits. * * Pointer validation: * * _ValidateRead - Confirms that a pointer is valid for reading * * _ValidateWrite - Confirms that a pointer is valid for writing * * _ValidateExecute - Confirms that a pointer is valid to jump to * * Data structure dumpers: * * DumpTypeDescriptor * * DumpFuncInfo * * DumpThrowInfo * * Execution tracing (only in /DENABLE_EHTRACE builds): * * EHTraceOutput * *Revision History: * ??-??-93 BS Module created * 10-17-94 BWT Disable code for PPC. * 04-25-95 DAK Add Kernel EH Support * 05-17-99 PML Remove all Macintosh support. * 10-22-99 PML Add EHTRACE support * ****/ #if defined(_NTSUBSET_) extern "C" { #include #include #include #include } #endif #include #include #include #pragma hdrstop #if defined(DEBUG) int __cdecl dprintf( char *format, ... ) { static char buffer[512]; int size = vsprintf( buffer, format, (char*)(&format+1) ); #if defined(_NTSUBSET_) DbgPrint( buffer ); #else OutputDebugString( buffer ); #endif return size; } #endif BOOL _ValidateRead( const void *data, UINT size ) { BOOL bValid = TRUE; #if defined(_NTSUBSET_) // bValid = MmIsSystemAddressAccessable( (PVOID) data ); #else if ( IsBadReadPtr( data, size ) ) { dprintf( "_ValidateRead( %p, %d ): Invalid Pointer!", data, size ); // terminate(); // terminate does not return. bValid = FALSE; } #endif return bValid; } BOOL _ValidateWrite( void *data, UINT size ) { BOOL bValid = TRUE; #if defined(_NTSUBSET_) // bValid = MmIsSystemAddressAccessable( (PVOID) data ); #else if ( IsBadWritePtr( data, size ) ) { dprintf( "_ValidateWrite( %p, %d ): Invalid Pointer!", data, size ); // terminate(); // terminate does not return. bValid = FALSE; } #endif return bValid; } BOOL _ValidateExecute( FARPROC code ) { BOOL bValid = TRUE; #if defined(_NTSUBSET_) bValid = _ValidateRead(code, sizeof(FARPROC) ); #else if ( IsBadCodePtr( code ) ) { dprintf( "_ValidateExecute( %p ): Invalid Function Address!", code ); // terminate(); // terminate does not return bValid = FALSE; } #endif return bValid; } #if defined(DEBUG) && defined(_M_IX86) // // dbRNListHead - returns current value of FS:0. // // For debugger use only, since debugger doesn't seem to be able to view the // teb. // EHRegistrationNode *dbRNListHead(void) { EHRegistrationNode *pRN; __asm { mov eax, dword ptr FS:[0] mov pRN, eax } return pRN; } #endif #ifdef ENABLE_EHTRACE #include #include // // Current EH tracing depth, stack for saving levels during __finally block // or __except filter. // int __ehtrace_level; int __ehtrace_level_stack_depth; int __ehtrace_level_stack[128]; // // EHTraceOutput - Dump formatted string to OutputDebugString // void __cdecl EHTraceOutput(const char *format, ...) { va_list arglist; char buf[1024]; sprintf(buf, "%p ", &format); OutputDebugString(buf); va_start(arglist, format); _vsnprintf(buf, sizeof(buf), format, arglist); OutputDebugString(buf); } // // EHTraceIndent - Return string for current EH tracing depth // const char*EHTraceIndent(int level) { static char indentbuf[128 + 1]; // Reset global level to recover from stack unwinds __ehtrace_level = level; int depth = max(0, level - 1); if (depth > (sizeof(indentbuf) - 1) / 2) { depth = (sizeof(indentbuf) - 1) / 2; } for (int i = 0; i < depth; ++i) { indentbuf[2 * i] = '|'; indentbuf[2 * i + 1] = ' '; } indentbuf[2 * depth] = '\0'; return indentbuf; } // // EHTraceFunc - Chop down __FUNCTION__ to simple name // const char *EHTraceFunc(const char *func) { static char namebuf[128]; const char *p = func + strlen(func) - 1; if (*p != ')') { // Name already simple (no arg list found) return func; } // Skip backwards past the argument list int parendepth = 1; while (p > func && parendepth > 0) { switch (*--p) { case '(': --parendepth; break; case ')': ++parendepth; break; } } // Find beginning of name // TODO: Won't work for funcs which return func-ptrs const char *pEnd = p; while (p > func && p[-1] != ' ') { --p; } size_t len = min(pEnd - p, sizeof(namebuf) - 1); memcpy(namebuf, p, len); namebuf[len] = '\0'; return namebuf; } // // EHTracePushLevel - Push current trace depth on stack to allow temporary // resetting of level with __finally block or __except filter. // void EHTracePushLevel(int new_level) { if (__ehtrace_level_stack_depth < sizeof(__ehtrace_level_stack) / sizeof(__ehtrace_level_stack[0])) { __ehtrace_level_stack[__ehtrace_level_stack_depth] = __ehtrace_level; } ++__ehtrace_level_stack_depth; __ehtrace_level = new_level; } // // EHTracePopLevel - Pop saved trace depth from stack on completion of // __finally block or __except filter, and optionally restore global depth. // void EHTracePopLevel(bool restore) { --__ehtrace_level_stack_depth; if (restore && __ehtrace_level_stack_depth < sizeof(__ehtrace_level_stack) / sizeof(__ehtrace_level_stack[0])) { __ehtrace_level = __ehtrace_level_stack[__ehtrace_level_stack_depth]; } } // // EHTraceExceptFilter - Dump trace info for __except filter. Trace level must // have been pushed before entry with EHTracePushLevel, so any functions called // for the 'expr' argument are dumped at the right level. // int EHTraceExceptFilter(const char *func, int expr) { EHTraceOutput("In : %s%s: __except filter returns %d (%s)\n", EHTraceIndent(__ehtrace_level), EHTraceFunc(func), expr, expr < 0 ? "EXCEPTION_CONTINUE_EXECUTION" : expr > 0 ? "EXCEPTION_EXECUTE_HANDLER" : "EXCEPTION_CONTINUE_SEARCH"); EHTracePopLevel(expr <= 0); return expr; } // // EHTraceHandlerReturn - Dump trace info for exception handler return // void EHTraceHandlerReturn(const char *func, int level, EXCEPTION_DISPOSITION result) { EHTraceOutput( "Exit : %s%s: Handler returning %d (%s)\n", \ EHTraceIndent(level), EHTraceFunc(func), result, result == ExceptionContinueExecution ? "ExceptionContinueExecution" : result == ExceptionContinueSearch ? "ExceptionContinueSearch" : result == ExceptionNestedException ? "ExceptionNestedException" : result == ExceptionCollidedUnwind ? "ExceptionCollidedUnwind" : "unknown" ); } #endif /* ENABLE_EHTRACE */