sym_resolver.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright (c) 2009 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // A smaller wrapper around the dbghelp symbol resolution routines.
  5. // For example:
  6. // SymResolver resolver("ntdll.dll");
  7. // resolver.Resolve("ntdll!NtBlahBlah");
  8. #ifndef TRACELINE_SYM_RESOLVER_H_
  9. #define TRACELINE_SYM_RESOLVER_H_
  10. #include <windows.h>
  11. #include <dbghelp.h>
  12. #include <vector>
  13. #include <string>
  14. #include <map>
  15. static BOOL CALLBACK SymEnumer(PCSTR name, DWORD64 base, PVOID context) {
  16. reinterpret_cast<std::vector<DWORD64>*>(context)->push_back(base);
  17. return TRUE;
  18. }
  19. class SymResolver {
  20. public:
  21. // Constructor to load a single DLL.
  22. SymResolver(const char* dllname, HANDLE proc = ::GetCurrentProcess())
  23. : proc_(proc) {
  24. // TODO(deanm): Would be nice to get this from WinDBG, but it's buried
  25. // in the workspace data blob... _NT_SYMBOL_PATH is not usually set...
  26. static char* kSymbolPath =
  27. "C:\\Program Files\\Debugging Tools for Windows (x86)\\sym;"
  28. "C:\\Program Files\\Debugging Tools for Windows\\sym";
  29. // If we want to load a specific DLL, or we want to load all.
  30. if (::SymInitialize(proc_, kSymbolPath, dllname ? FALSE : TRUE) != TRUE) {
  31. NOTREACHED("SymInitialize failed: %d", GetLastError());
  32. }
  33. base_ = 0;
  34. if (dllname) {
  35. base_ = ::SymLoadModuleEx(proc_,
  36. NULL,
  37. const_cast<char*>(dllname),
  38. NULL,
  39. reinterpret_cast<DWORD64>(
  40. GetModuleHandleA(dllname)),
  41. 0,
  42. NULL,
  43. 0);
  44. if (base_ == 0) {
  45. NOTREACHED("SymLoadModuleEx(%s) failed: %d", dllname, GetLastError());
  46. }
  47. }
  48. std::vector<DWORD64> bases;
  49. // The name returned from SymEnumerateModules64 doesn't include the ext,
  50. // so we can't differentiate between a dll and exe of the same name. So
  51. // collect all of the base addresses and query for more info.
  52. // The prototype changed from PSTR to PCSTR, so in order to support older
  53. // SDKs we have to cast SymEnumer.
  54. PSYM_ENUMMODULES_CALLBACK64 enumer =
  55. reinterpret_cast<PSYM_ENUMMODULES_CALLBACK64>(&SymEnumer);
  56. if (SymEnumerateModules64(proc_, enumer, &bases) != TRUE) {
  57. NOTREACHED("SymEnumerateModules64 failed: %d\n", GetLastError());
  58. }
  59. for (size_t i = 0; i < bases.size(); ++i) {
  60. // This was failing, turns out I was just using the system32
  61. // dbghelp.dll which is old, use the one from windbg :(
  62. IMAGEHLP_MODULE64 info;
  63. info.SizeOfStruct = sizeof(info);
  64. if (SymGetModuleInfo64(proc_, bases[i], &info) != TRUE) {
  65. NOTREACHED("SymGetModuleInfo64 failed: %d\n", GetLastError());
  66. }
  67. std::string filename(info.ImageName);
  68. size_t last_slash = filename.find_last_of('\\');
  69. if (last_slash != std::string::npos)
  70. filename = filename.substr(filename.find_last_of('\\') + 1);
  71. // Map the base address to the image name...
  72. dlls_[static_cast<int>(bases[i])] = filename;
  73. }
  74. // TODO(deanm): check the symbols are rad and stuff...
  75. }
  76. char* Resolve(const char* name) {
  77. // The API writes to the space after SYMBOL_INFO...
  78. struct {
  79. SYMBOL_INFO info;
  80. char buf[128];
  81. } info = {0};
  82. info.info.SizeOfStruct = sizeof(info.info);
  83. info.info.ModBase = base_;
  84. info.info.MaxNameLen = 127;
  85. if (SymFromName(proc_, const_cast<char*>(name), &info.info) != TRUE) {
  86. NOTREACHED("SymFromName(%s) failed: %d", name, GetLastError());
  87. }
  88. return reinterpret_cast<char*>(info.info.Address);
  89. }
  90. std::string Unresolve(int ptr) {
  91. // The API writes to the space after SYMBOL_INFO...
  92. struct {
  93. SYMBOL_INFO info;
  94. char buf[128];
  95. } info = {0};
  96. info.info.SizeOfStruct = sizeof(info.info);
  97. info.info.ModBase = base_;
  98. info.info.MaxNameLen = 127;
  99. if (!::SymFromAddr(proc_, static_cast<DWORD64>(ptr), NULL, &info.info)) {
  100. return std::string("failed");
  101. }
  102. std::string name;
  103. int addr = static_cast<int>(info.info.Address);
  104. int base = static_cast<int>(info.info.ModBase);
  105. if (dlls_.count(base) == 1) {
  106. name.append(dlls_[base]);
  107. } else {
  108. name.append("unknown_mod");
  109. }
  110. name.push_back('!');
  111. name.append(info.info.Name);
  112. char buf[32];
  113. _itoa_s(ptr - addr, buf, sizeof(buf), 16);
  114. name.append("+0x");
  115. name.append(buf);
  116. DWORD disp;
  117. IMAGEHLP_LINE64 line;
  118. if (::SymGetLineFromAddr64(
  119. proc_, static_cast<DWORD64>(ptr), &disp, &line)) {
  120. name.append(" [ ");
  121. name.append(line.FileName);
  122. name.append(":");
  123. _itoa_s(line.LineNumber, buf, sizeof(buf), 10);
  124. name.append(buf);
  125. name.append(" ]");
  126. }
  127. return name;
  128. }
  129. ~SymResolver() {
  130. if (::SymCleanup(proc_) != TRUE) {
  131. NOTREACHED("SymCleanup failed: %d", GetLastError());
  132. }
  133. }
  134. private:
  135. HANDLE proc_;
  136. ULONG64 base_;
  137. std::map<int, std::string> dlls_;
  138. };
  139. #endif // TRACELINE_SYM_RESOLVER_H_