Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

454 lines
11 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
stkwalk.c
Abstract:
This module contains memory debug routines for catching memory leaks and memory
overwrites.
Author:
Stolen from dbgmem.c
Jim Stewart/Ramesh Pabbati January 8, 1996
Fixed up for regleaks
UShaji Dec 11th, 1998
Revision History:
--*/
#ifdef LOCAL
#ifdef LEAK_TRACK
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include<imagehlp.h>
#include "regleak.h"
#include "stkwalk.h"
DWORD MachineType; // the architecutre we are on
HANDLE OurProcess; // the process that we are running as a part of
// typedefs from imagehlp.dll
typedef BOOL (WINAPI * PFNSYMINITIALIZE)(HANDLE hProcess,
PSTR UserSearchPath,
BOOL fInvadeProcess);
typedef BOOL (WINAPI * PFNSYMCLEANUP)(HANDLE hProcess);
typedef BOOL (WINAPI * PFNSTACKWALK)(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
typedef BOOL (WINAPI * PFNSYMGETSYMFROMADDR)(HANDLE hProcess,
DWORD_PTR Address,
PDWORD_PTR Displacement,
PIMAGEHLP_SYMBOL Symbol);
typedef DWORD_PTR (WINAPI * PFNSYMGETMODULEBASE)(HANDLE hProcess,
DWORD_PTR dwAddr);
typedef PVOID (WINAPI * PFNSYMFUNCTIONTABLEACCESS)(HANDLE hProcess,
DWORD_PTR AddrBase);
// imagehlp function pointers
PFNSYMINITIALIZE g_pfnSymInitialize=NULL;
PFNSYMCLEANUP g_pfnSymCleanup=NULL;
PFNSTACKWALK g_pfnStackWalk=NULL;
PFNSYMGETSYMFROMADDR g_pfnSymGetSymFromAddr=NULL;
PFNSYMFUNCTIONTABLEACCESS g_pfnSymFunctionTableAccess=NULL;
PFNSYMGETMODULEBASE g_pfnSymGetModuleBase=NULL;
HINSTANCE g_hImagehlpInstance=NULL;
BOOL fDebugInitialised = FALSE;
BOOL
InitDebug(
);
DWORD GetStack(
IN EXCEPTION_POINTERS *exp,
IN PCALLER_SYM Caller,
IN int Skip,
IN int cFind,
IN int fResolveSymbols
);
BOOL LoadImageHLP()
{
g_hImagehlpInstance = LoadLibrary ("imagehlp.dll");
if (!g_hImagehlpInstance) {
return FALSE;
}
g_pfnSymInitialize = (PFNSYMINITIALIZE) GetProcAddress (g_hImagehlpInstance,
"SymInitialize");
if (!g_pfnSymInitialize) {
return FALSE;
}
g_pfnSymCleanup = (PFNSYMCLEANUP) GetProcAddress (g_hImagehlpInstance,
"SymCleanup");
if (!g_pfnSymCleanup) {
return FALSE;
}
g_pfnStackWalk = (PFNSTACKWALK) GetProcAddress (g_hImagehlpInstance,
"StackWalk");
if (!g_pfnStackWalk) {
return FALSE;
}
g_pfnSymGetSymFromAddr = (PFNSYMGETSYMFROMADDR) GetProcAddress (g_hImagehlpInstance,
"SymGetSymFromAddr");
if (!g_pfnSymGetSymFromAddr) {
return FALSE;
}
g_pfnSymFunctionTableAccess = (PFNSYMFUNCTIONTABLEACCESS) GetProcAddress (g_hImagehlpInstance,
"SymFunctionTableAccess");
if (!g_pfnSymFunctionTableAccess) {
return FALSE;
}
g_pfnSymGetModuleBase = (PFNSYMGETMODULEBASE) GetProcAddress (g_hImagehlpInstance,
"SymGetModuleBase");
if (!g_pfnSymGetModuleBase) {
return FALSE;
}
return TRUE;
}
BOOL
InitDebug(
)
/*++
Description:
This routine initializes the debug memory functionality.
Arguments:
none
Return Value:
BOOL - pass or fail
--*/
{
BOOL status;
SYSTEM_INFO SysInfo;
if (fDebugInitialised)
return TRUE;
status = RtlEnterCriticalSection(&(g_RegLeakTraceInfo.StackInitCriticalSection));
ASSERT( NT_SUCCESS( status ) );
if (fDebugInitialised)
return TRUE;
OurProcess = GetCurrentProcess();
g_RegLeakTraceInfo.szSymPath = (LPTSTR) RtlAllocateHeap(
RtlProcessHeap(),
0,
SYM_PATH_MAX_SIZE*sizeof(TCHAR));
if (!g_RegLeakTraceInfo.szSymPath) {
// looks like machine already doesn't have enough memory
// disable leak tracking
g_RegLeakTraceInfo.bEnableLeakTrack = 0;
return FALSE;
}
g_RegLeakTraceInfo.dwMaxStackDepth = GetProfileInt(TEXT("RegistryLeak"), TEXT("StackDepth"), MAX_LEAK_STACK_DEPTH);
GetProfileString(TEXT("RegistryLeak"), TEXT("SymbolPath"), TEXT(""), g_RegLeakTraceInfo.szSymPath, SYM_PATH_MAX_SIZE);
if (!(*g_RegLeakTraceInfo.szSymPath)) {
RtlFreeHeap(
RtlProcessHeap(),
0,
g_RegLeakTraceInfo.szSymPath);
g_RegLeakTraceInfo.szSymPath = NULL;
}
if (!LoadImageHLP()) {
g_RegLeakTraceInfo.bEnableLeakTrack = FALSE;
status = RtlLeaveCriticalSection(&(g_RegLeakTraceInfo.StackInitCriticalSection));
return FALSE;
}
GetSystemInfo( &SysInfo );
switch (SysInfo.wProcessorArchitecture) {
default:
case PROCESSOR_ARCHITECTURE_INTEL:
MachineType = IMAGE_FILE_MACHINE_I386;
break;
case PROCESSOR_ARCHITECTURE_MIPS:
//
// note this may not detect R10000 machines correctly
//
MachineType = IMAGE_FILE_MACHINE_R4000;
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
MachineType = IMAGE_FILE_MACHINE_ALPHA;
break;
case PROCESSOR_ARCHITECTURE_PPC:
MachineType = IMAGE_FILE_MACHINE_POWERPC;
break;
}
// symbols from Current directory/Environment variable _NT_SYMBOL_PATH
// Environment variable _NT_ALTERNATE_SYMBOL_PATH or Environment variable SYSTEMROOT
status = g_pfnSymInitialize ( OurProcess, g_RegLeakTraceInfo.szSymPath, FALSE );
fDebugInitialised = TRUE;
status = RtlLeaveCriticalSection(&(g_RegLeakTraceInfo.StackInitCriticalSection));
return( TRUE );
}
BOOL
StopDebug()
{
if (fDebugInitialised) {
BOOL fSuccess;
fSuccess = g_pfnSymCleanup(OurProcess);
fDebugInitialised = FALSE;
FreeLibrary(g_hImagehlpInstance);
if (g_RegLeakTraceInfo.szSymPath) {
RtlFreeHeap(
RtlProcessHeap(),
0,
g_RegLeakTraceInfo.szSymPath);
}
return fSuccess;
}
return TRUE;
}
BOOL
ReadMem(
IN HANDLE hProcess,
IN LPCVOID BaseAddr,
IN LPVOID Buffer,
IN DWORD Size,
IN LPDWORD NumBytes )
/*++
Description:
This is a callback routine that StackWalk uses - it just calls teh system ReadProcessMemory
routine with this process's handle
Arguments:
Return Value:
none
--*/
{
BOOL status;
SIZE_T RealNumberBytesRead;
status = ReadProcessMemory( GetCurrentProcess(),BaseAddr,Buffer,Size,&RealNumberBytesRead );
*NumBytes = (DWORD)RealNumberBytesRead;
return( status );
}
VOID
GetCallStack(
IN PCALLER_SYM Caller,
IN int Skip,
IN int cFind,
IN int fResolveSymbols
)
/*++
Description:
This routine walks te stack to find the return address of caller. The number of callers
and the number of callers on top to be skipped can be specified.
Arguments:
pdwCaller array of DWORD to return callers
return addresses
Skip no. of callers to skip
cFInd no. of callers to find
Return Value:
none
--*/
{
if (!g_RegLeakTraceInfo.bEnableLeakTrack) {
return;
}
if (!InitDebug()) {
return;
}
__try {
memset(Caller, 0, cFind * sizeof(CALLER_SYM));
RaiseException(MY_DBG_EXCEPTION, 0, 0, NULL);
// raise an exception to get the exception record to start the stack walk
//
}
__except(GetStack(GetExceptionInformation(), Caller, Skip, cFind, fResolveSymbols)) {
}
}
DWORD GetStack(
IN EXCEPTION_POINTERS *exp,
IN PCALLER_SYM Caller,
IN int Skip,
IN int cFind,
IN int fResolveSymbols
)
{
BOOL status;
CONTEXT ContextRecord;
PUCHAR Buffer[sizeof(IMAGEHLP_SYMBOL)-1 + MAX_FUNCTION_INFO_SIZE]; // symbol info
PIMAGEHLP_SYMBOL Symbol = (PIMAGEHLP_SYMBOL)Buffer;
STACKFRAME StackFrame;
INT i;
DWORD Count;
memcpy(&ContextRecord, exp->ContextRecord, sizeof(CONTEXT));
ZeroMemory( &StackFrame,sizeof(STACKFRAME) );
StackFrame.AddrPC.Segment = 0;
StackFrame.AddrPC.Mode = AddrModeFlat;
#ifdef _M_IX86
StackFrame.AddrFrame.Offset = ContextRecord.Ebp;
StackFrame.AddrFrame.Mode = AddrModeFlat;
StackFrame.AddrStack.Offset = ContextRecord.Esp;
StackFrame.AddrStack.Mode = AddrModeFlat;
StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Eip;
#elif defined(_M_MRX000)
StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Fir;
#elif defined(_M_ALPHA)
StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Fir;
#elif defined(_M_PPC)
StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Iar;
#endif
Count = 0;
for (i=0;i<cFind+Skip ;i++ ) {
status = g_pfnStackWalk( MachineType,
OurProcess,
GetCurrentThread(),
&StackFrame,
(PVOID)&ContextRecord,
(PREAD_PROCESS_MEMORY_ROUTINE)ReadMem,
g_pfnSymFunctionTableAccess,
g_pfnSymGetModuleBase,
NULL );
if (status) {
if ( i >= Skip) {
DWORD Displacement;
ZeroMemory( Symbol,sizeof(IMAGEHLP_SYMBOL)-1 + MAX_FUNCTION_INFO_SIZE );
Symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
Symbol->Address = StackFrame.AddrPC.Offset;
Symbol->MaxNameLength = MAX_FUNCTION_INFO_SIZE-1;
Symbol->Flags = SYMF_OMAP_GENERATED;
if (fResolveSymbols)
status = g_pfnSymGetSymFromAddr( OurProcess,StackFrame.AddrPC.Offset,(DWORD_PTR*)&Displacement,Symbol );
//
// save the name of the function and the displacement into it for later printing
//
Caller[Count].Addr = (PVOID)StackFrame.AddrPC.Offset;
if (status) {
strcpy( Caller[Count].Buff,Symbol->Name );
Caller[Count].Displacement = Displacement;
}
Count++;
}
} else {
break;
}
}
return EXCEPTION_CONTINUE_EXECUTION;
// done with exceptions
}
#endif // LEAK_TRACK
#endif // LOCAL