#include #include #ifndef R_OK # define R_OK 4 /* Test for read permission. */ # define W_OK 2 /* Test for write permission. */ # define X_OK 1 /* Test for execute permission. */ # define F_OK 0 /* Test for existence. */ #endif #define NL "\n" //#define LOCAL_DEBUG //#if defined(LOCAL_DEBUG) #include //#endif namespace pdbutils { HANDLE _currentProcess = 0; #if defined(LOCAL_DEBUG) # define DOUT(msg) do { std::cout << msg; } while (false) # define DOUTNL(msg) do { std::cout << msg << std::endl; } while (false) #else # define DOUT(msg) # define DOUTNL(msg) #endif #define ELOGNL(msg) do { DbgStream out; out << msg << NL; OutputDebugString(out.str().c_str()); } while (false) namespace { } static intptr_t CurrentPointerRecursion = 0; static bool _init_sys_libs() { static bool _inited = false; if (_inited == true) return true; //SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); SymSetOptions( SYMOPT_DEFERRED_LOADS ); if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) return false; _currentProcess = GetCurrentProcess(); char sympath[4096]; SymGetSearchPath(_currentProcess, sympath, sizeof(sympath)); char moduleFilename[MAX_PATH]; memset(moduleFilename, 0, sizeof(moduleFilename)); HMODULE hm = GetModuleHandle(NULL); GetModuleFileName(hm, moduleFilename, MAX_PATH); DbgString mfile = moduleFilename; intptr_t lidx = DBGSTRING_LASTINDEX(mfile, "\\"); if (lidx != -1) { DbgString modulepath = DBGSTRING_SUBSTR2(mfile, 0, lidx); DbgString modname = DBGSTRING_SUBSTR1(mfile, lidx + 1); modname = DBGSTRING_SUBSTR2(modname, 0, DBGSTRING_SIZE(modname) - 4); // asume .exe DbgString str = sympath; str = str + ";" + modulepath; str = str + ";" + modulepath + "\\" + modname + "_pdbs"; SymSetSearchPath(_currentProcess, (char*)DBGSTRING2CHARPTR(str)); char buffer[1024]; SymGetSearchPath(_currentProcess, buffer, 1024); ELOGNL("Set new SymbolPath: " << (char*)buffer); } else { DOUTNL("Cannot set new SymbolPath: " << (char*)DBGSTRING2CHARPTR(mfile)); } _inited = true; return _inited; } bool DbgFrame::findElementForAddress(void* addr, DbgType& type) const { intptr_t i = 0; for (i = 0; i < params.size(); ++i) { if (params[i].findElementForAddress(addr, type) == true) return true; } for (i = 0; i < locals.size(); ++i) { if (locals[i].findElementForAddress(addr, type) == true) return true; } return false; } //static intptr_t getProgramCounters(FrameAddress* frames, intptr_t pccount, void* threadHandle) { if (_init_sys_libs() == false) return 0; if (threadHandle == 0) threadHandle = GetCurrentThread(); DWORD dwMachineType = 0; memset(frames, 0, sizeof(FrameAddress) * pccount); STACKFRAME64 sf; memset(&sf, 0, sizeof(sf)); CONTEXT context; context.ContextFlags = CONTEXT_FULL; HANDLE currentThread = threadHandle; HANDLE currentProcess = _currentProcess; if (GetThreadContext(currentThread, &context) == 0) return 0; #ifdef _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 = context.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = context.Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.Ebp; sf.AddrFrame.Mode = AddrModeFlat; dwMachineType = IMAGE_FILE_MACHINE_I386; #endif #ifdef _M_X64 dwMachineType = IMAGE_FILE_MACHINE_AMD64; #endif intptr_t i; for (i = 0; i < pccount; ++i) { // Get the next stack frame if ( ! StackWalk64( dwMachineType, currentProcess, currentThread, &sf, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL ) ) break; if( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure break; // the frame is OK. Bail if not. frames[i].address = (intptr_t) sf.AddrPC.Offset; frames[i].offset = (intptr_t) sf.AddrFrame.Offset; } return i; } //static intptr_t getProgramCounters(FrameAddress* frames, intptr_t pccount, CONTEXT& context) { if (_init_sys_libs() == false) return 0; DWORD dwMachineType = 0; memset(frames, 0, sizeof(FrameAddress) * pccount); STACKFRAME sf; memset(&sf, 0, sizeof(sf)); HANDLE currentThread = GetCurrentThread(); //CONTEXT context; //context.ContextFlags = CONTEXT_FULL; #ifdef _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 = context.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = context.Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.Ebp; sf.AddrFrame.Mode = AddrModeFlat; dwMachineType = IMAGE_FILE_MACHINE_I386; #endif intptr_t i ; for (i = 0; i < pccount; ++i) { // Get the next stack frame if ( ! StackWalk( dwMachineType, _currentProcess, NULL, &sf, &context, 0, SymFunctionTableAccess, SymGetModuleBase, 0 ) ) break; if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure break; // the frame is OK. Bail if not. frames[i].address = (int)sf.AddrPC.Offset; frames[i].offset = (int)sf.AddrFrame.Offset; } return i; } static bool get_logical_address(void * addr, char * szModule, uintptr_t len, uintptr_t & section, uintptr_t & offset) { MEMORY_BASIC_INFORMATION mbi; if (VirtualQuery( addr, &mbi, sizeof(mbi)) == FALSE) return false; uintptr_t hMod = (uintptr_t) mbi.AllocationBase; if (GetModuleFileName((HMODULE) hMod, szModule, (DWORD) len) == FALSE) return false; PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod; if (pDosHdr == 0) return false; PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew); PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION( pNtHdr ); uintptr_t rva = (uintptr_t) addr - hMod; for (intptr_t i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++) { uintptr_t sectionStart = pSection->VirtualAddress; uintptr_t sectionEnd = sectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize); if ((rva >= sectionStart) && (rva <= sectionEnd)) { section = DWORD(i + 1); offset = rva - sectionStart; return true; } } return false; } bool querySymbolValue(PSYMBOL_INFO pSym, DbgFrame& frame); static BOOL CALLBACK dbgutils_enumerateSymbolsCallback(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext) { //char szBuffer[2048]; DbgFrame *dbframe = (DbgFrame*)UserContext; __try { querySymbolValue( pSymInfo, *((DbgFrame*)UserContext)); } __except( 1 ) { dbframe->functionName = "pdbutils: Unexpected Failure in Parsing PDB-Info"; DOUTNL("punting on symbol: " << pSymInfo->Name); } return TRUE; } static void dbgutils_getFrame(const FrameAddress& frameAddr, DbgFrame& frame) { BYTE symbolBuffer[sizeof(SYMBOL_INFO) + 1024]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; pSymbol->SizeOfStruct = sizeof(symbolBuffer); pSymbol->MaxNameLen = 1024; DOUTNL("Frame: " << (void*)frameAddr.offset << ", " << (void*)frameAddr.offset); if (frame.queryFlags & DbgFrameGetFuncName) { DWORD64 symDisplacement = 0; if (SymFromAddr(_currentProcess, frameAddr.address, &symDisplacement, pSymbol)) { frame.displacement = symDisplacement; frame.functionName = pSymbol->Name; if (frame.functionName.startsWith("pdbutils") == true) { frame.functionName = frame.functionName + "