295 lines
7.3 KiB
C++
295 lines
7.3 KiB
C++
/***
|
|
*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 <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntos.h>
|
|
}
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
#include <eh.h>
|
|
#include <ehassert.h>
|
|
|
|
#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 <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
//
|
|
// 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 */
|