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.
 
 
 
 
 
 

364 lines
8.9 KiB

/*++
Copyright (C) 1999-2001 Microsoft Corporation
Module Name:
STKTRACE.CPP
Abstract:
Symbolic stack trace
History:
raymcc 27-May-99
--*/
#include <windows.h>
#include <imagehlp.h>
#include "kernel33.h"
#include "stktrace.h"
// Compiler bug workaround
void xstrcat(TCHAR *p1, TCHAR *p2)
{
while (*p1++); p1--;
while (*p1++ = *p2++);
}
static HANDLE s_hProcess = 0;
static HANDLE s_hPrivateHeap = 0;
// IMAGHLP.DLL Function pointers
// =============================
typedef BOOL (__stdcall *PFN_SymInitialize)(
IN HANDLE hProcess,
IN PSTR UserSearchPath,
IN BOOL fInvadeProcess
);
typedef PVOID (__stdcall *PFN_SymFunctionTableAccess)(
HANDLE hProcess,
DWORD AddrBase
);
typedef BOOL (__stdcall *PFN_SymGetSymFromAddr)(
IN HANDLE hProcess,
IN DWORD dwAddr,
OUT PDWORD pdwDisplacement,
OUT PIMAGEHLP_SYMBOL Symbol
);
typedef BOOL (__stdcall *PFN_SymGetLineFromAddr)(
IN HANDLE hProcess,
IN DWORD dwAddr,
OUT PDWORD pdwDisplacement,
OUT PIMAGEHLP_LINE Line
);
typedef DWORD (__stdcall *PFN_SymGetModuleBase)(
IN HANDLE hProcess,
IN DWORD dwAddr
);
typedef BOOL (__stdcall *PFN_StackWalk)(
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
);
static PFN_SymInitialize pfSymInitialize = 0;
static PFN_SymFunctionTableAccess pfSymFunctionTableAccess = 0;
static PFN_SymGetSymFromAddr pfSymGetSymFromAddr = 0;
static PFN_SymGetLineFromAddr pfSymGetLineFromAddr = 0;
static PFN_SymGetModuleBase pfSymGetModuleBase = 0;
static PFN_StackWalk pfStackWalk = 0;
//***************************************************************************
//
//***************************************************************************
BOOL m_bActive = FALSE;
BOOL StackTrace_Init()
{
if (m_bActive) // Already running
return TRUE;
m_bActive = FALSE;
TCHAR IniPath[MAX_PATH], buf[MAX_PATH], SymPath[MAX_PATH];
*IniPath = 0;
*buf = 0;
*SymPath = 0;
GetSystemDirectory(IniPath, MAX_PATH);
xstrcat(IniPath, __TEXT("\\WBEM\\WMIDBG.INI")); // Compiler bug workaround
DWORD dwRes = GetPrivateProfileString(
__TEXT("WMI DEBUG"),
__TEXT("DLLNAME"),
__TEXT(""),
buf,
MAX_PATH,
IniPath
);
dwRes = GetPrivateProfileString(
__TEXT("WMI DEBUG"),
__TEXT("SYMPATH"),
__TEXT(""),
SymPath,
MAX_PATH,
IniPath
);
HMODULE hMod = LoadLibrary(buf);
if (hMod == 0)
return FALSE;
pfSymInitialize = (PFN_SymInitialize) GetProcAddress(hMod, "SymInitialize");
pfSymFunctionTableAccess = (PFN_SymFunctionTableAccess) GetProcAddress(hMod, "SymFunctionTableAddress");
pfSymGetSymFromAddr = (PFN_SymGetSymFromAddr) GetProcAddress(hMod, "SymGetSymFromAddr");
pfSymGetLineFromAddr = (PFN_SymGetLineFromAddr) GetProcAddress(hMod, "SymGetLineFromAddr");
pfSymGetModuleBase = (PFN_SymGetModuleBase) GetProcAddress(hMod, "SymGetModuleBase");
pfStackWalk = (PFN_StackWalk) GetProcAddress(hMod, "StackWalk");
if (pfStackWalk == 0 || pfSymInitialize == 0 || pfSymGetSymFromAddr == 0)
{
FreeLibrary(hMod);
return FALSE;
}
s_hProcess = GetCurrentProcess();
s_hPrivateHeap = HeapCreate(0, 0x8000, 0);
char chSymPath[MAX_PATH];
lstrcpy(chSymPath, SymPath);
BOOL bRes = pfSymInitialize(s_hProcess, chSymPath, TRUE);
if (!bRes)
return FALSE;
m_bActive = TRUE;
return TRUE;
}
//***************************************************************************
//
//***************************************************************************
//***************************************************************************
//
//***************************************************************************
BOOL StackTrace_GetSymbolByAddr(
LPVOID pAddr,
DWORD *pdwDisp,
int nBufSize,
char *pBuf
)
{
if (!m_bActive)
return FALSE;
BYTE Buf[256];
char File[256];
IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) Buf;
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
pSym->Address = 0;
pSym->Size = 0;
pSym->Flags = 0;
pSym->MaxNameLength = 128;
pSym->Name[0] = 0;
BOOL bRes = pfSymGetSymFromAddr(s_hProcess, DWORD(pAddr), pdwDisp, pSym);
if (!bRes)
{
DWORD dwRes = GetLastError();
if (dwRes == ERROR_INVALID_ADDRESS)
lstrcpy(pBuf, "Invalid Address");
else if (dwRes == ERROR_MOD_NOT_FOUND)
lstrcpy(pBuf, "Error: Module Not Found");
else
wsprintf(pBuf, "Error: GetLastError() = %d\n", dwRes);
return FALSE;
}
IMAGEHLP_LINE Line;
Line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
Line.Key = 0;
Line.LineNumber = 0;
Line.FileName = File;
Line.Address = 0;
/*if (pfSymGetLineFromAddr)
{
bRes = pfSymGetLineFromAddr(s_hProcess, DWORD(pAddr), pdwDisp, &Line);
if (!bRes)
return FALSE;
}
*/
lstrcpyn(pBuf, pSym->Name, nBufSize);
return TRUE;
}
void StackTrace_Delete(StackTrace *pMem)
{
pfnHeapFree(s_hPrivateHeap, 0, pMem);
}
//***************************************************************************
//
//***************************************************************************
void _FillMemory(LPVOID pMem, LONG lCount, BYTE b)
{
LPBYTE pArray = LPBYTE(pMem);
for (int i = 0; i < lCount; i++)
{
pArray[i] = b;
}
}
//***************************************************************************
//
//***************************************************************************
StackTrace *StackTrace__NewTrace()
{
if (!m_bActive)
return NULL;
HANDLE hThread = GetCurrentThread();
// Get the thread context, registers, etc.
// =======================================
CONTEXT ctx;
_FillMemory(&ctx, sizeof(ctx), 0);
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(hThread, &ctx);
// Set up the starting stack frame.
// ================================
STACKFRAME sf;
_FillMemory(&sf, sizeof(sf), 0);
sf.AddrPC.Offset = ctx.Eip;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Offset = ctx.Esp;
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Offset = ctx.Ebp;
sf.AddrFrame.Mode = AddrModeFlat;
// Walk the stack.
// ===============
const DWORD dwMaxAddresses = 128;
DWORD Addresses[dwMaxAddresses];
DWORD dwNumAddresses = 0;
for (int i = 0; ;i++)
{
BOOL bRes = pfStackWalk(
IMAGE_FILE_MACHINE_I386,
s_hProcess,
hThread,
&sf,
&ctx,
0,
pfSymFunctionTableAccess,
pfSymGetModuleBase,
NULL
);
if (bRes == FALSE)
break;
if (i == 0)
continue; // Skip the StackWalk frame itself
if (sf.AddrPC.Offset == 0)
break;
Addresses[dwNumAddresses++] = sf.AddrPC.Offset;
if (dwNumAddresses == dwMaxAddresses)
break;
}
// Now, allocate a StackTrace struct to return to user.
// ====================================================
StackTrace *pTrace = (StackTrace *) pfnHeapAlloc(s_hPrivateHeap, HEAP_ZERO_MEMORY,
sizeof(StackTrace) + sizeof(DWORD) * dwNumAddresses - 1);
pTrace->m_dwCount = dwNumAddresses;
for (DWORD dwIx = 0; dwIx < dwNumAddresses; dwIx++)
pTrace->m_dwAddresses[dwIx] = Addresses[dwIx];
return pTrace;
}
//***************************************************************************
//
//***************************************************************************
char *StackTrace_Dump(StackTrace *pTrace)
{
if (!m_bActive)
return 0;
char Buf[64];
char Buf2[256];
static char Buf3[8192];
*Buf3 = 0;
lstrcat(Buf, "---block---\r\n");
for (DWORD dwIx = 0; dwIx < pTrace->m_dwCount; dwIx++)
{
DWORD dwAddress = pTrace->m_dwAddresses[dwIx];
wsprintf(Buf, " 0x%08x ", dwAddress);
///////////////
char Name[128];
lstrcpy(Name, "<no symbol>\n");
DWORD dwDisp;
*Name = 0;
StackTrace_GetSymbolByAddr(LPVOID(dwAddress), &dwDisp, 127, Name);
////////////
wsprintf(Buf2, "%s disp=0x%04x <%s>\r\n", Buf, dwDisp, Name);
lstrcat(Buf3, Buf2);
}
return Buf3;
}