|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
excprt.c Abstract:
This module uses imagehlp.dll to dump the stack when an exception occurs.
Author:
Sunita Shrivastava(sunitas) 11/5/1997
Revision History:
--*/ #include "initp.h"
#include "dbghelp.h"
// Make typedefs for some IMAGEHLP.DLL functions so that we can use them
// with GetProcAddress
typedef BOOL (__stdcall * SYMINITIALIZEPROC)( HANDLE, LPSTR, BOOL ); typedef BOOL (__stdcall *SYMCLEANUPPROC)( HANDLE );
typedef BOOL (__stdcall * STACKWALKPROC) ( DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE );
typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)( HANDLE, ULONG_PTR );
typedef ULONG_PTR (__stdcall *SYMGETMODULEBASEPROC)( HANDLE, ULONG_PTR );
typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC) ( HANDLE, ULONG_PTR, PULONG_PTR, PIMAGEHLP_SYMBOL );
SYMINITIALIZEPROC _SymInitialize = 0; SYMCLEANUPPROC _SymCleanup = 0; STACKWALKPROC _StackWalk = 0; SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess = 0; SYMGETMODULEBASEPROC _SymGetModuleBase = 0; SYMGETSYMFROMADDRPROC _SymGetSymFromAddr = 0;
//local prototypes for forward use
BOOL InitImagehlpFunctions(); void ImagehlpStackWalk( IN PCONTEXT pContext ); BOOL GetLogicalAddress( IN PVOID addr, OUT LPWSTR szModule, IN DWORD len, OUT LPDWORD section, OUT PULONG_PTR offset );
void GenerateExceptionReport( IN PEXCEPTION_POINTERS pExceptionInfo) /*++
Routine Description:
Top level exception handler for the cluster service process. Currently this just exits immediately and assumes that the cluster proxy will notice and restart us as appropriate.
Arguments:
ExceptionInfo - Supplies the exception information
Return Value:
None.
--*/ { PCONTEXT pCtxt = pExceptionInfo->ContextRecord;
if ( !InitImagehlpFunctions() ) { ClRtlLogPrint(LOG_CRITICAL, "[CS] Dbghelp.dll or its exported procs not found\r\n");
#if 0
#ifdef _M_IX86 // Intel Only!
// Walk the stack using x86 specific code
IntelStackWalk( pCtx ); #endif
#endif
return; }
ImagehlpStackWalk( pCtxt );
_SymCleanup( GetCurrentProcess() ); }
BOOL InitImagehlpFunctions() /*++
Routine Description:
Initializes the imagehlp functions/data.
Arguments:
None.
Return Value:
None.
--*/ { HMODULE hModImagehlp = LoadLibraryW( L"DBGHELP.DLL" );
if ( !hModImagehlp ) return FALSE;
_SymInitialize = (SYMINITIALIZEPROC)GetProcAddress( hModImagehlp, "SymInitialize" ); if ( !_SymInitialize ) return FALSE;
_SymCleanup = (SYMCLEANUPPROC)GetProcAddress( hModImagehlp, "SymCleanup" ); if ( !_SymCleanup ) return FALSE;
_StackWalk = (STACKWALKPROC)GetProcAddress( hModImagehlp, "StackWalk" ); if ( !_StackWalk ) return FALSE;
_SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress( hModImagehlp, "SymFunctionTableAccess" );
if ( !_SymFunctionTableAccess ) return FALSE;
_SymGetModuleBase=(SYMGETMODULEBASEPROC)GetProcAddress( hModImagehlp, "SymGetModuleBase"); if ( !_SymGetModuleBase ) return FALSE;
_SymGetSymFromAddr=(SYMGETSYMFROMADDRPROC)GetProcAddress( hModImagehlp, "SymGetSymFromAddr" ); if ( !_SymGetSymFromAddr ) return FALSE;
if ( !_SymInitialize( GetCurrentProcess(), 0, TRUE ) ) return FALSE;
return TRUE; }
void ImagehlpStackWalk( IN PCONTEXT pContext ) /*++
Routine Description:
Walks the stack, and writes the results to the report file
Arguments:
ExceptionInfo - Supplies the exception information
Return Value:
None.
--*/ { STACKFRAME sf; BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + 512 ]; PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer; ULONG_PTR symDisplacement = 0; // Displacement of the input address,
// relative to the start of the symbol
DWORD dwMachineType; UCHAR printBuffer[512]; DWORD nextPrtBufChar;
#if defined (_M_IX86)
dwMachineType = IMAGE_FILE_MACHINE_I386; #else if defined(_M_ALPHA)
dwMachineType = IMAGE_FILE_MACHINE_ALPHA; #endif
ClRtlLogPrint(LOG_CRITICAL, "[CS] CallStack:\r\n");
ClRtlLogPrint(LOG_CRITICAL, "[CS] Frame Address\r\n");
// Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
memset( &sf, 0, sizeof(sf) );
#if defined (_M_IX86)
// Initialize the STACKFRAME structure for the first call. This is only
// necessary for Intel CPUs, and isn't mentioned in the documentation.
sf.AddrPC.Offset = pContext->Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = pContext->Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = pContext->Ebp; sf.AddrFrame.Mode = AddrModeFlat; #endif // _M_IX86
while ( 1 ) { if ( ! _StackWalk( dwMachineType, GetCurrentProcess(), GetCurrentThread(), &sf, pContext, 0, _SymFunctionTableAccess, _SymGetModuleBase, 0 ) ) break; if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure
break; // the frame is OK. Bail if not.
nextPrtBufChar = sprintf(printBuffer, " %08X %08X ", sf.AddrFrame.Offset, sf.AddrPC.Offset );
// IMAGEHLP is wacky, and requires you to pass in a pointer to an
// IMAGEHLP_SYMBOL structure. The problem is that this structure is
// variable length. That is, you determine how big the structure is
// at runtime. This means that you can't use sizeof(struct).
// So...make a buffer that's big enough, and make a pointer
// to the buffer. We also need to initialize not one, but TWO
// members of the structure before it can be used.
pSymbol->SizeOfStruct = sizeof(symbolBuffer); pSymbol->MaxNameLength = 512;
if ( _SymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, &symDisplacement, pSymbol) ) { sprintf(printBuffer+nextPrtBufChar, "%hs+%p\n", pSymbol->Name, symDisplacement); } else // No symbol found. Print out the logical address instead.
{ WCHAR szModule[MAX_PATH] = L""; DWORD section = 0; ULONG_PTR offset = 0;
GetLogicalAddress( (PVOID)sf.AddrPC.Offset, szModule, sizeof(szModule)/sizeof(WCHAR), §ion, &offset );
sprintf(printBuffer+nextPrtBufChar, "%04X:%08p %s\n", section, offset, szModule ); }
ClRtlLogPrint(LOG_CRITICAL, "%1!hs!\n", printBuffer ); } }
BOOL GetLogicalAddress( IN PVOID addr, OUT LPWSTR szModule, IN DWORD len, OUT LPDWORD section, OUT PULONG_PTR offset ) /*++
Routine Description:
Given a linear address, locates the module, section, and offset containing that address. Note: the szModule paramater buffer is an output buffer of length specified by the len parameter (in characters!)
Arguments:
ExceptionInfo - Supplies the exception information
Return Value:
None.
--*/ { MEMORY_BASIC_INFORMATION mbi; ULONG_PTR hMod; // Point to the DOS header in memory
PIMAGE_DOS_HEADER pDosHdr; // From the DOS header, find the NT (PE) header
PIMAGE_NT_HEADERS pNtHdr; PIMAGE_SECTION_HEADER pSection; ULONG_PTR rva ; int i; if ( !VirtualQuery( addr, &mbi, sizeof(mbi) ) ) return FALSE;
hMod = (ULONG_PTR)mbi.AllocationBase;
if ( !GetModuleFileName( (HMODULE)hMod, szModule, len ) ) return FALSE;
rva = (ULONG_PTR)addr - hMod; // RVA is offset from module load address
pDosHdr = (PIMAGE_DOS_HEADER)hMod; pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew); pSection = IMAGE_FIRST_SECTION( pNtHdr ); // Iterate through the section table, looking for the one that encompasses
// the linear address.
for ( i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++ ) { ULONG_PTR sectionStart = pSection->VirtualAddress; ULONG_PTR sectionEnd = sectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
// Is the address in this section???
if ( (rva >= sectionStart) && (rva <= sectionEnd) ) { // Yes, address is in the section. Calculate section and offset,
// and store in the "section" & "offset" params, which were
// passed by reference.
*section = i+1; *offset = rva - sectionStart; return TRUE; } }
return FALSE; // Should never get here!
}
|