Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

549 lines
17 KiB

/*++
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:
--*/
#define UNICODE 1
#define _UNICODE 1
#include "resmonp.h"
#include "dbghelp.h"
// Make typedefs for some dbghelp.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 );
typedef BOOL (__stdcall *SYMFROMADDRPROC)
( HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO );
typedef BOOL (__stdcall *MINIDUMPWRITEDUMP)
( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
PMINIDUMP_EXCEPTION_INFORMATION,
PMINIDUMP_USER_STREAM_INFORMATION,
PMINIDUMP_CALLBACK_INFORMATION );
SYMINITIALIZEPROC _SymInitialize = 0;
SYMCLEANUPPROC _SymCleanup = 0;
STACKWALKPROC _StackWalk = 0;
SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess = 0;
SYMGETMODULEBASEPROC _SymGetModuleBase = 0;
SYMGETSYMFROMADDRPROC _SymGetSymFromAddr = 0;
SYMFROMADDRPROC _SymFromAddr = 0;
MINIDUMPWRITEDUMP _MiniDumpWriteDump = NULL;
//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
GenerateMemoryDump(
IN PEXCEPTION_POINTERS pExceptionInfo
);
VOID
DumpCriticalSection(
IN PCRITICAL_SECTION CriticalSection
)
/*++
Routine Description:
Inputs:
Outputs:
--*/
{
DWORD status;
ClRtlLogPrint(LOG_CRITICAL, "[RM] Dumping Critical Section at %1!08LX!\n",
CriticalSection );
try {
if ( CriticalSection->LockCount == -1 ) {
ClRtlLogPrint(LOG_CRITICAL, " LockCount NOT LOCKED\n" );
} else {
ClRtlLogPrint(LOG_CRITICAL, " LockCount %1!u!\n",
CriticalSection->LockCount );
}
ClRtlLogPrint(LOG_CRITICAL, " RecursionCount %1!x!\n",
CriticalSection->RecursionCount );
ClRtlLogPrint(LOG_CRITICAL, " OwningThread %1!x!\n",
CriticalSection->OwningThread );
ClRtlLogPrint(LOG_CRITICAL, " EntryCount %1!x!\n",
CriticalSection->DebugInfo->EntryCount );
ClRtlLogPrint(LOG_CRITICAL, " ContentionCount %1!x!\n\n",
CriticalSection->DebugInfo->ContentionCount );
} except ( EXCEPTION_EXECUTE_HANDLER ) {
status = GetExceptionCode();
ClRtlLogPrint(LOG_CRITICAL, "[RM] Exception %1!lx! occurred while dumping critsec\n\n",
status );
}
} // DumpCriticalSection
VOID
GenerateMemoryDump(
IN PEXCEPTION_POINTERS pExceptionInfo
)
/*++
Routine Description:
Generates a memory dump for the resource monitor process.
Arguments:
pExceptionInfo - Supplies the exception information
Return Value:
None.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
WCHAR szFileName[ MAX_PATH + RTL_NUMBER_OF ( RM_DMP_FILE_NAME ) + 1 ];
HANDLE hDumpFile = INVALID_HANDLE_VALUE;
MINIDUMP_EXCEPTION_INFORMATION mdumpExceptionInfo;
if ( !_MiniDumpWriteDump )
{
dwStatus = ERROR_INVALID_PARAMETER;
ClRtlLogPrint(LOG_CRITICAL, "[RM] GenerateMemoryDump: _MiniDumpWriteDump fn ptr is invalid, Status=%1!u!\n",
dwStatus);
goto FnExit;
}
dwStatus = ClRtlGetClusterDirectory( szFileName, RTL_NUMBER_OF ( szFileName ) );
if ( dwStatus != ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_CRITICAL, "[RM] GenerateMemoryDump: Could not get cluster dir, Status=%1!u!\n",
dwStatus);
goto FnExit;
}
wcsncat( szFileName,
RM_DMP_FILE_NAME,
RTL_NUMBER_OF ( szFileName ) -
( wcslen ( szFileName ) + 1 ) );
szFileName [ RTL_NUMBER_OF ( szFileName ) - 1 ] = UNICODE_NULL;
hDumpFile = CreateFile( szFileName,
GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
0,
NULL );
if ( hDumpFile == INVALID_HANDLE_VALUE )
{
dwStatus = GetLastError ();
ClRtlLogPrint(LOG_CRITICAL, "[RM] GenerateMemoryDump: Could not create file %1!ws!, Status=%2!u!\n",
szFileName,
dwStatus);
goto FnExit;
}
mdumpExceptionInfo.ThreadId = GetCurrentThreadId ();
mdumpExceptionInfo.ExceptionPointers = pExceptionInfo;
mdumpExceptionInfo.ClientPointers = TRUE;
ClRtlLogPrint(LOG_NOISE, "[RM] GenerateMemoryDump: Start memory dump to file %1!ws!\n",
szFileName);
if( !_MiniDumpWriteDump( GetCurrentProcess(),
GetCurrentProcessId(),
hDumpFile,
MiniDumpNormal | MiniDumpWithHandleData,
&mdumpExceptionInfo,
NULL,
NULL ) )
{
dwStatus = GetLastError ();
ClRtlLogPrint(LOG_CRITICAL, "[CS] GenerateMemoryDump: Could not write dump, Status=%1!u!\n",
dwStatus);
goto FnExit;
}
FnExit:
if ( hDumpFile != INVALID_HANDLE_VALUE ) CloseHandle ( hDumpFile );
ClRtlLogPrint(LOG_NOISE, "[RM] GenerateMemoryDump: Memory dump status %1!u!\n",
dwStatus);
return;
}// GenerateMemoryDump
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, "[RM] 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;
}
GenerateMemoryDump ( pExceptionInfo );
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;
_SymFromAddr=(SYMFROMADDRPROC)GetProcAddress( hModImagehlp,
"SymFromAddr" );
if ( !_SymFromAddr )
return FALSE;
_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress( hModImagehlp,
"MiniDumpWriteDump" );
if ( !_MiniDumpWriteDump )
return FALSE;
// Set the current directory so that the symbol handler functions will pick up any PDBs that happen to be in
// the cluster dir.
// No need to save and restore the previous current dir since we will be dying after this.
{
WCHAR currentDir[ MAX_PATH + 1 ];
UINT windirLen = GetWindowsDirectory( currentDir, MAX_PATH );
if ( windirLen != 0 && windirLen <= MAX_PATH - wcslen( L"\\Cluster" ) )
{
wcscat( currentDir, L"\\Cluster" );
if ( !SetCurrentDirectory( currentDir ))
{
ClRtlLogPrint( LOG_CRITICAL, "Failed to set current directory to %1!ws!, error %2!d!\n", currentDir, GetLastError() );
}
}
}
if ( !_SymInitialize( GetCurrentProcess(), NULL, TRUE ) )
return FALSE;
return TRUE;
} // InitImagehlpFunctions
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 ];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
DWORD64 symDisplacement = 0; // Displacement of the input address,
// relative to the start of the symbol
DWORD dwMachineType;
UCHAR printBuffer[512];
DWORD nextPrtBufChar;
ClRtlLogPrint(LOG_CRITICAL,
"[RM] CallStack:\n");
ClRtlLogPrint(LOG_CRITICAL,
"[RM] Frame Address\n");
// Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
memset( &sf, 0, sizeof(sf) );
#if defined (_M_IX86)
dwMachineType = IMAGE_FILE_MACHINE_I386;
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;
#elif defined(_M_AMD64)
dwMachineType = IMAGE_FILE_MACHINE_AMD64;
sf.AddrPC.Offset = pContext->Rip;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Offset = pContext->Rsp;
sf.AddrStack.Mode = AddrModeFlat;
#elif defined(_M_IA64)
dwMachineType = IMAGE_FILE_MACHINE_IA64;
sf.AddrPC.Offset = pContext->StIIP;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Offset = pContext->IntSp;
sf.AddrStack.Mode = AddrModeFlat;
#else
#error "No Target Architecture"
#endif // defined(_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 = _snprintf(printBuffer,
sizeof(printBuffer),
" %p %p ",
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->MaxNameLen = 512;
if ( _SymFromAddr(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),
&section, &offset );
sprintf(printBuffer+nextPrtBufChar,
"%04X:%08p %S\n",
section, offset, szModule );
}
ClRtlLogPrint(LOG_CRITICAL, "%1!hs!", 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!
}