// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // A smaller wrapper around the dbghelp symbol resolution routines. // For example: // SymResolver resolver("ntdll.dll"); // resolver.Resolve("ntdll!NtBlahBlah"); #ifndef TRACELINE_SYM_RESOLVER_H_ #define TRACELINE_SYM_RESOLVER_H_ #include #include #include #include #include static BOOL CALLBACK SymEnumer(PCSTR name, DWORD64 base, PVOID context) { reinterpret_cast*>(context)->push_back(base); return TRUE; } class SymResolver { public: // Constructor to load a single DLL. SymResolver(const char* dllname, HANDLE proc = ::GetCurrentProcess()) : proc_(proc) { // TODO(deanm): Would be nice to get this from WinDBG, but it's buried // in the workspace data blob... _NT_SYMBOL_PATH is not usually set... static char* kSymbolPath = "C:\\Program Files\\Debugging Tools for Windows (x86)\\sym;" "C:\\Program Files\\Debugging Tools for Windows\\sym"; // If we want to load a specific DLL, or we want to load all. if (::SymInitialize(proc_, kSymbolPath, dllname ? FALSE : TRUE) != TRUE) { NOTREACHED("SymInitialize failed: %d", GetLastError()); } base_ = 0; if (dllname) { base_ = ::SymLoadModuleEx(proc_, NULL, const_cast(dllname), NULL, reinterpret_cast( GetModuleHandleA(dllname)), 0, NULL, 0); if (base_ == 0) { NOTREACHED("SymLoadModuleEx(%s) failed: %d", dllname, GetLastError()); } } std::vector bases; // The name returned from SymEnumerateModules64 doesn't include the ext, // so we can't differentiate between a dll and exe of the same name. So // collect all of the base addresses and query for more info. // The prototype changed from PSTR to PCSTR, so in order to support older // SDKs we have to cast SymEnumer. PSYM_ENUMMODULES_CALLBACK64 enumer = reinterpret_cast(&SymEnumer); if (SymEnumerateModules64(proc_, enumer, &bases) != TRUE) { NOTREACHED("SymEnumerateModules64 failed: %d\n", GetLastError()); } for (size_t i = 0; i < bases.size(); ++i) { // This was failing, turns out I was just using the system32 // dbghelp.dll which is old, use the one from windbg :( IMAGEHLP_MODULE64 info; info.SizeOfStruct = sizeof(info); if (SymGetModuleInfo64(proc_, bases[i], &info) != TRUE) { NOTREACHED("SymGetModuleInfo64 failed: %d\n", GetLastError()); } std::string filename(info.ImageName); size_t last_slash = filename.find_last_of('\\'); if (last_slash != std::string::npos) filename = filename.substr(filename.find_last_of('\\') + 1); // Map the base address to the image name... dlls_[static_cast(bases[i])] = filename; } // TODO(deanm): check the symbols are rad and stuff... } char* Resolve(const char* name) { // The API writes to the space after SYMBOL_INFO... struct { SYMBOL_INFO info; char buf[128]; } info = {0}; info.info.SizeOfStruct = sizeof(info.info); info.info.ModBase = base_; info.info.MaxNameLen = 127; if (SymFromName(proc_, const_cast(name), &info.info) != TRUE) { NOTREACHED("SymFromName(%s) failed: %d", name, GetLastError()); } return reinterpret_cast(info.info.Address); } std::string Unresolve(int ptr) { // The API writes to the space after SYMBOL_INFO... struct { SYMBOL_INFO info; char buf[128]; } info = {0}; info.info.SizeOfStruct = sizeof(info.info); info.info.ModBase = base_; info.info.MaxNameLen = 127; if (!::SymFromAddr(proc_, static_cast(ptr), NULL, &info.info)) { return std::string("failed"); } std::string name; int addr = static_cast(info.info.Address); int base = static_cast(info.info.ModBase); if (dlls_.count(base) == 1) { name.append(dlls_[base]); } else { name.append("unknown_mod"); } name.push_back('!'); name.append(info.info.Name); char buf[32]; _itoa_s(ptr - addr, buf, sizeof(buf), 16); name.append("+0x"); name.append(buf); DWORD disp; IMAGEHLP_LINE64 line; if (::SymGetLineFromAddr64( proc_, static_cast(ptr), &disp, &line)) { name.append(" [ "); name.append(line.FileName); name.append(":"); _itoa_s(line.LineNumber, buf, sizeof(buf), 10); name.append(buf); name.append(" ]"); } return name; } ~SymResolver() { if (::SymCleanup(proc_) != TRUE) { NOTREACHED("SymCleanup failed: %d", GetLastError()); } } private: HANDLE proc_; ULONG64 base_; std::map dlls_; }; #endif // TRACELINE_SYM_RESOLVER_H_