/*++ Copyright (C) 1999-2001 Microsoft Corporation Module Name: STKTRACE.CPP Abstract: Symbolic stack trace History: raymcc 27-May-99 --*/ #include #include #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, "\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; }