| OLD | NEW |
| 1 /* Copyright (c) 2008, Google Inc. | 1 /* Copyright (c) 2008, Google Inc. |
| 2 * All rights reserved. | 2 * All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 * | 29 * |
| 30 * --- | 30 * --- |
| 31 * Author: David Vitek | 31 * Author: David Vitek |
| 32 * | 32 * |
| 33 * Dump function addresses using Microsoft debug symbols. This works | 33 * Dump function addresses using Microsoft debug symbols. This works |
| 34 * on PDB files. Note that this program will download symbols to | 34 * on PDB files. Note that this program will download symbols to |
| 35 * c:\websymbols without asking. | 35 * c:\websymbols without asking. |
| 36 */ | 36 */ |
| 37 | 37 |
| 38 #ifndef WIN32_LEAN_AND_MEAN |
| 38 #define WIN32_LEAN_AND_MEAN | 39 #define WIN32_LEAN_AND_MEAN |
| 40 #endif |
| 41 |
| 42 #ifndef _CRT_SECURE_NO_WARNINGS |
| 39 #define _CRT_SECURE_NO_WARNINGS | 43 #define _CRT_SECURE_NO_WARNINGS |
| 44 #endif |
| 45 |
| 46 #ifndef _CRT_SECURE_NO_DEPRECATE |
| 40 #define _CRT_SECURE_NO_DEPRECATE | 47 #define _CRT_SECURE_NO_DEPRECATE |
| 48 #endif |
| 41 | 49 |
| 42 #include <stdio.h> | 50 #include <stdio.h> |
| 43 #include <stdlib.h> | 51 #include <stdlib.h> |
| 44 | 52 |
| 45 #include <windows.h> | 53 #include <windows.h> |
| 46 #include <dbghelp.h> | 54 #include <dbghelp.h> |
| 47 | 55 |
| 48 #define SEARCH_CAP (1024*1024) | 56 #define SEARCH_CAP (1024*1024) |
| 49 #define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols" | 57 #define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols" |
| 50 | 58 |
| 51 int main(int argc, char *argv[]) { | 59 int main(int argc, char *argv[]) { |
| 52 DWORD error; | 60 DWORD error; |
| 53 HANDLE process; | 61 HANDLE process; |
| 54 ULONG64 module_base; | 62 ULONG64 module_base; |
| 55 int i; | 63 int i; |
| 56 char* search; | 64 char* search; |
| 57 char buf[256]; /* Enough to hold one hex address, I trust! */ | 65 char buf[256]; /* Enough to hold one hex address, I trust! */ |
| 58 int rv = 0; | 66 int rv = 0; |
| 59 /* We may add SYMOPT_UNDNAME if --demangle is specified: */ | 67 /* We may add SYMOPT_UNDNAME if --demangle is specified: */ |
| 60 DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES; | 68 DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES; |
| 61 char* filename = "a.out"; /* The default if -e isn't specified */ | 69 char* filename = "a.out"; /* The default if -e isn't specified */ |
| 62 int print_function_name = 0; /* Set to 1 if -f is specified */ | 70 int print_function_name = 0; /* Set to 1 if -f is specified */ |
| 63 | 71 |
| 64 for (i = 1; i < argc; i++) { | 72 for (i = 1; i < argc; i++) { |
| 65 if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) { | 73 if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) { |
| 66 print_function_name = 1; | 74 print_function_name = 1; |
| 67 } else if (strcmp(argv[i], "--demangle") == 0 || | 75 } else if (strcmp(argv[i], "--demangle") == 0 || |
| 68 strcmp(argv[i], "-C") == 0) { | 76 strcmp(argv[i], "-C") == 0) { |
| 69 symopts |= SYMOPT_UNDNAME; | 77 symopts |= SYMOPT_UNDNAME; |
| 70 } else if (strcmp(argv[i], "-e") == 0) { | 78 } else if (strcmp(argv[i], "--exe") == 0 || |
| 79 strcmp(argv[i], "-e") == 0) { |
| 71 if (i + 1 >= argc) { | 80 if (i + 1 >= argc) { |
| 72 fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n"); | 81 fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n"); |
| 73 return 1; | 82 return 1; |
| 74 } | 83 } |
| 75 filename = argv[i+1]; | 84 filename = argv[i+1]; |
| 76 i++; /* to skip over filename too */ | 85 i++; /* to skip over filename too */ |
| 77 } else { | 86 } else { |
| 78 fprintf(stderr, "usage: " | 87 fprintf(stderr, "usage: " |
| 79 "addr2line-pdb [-f|--functions] [-C|--demangle] [-e filename]\n"); | 88 "addr2line-pdb [-f|--functions] [-C|--demangle] [-e filename]\n"); |
| 80 fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n"); | 89 fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n"); |
| 81 exit(1); | 90 exit(1); |
| 82 } | 91 } |
| 83 } | 92 } |
| 84 | 93 |
| 85 process = GetCurrentProcess(); | 94 process = GetCurrentProcess(); |
| 86 | 95 |
| 87 if (!SymInitialize(process, NULL, FALSE)) { | 96 if (!SymInitialize(process, NULL, FALSE)) { |
| 88 error = GetLastError(); | 97 error = GetLastError(); |
| 89 fprintf(stderr, "SymInitialize returned error : %d\n", error); | 98 fprintf(stderr, "SymInitialize returned error : %lu\n", error); |
| 90 return 1; | 99 return 1; |
| 91 } | 100 } |
| 92 | 101 |
| 93 search = malloc(SEARCH_CAP); | 102 search = malloc(SEARCH_CAP); |
| 94 if (SymGetSearchPath(process, search, SEARCH_CAP)) { | 103 if (SymGetSearchPath(process, search, SEARCH_CAP)) { |
| 95 if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { | 104 if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { |
| 96 fprintf(stderr, "Search path too long\n"); | 105 fprintf(stderr, "Search path too long\n"); |
| 97 SymCleanup(process); | 106 SymCleanup(process); |
| 98 return 1; | 107 return 1; |
| 99 } | 108 } |
| 100 strcat(search, ";" WEBSYM); | 109 strcat(search, ";" WEBSYM); |
| 101 } else { | 110 } else { |
| 102 error = GetLastError(); | 111 error = GetLastError(); |
| 103 fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); | 112 fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error); |
| 104 rv = 1; /* An error, but not a fatal one */ | 113 rv = 1; /* An error, but not a fatal one */ |
| 105 strcpy(search, WEBSYM); /* Use a default value */ | 114 strcpy(search, WEBSYM); /* Use a default value */ |
| 106 } | 115 } |
| 107 if (!SymSetSearchPath(process, search)) { | 116 if (!SymSetSearchPath(process, search)) { |
| 108 error = GetLastError(); | 117 error = GetLastError(); |
| 109 fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); | 118 fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error); |
| 110 rv = 1; /* An error, but not a fatal one */ | 119 rv = 1; /* An error, but not a fatal one */ |
| 111 } | 120 } |
| 112 | 121 |
| 113 SymSetOptions(symopts); | 122 SymSetOptions(symopts); |
| 114 module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); | 123 module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); |
| 115 if (!module_base) { | 124 if (!module_base) { |
| 116 /* SymLoadModuleEx failed */ | 125 /* SymLoadModuleEx failed */ |
| 117 error = GetLastError(); | 126 error = GetLastError(); |
| 118 fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", | 127 fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n", |
| 119 error, filename); | 128 error, filename); |
| 120 SymCleanup(process); | 129 SymCleanup(process); |
| 121 return 1; | 130 return 1; |
| 122 } | 131 } |
| 123 | 132 |
| 124 buf[sizeof(buf)-1] = '\0'; /* Just to be safe */ | 133 buf[sizeof(buf)-1] = '\0'; /* Just to be safe */ |
| 125 while (fgets(buf, sizeof(buf)-1, stdin)) { | 134 while (fgets(buf, sizeof(buf)-1, stdin)) { |
| 126 /* GNU addr2line seems to just do a strtol and ignore any | 135 /* GNU addr2line seems to just do a strtol and ignore any |
| 127 * weird characters it gets, so we will too. | 136 * weird characters it gets, so we will too. |
| 128 */ | 137 */ |
| 129 unsigned __int64 addr = _strtoui64(buf, NULL, 16); | 138 unsigned __int64 reladdr = _strtoui64(buf, NULL, 16); |
| 130 ULONG64 buffer[(sizeof(SYMBOL_INFO) + | 139 ULONG64 buffer[(sizeof(SYMBOL_INFO) + |
| 131 MAX_SYM_NAME*sizeof(TCHAR) + | 140 MAX_SYM_NAME*sizeof(TCHAR) + |
| 132 sizeof(ULONG64) - 1) | 141 sizeof(ULONG64) - 1) |
| 133 / sizeof(ULONG64)]; | 142 / sizeof(ULONG64)]; |
| 134 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; | 143 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; |
| 135 IMAGEHLP_LINE64 line; | 144 IMAGEHLP_LINE64 line; |
| 136 DWORD dummy; | 145 DWORD dummy; |
| 146 |
| 147 // Just ignore overflow. In an overflow scenario, the resulting address |
| 148 // will be lower than module_base which hasn't been mapped by any prior |
| 149 // SymLoadModuleEx() command. This will cause SymFromAddr() and |
| 150 // SymGetLineFromAddr64() both to return failures and print the correct |
| 151 // ?? and ??:0 message variant. |
| 152 ULONG64 absaddr = reladdr + module_base; |
| 153 |
| 137 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); | 154 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
| 138 pSymbol->MaxNameLen = MAX_SYM_NAME; | 155 pSymbol->MaxNameLen = MAX_SYM_NAME; |
| 139 if (print_function_name) { | 156 if (print_function_name) { |
| 140 if (SymFromAddr(process, (DWORD64)addr, NULL, pSymbol)) { | 157 if (SymFromAddr(process, (DWORD64)absaddr, NULL, pSymbol)) { |
| 141 printf("%s\n", pSymbol->Name); | 158 printf("%s\n", pSymbol->Name); |
| 142 } else { | 159 } else { |
| 143 printf("??\n"); | 160 printf("??\n"); |
| 144 } | 161 } |
| 145 } | 162 } |
| 146 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); | 163 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); |
| 147 if (SymGetLineFromAddr64(process, (DWORD64)addr, &dummy, &line)) { | 164 if (SymGetLineFromAddr64(process, (DWORD64)absaddr, &dummy, &line)) { |
| 148 printf("%s:%d\n", line.FileName, (int)line.LineNumber); | 165 printf("%s:%d\n", line.FileName, (int)line.LineNumber); |
| 149 } else { | 166 } else { |
| 150 printf("??:0\n"); | 167 printf("??:0\n"); |
| 151 } | 168 } |
| 152 } | 169 } |
| 153 SymUnloadModule64(process, module_base); | 170 SymUnloadModule64(process, module_base); |
| 154 SymCleanup(process); | 171 SymCleanup(process); |
| 155 return rv; | 172 return rv; |
| 156 } | 173 } |
| OLD | NEW |