nm-pdb.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /* Copyright (c) 2008, Google Inc.
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. * ---
  31. * Author: David Vitek
  32. *
  33. * Dump function addresses using Microsoft debug symbols. This works
  34. * on PDB files. Note that this program will download symbols to
  35. * c:\websymbols without asking.
  36. */
  37. #define WIN32_LEAN_AND_MEAN
  38. #define _CRT_SECURE_NO_WARNINGS
  39. #define _CRT_SECURE_NO_DEPRECATE
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h> // for _strdup
  43. #include <windows.h>
  44. #include <dbghelp.h>
  45. // Unfortunately, there is no versioning info in dbghelp.h so I can
  46. // tell whether it has an old-style (circa VC7.1) IMAGEHLP_MODULE64
  47. // struct, with only a few fields, or a new-style (circa VC8)
  48. // IMAGEHLP_MODULE64, with lots of fields. These fields are just used
  49. // for debugging, so it's fine to just assume the smaller struct, but
  50. // for most people, using a modern MSVC, the full struct is available.
  51. // If you are one of those people and would like this extra debugging
  52. // info, you can uncomment the line below.
  53. //#define VC8_OR_ABOVE
  54. #define SEARCH_CAP (1024*1024)
  55. #define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
  56. typedef struct {
  57. char *name;
  58. ULONG64 addr;
  59. ULONG flags;
  60. } SYM;
  61. typedef struct {
  62. ULONG64 module_base;
  63. SYM *syms;
  64. DWORD syms_len;
  65. DWORD syms_cap;
  66. } SYM_CONTEXT;
  67. static int sym_cmp(const void *_s1, const void *_s2) {
  68. const SYM *s1 = (const SYM *)_s1;
  69. const SYM *s2 = (const SYM *)_s2;
  70. if (s1->addr < s2->addr)
  71. return -1;
  72. if (s1->addr > s2->addr)
  73. return 1;
  74. return 0;
  75. }
  76. static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO symbol_info,
  77. ULONG symbol_size,
  78. PVOID user_context) {
  79. SYM_CONTEXT *ctx = (SYM_CONTEXT*)user_context;
  80. if (symbol_info->Address < ctx->module_base ||
  81. (symbol_info->Flags & SYMFLAG_TLSREL)) {
  82. return TRUE;
  83. }
  84. if (ctx->syms_len == ctx->syms_cap) {
  85. if (!ctx->syms_cap)
  86. ctx->syms_cap++;
  87. ctx->syms_cap *= 2;
  88. ctx->syms = realloc(ctx->syms, sizeof(ctx->syms[0]) * ctx->syms_cap);
  89. }
  90. ctx->syms[ctx->syms_len].name = _strdup(symbol_info->Name);
  91. ctx->syms[ctx->syms_len].addr = symbol_info->Address;
  92. ctx->syms[ctx->syms_len].flags = symbol_info->Flags;
  93. ctx->syms_len++;
  94. return TRUE;
  95. }
  96. static void MaybePrint(const char* var, const char* description) {
  97. if (var[0])
  98. printf("%s: %s\n", description, var);
  99. }
  100. static void PrintAvailability(BOOL var, const char *description) {
  101. printf("%s: %s\n", description, (var ? "Available" : "Not available"));
  102. }
  103. static void ShowSymbolInfo(HANDLE process, ULONG64 module_base) {
  104. /* Get module information. */
  105. IMAGEHLP_MODULE64 module_info;
  106. BOOL getmoduleinfo_rv;
  107. printf("Load Address: %I64x\n", module_base);
  108. memset(&module_info, 0, sizeof(module_info));
  109. module_info.SizeOfStruct = sizeof(module_info);
  110. getmoduleinfo_rv = SymGetModuleInfo64(process, module_base, &module_info);
  111. if (!getmoduleinfo_rv) {
  112. printf("Error: SymGetModuleInfo64() failed. Error code: %u\n",
  113. GetLastError());
  114. return;
  115. }
  116. /* Display information about symbols, based on kind of symbol. */
  117. switch (module_info.SymType) {
  118. case SymNone:
  119. printf(("No symbols available for the module.\n"));
  120. break;
  121. case SymExport:
  122. printf(("Loaded symbols: Exports\n"));
  123. break;
  124. case SymCoff:
  125. printf(("Loaded symbols: COFF\n"));
  126. break;
  127. case SymCv:
  128. printf(("Loaded symbols: CodeView\n"));
  129. break;
  130. case SymSym:
  131. printf(("Loaded symbols: SYM\n"));
  132. break;
  133. case SymVirtual:
  134. printf(("Loaded symbols: Virtual\n"));
  135. break;
  136. case SymPdb:
  137. printf(("Loaded symbols: PDB\n"));
  138. break;
  139. case SymDia:
  140. printf(("Loaded symbols: DIA\n"));
  141. break;
  142. case SymDeferred:
  143. printf(("Loaded symbols: Deferred\n")); /* not actually loaded */
  144. break;
  145. default:
  146. printf(("Loaded symbols: Unknown format.\n"));
  147. break;
  148. }
  149. MaybePrint("Image name", module_info.ImageName);
  150. MaybePrint("Loaded image name", module_info.LoadedImageName);
  151. #ifdef VC8_OR_ABOVE /* TODO(csilvers): figure out how to tell */
  152. MaybePrint("PDB file name", module_info.LoadedPdbName);
  153. if (module_info.PdbUnmatched || module_info.DbgUnmatched) {
  154. /* This can only happen if the debug information is contained in a
  155. * separate file (.DBG or .PDB)
  156. */
  157. printf(("Warning: Unmatched symbols.\n"));
  158. }
  159. #endif
  160. /* Contents */
  161. #ifdef VC8_OR_ABOVE /* TODO(csilvers): figure out how to tell */
  162. PrintAvailability("Line numbers", module_info.LineNumbers);
  163. PrintAvailability("Global symbols", module_info.GlobalSymbols);
  164. PrintAvailability("Type information", module_info.TypeInfo);
  165. #endif
  166. }
  167. void usage() {
  168. fprintf(stderr, "usage: nm-pdb [-C|--demangle] <module or filename>\n");
  169. }
  170. int main(int argc, char *argv[]) {
  171. DWORD error;
  172. HANDLE process;
  173. ULONG64 module_base;
  174. SYM_CONTEXT ctx;
  175. int i;
  176. char* search;
  177. char* filename = NULL;
  178. int rv = 0;
  179. /* We may add SYMOPT_UNDNAME if --demangle is specified: */
  180. DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG;
  181. for (i = 1; i < argc; i++) {
  182. if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) {
  183. symopts |= SYMOPT_UNDNAME;
  184. } else if (strcmp(argv[i], "--help") == 0) {
  185. usage();
  186. exit(0);
  187. } else {
  188. break;
  189. }
  190. }
  191. if (i != argc - 1) {
  192. usage();
  193. exit(1);
  194. }
  195. filename = argv[i];
  196. process = GetCurrentProcess();
  197. if (!SymInitialize(process, NULL, FALSE)) {
  198. error = GetLastError();
  199. fprintf(stderr, "SymInitialize returned error : %d\n", error);
  200. return 1;
  201. }
  202. search = malloc(SEARCH_CAP);
  203. if (SymGetSearchPath(process, search, SEARCH_CAP)) {
  204. if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) {
  205. fprintf(stderr, "Search path too long\n");
  206. SymCleanup(process);
  207. return 1;
  208. }
  209. strcat(search, ";" WEBSYM);
  210. } else {
  211. error = GetLastError();
  212. fprintf(stderr, "SymGetSearchPath returned error : %d\n", error);
  213. rv = 1; /* An error, but not a fatal one */
  214. strcpy(search, WEBSYM); /* Use a default value */
  215. }
  216. if (!SymSetSearchPath(process, search)) {
  217. error = GetLastError();
  218. fprintf(stderr, "SymSetSearchPath returned error : %d\n", error);
  219. rv = 1; /* An error, but not a fatal one */
  220. }
  221. SymSetOptions(symopts);
  222. module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0);
  223. if (!module_base) {
  224. /* SymLoadModuleEx failed */
  225. error = GetLastError();
  226. fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n",
  227. error, filename);
  228. SymCleanup(process);
  229. return 1;
  230. }
  231. ShowSymbolInfo(process, module_base);
  232. memset(&ctx, 0, sizeof(ctx));
  233. ctx.module_base = module_base;
  234. if (!SymEnumSymbols(process, module_base, NULL, EnumSymProc, &ctx)) {
  235. error = GetLastError();
  236. fprintf(stderr, "SymEnumSymbols returned error: %d\n", error);
  237. rv = 1;
  238. } else {
  239. DWORD j;
  240. qsort(ctx.syms, ctx.syms_len, sizeof(ctx.syms[0]), sym_cmp);
  241. for (j = 0; j < ctx.syms_len; j++) {
  242. printf("%016I64x X %s\n", ctx.syms[j].addr, ctx.syms[j].name);
  243. }
  244. /* In a perfect world, maybe we'd clean up ctx's memory? */
  245. }
  246. SymUnloadModule64(process, module_base);
  247. SymCleanup(process);
  248. return rv;
  249. }