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 38 #define WIN32_LEAN_AND_MEAN 39 #define _CRT_SECURE_NO_WARNINGS 40 #define _CRT_SECURE_NO_DEPRECATE 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 45 #include <windows.h> 46 #include <dbghelp.h> 47 48 #define SEARCH_CAP (1024*1024) 49 #define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols" 50 51 int main(int argc, char *argv[]) { 52 DWORD error; 53 HANDLE process; 54 ULONG64 module_base; 55 int i; 56 char* search; 57 char buf[256]; /* Enough to hold one hex address, I trust! */ 58 int rv = 0; 59 /* We may add SYMOPT_UNDNAME if --demangle is specified: */ 60 DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES; 61 char* filename = "a.out"; /* The default if -e isn't specified */ 62 int print_function_name = 0; /* Set to 1 if -f is specified */ 63 64 for (i = 1; i < argc; i++) { 65 if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) { 66 print_function_name = 1; 67 } else if (strcmp(argv[i], "--demangle") == 0 || 68 strcmp(argv[i], "-C") == 0) { 69 symopts |= SYMOPT_UNDNAME; 70 } else if (strcmp(argv[i], "-e") == 0) { 71 if (i + 1 >= argc) { 72 fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n"); 73 return 1; 74 } 75 filename = argv[i+1]; 76 i++; /* to skip over filename too */ 77 } else { 78 fprintf(stderr, "usage: " 79 "addr2line-pdb [-f|--functions] [-C|--demangle] [-e filename]\n"); 80 fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n"); 81 exit(1); 82 } 83 } 84 85 process = GetCurrentProcess(); 86 87 if (!SymInitialize(process, NULL, FALSE)) { 88 error = GetLastError(); 89 fprintf(stderr, "SymInitialize returned error : %d\n", error); 90 return 1; 91 } 92 93 search = malloc(SEARCH_CAP); 94 if (SymGetSearchPath(process, search, SEARCH_CAP)) { 95 if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { 96 fprintf(stderr, "Search path too long\n"); 97 SymCleanup(process); 98 return 1; 99 } 100 strcat(search, ";" WEBSYM); 101 } else { 102 error = GetLastError(); 103 fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); 104 rv = 1; /* An error, but not a fatal one */ 105 strcpy(search, WEBSYM); /* Use a default value */ 106 } 107 if (!SymSetSearchPath(process, search)) { 108 error = GetLastError(); 109 fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); 110 rv = 1; /* An error, but not a fatal one */ 111 } 112 113 SymSetOptions(symopts); 114 module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); 115 if (!module_base) { 116 /* SymLoadModuleEx failed */ 117 error = GetLastError(); 118 fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", 119 error, filename); 120 SymCleanup(process); 121 return 1; 122 } 123 124 buf[sizeof(buf)-1] = '\0'; /* Just to be safe */ 125 while (fgets(buf, sizeof(buf)-1, stdin)) { 126 /* GNU addr2line seems to just do a strtol and ignore any 127 * weird characters it gets, so we will too. 128 */ 129 unsigned __int64 addr = _strtoui64(buf, NULL, 16); 130 ULONG64 buffer[(sizeof(SYMBOL_INFO) + 131 MAX_SYM_NAME*sizeof(TCHAR) + 132 sizeof(ULONG64) - 1) 133 / sizeof(ULONG64)]; 134 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; 135 IMAGEHLP_LINE64 line; 136 DWORD dummy; 137 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); 138 pSymbol->MaxNameLen = MAX_SYM_NAME; 139 if (print_function_name) { 140 if (SymFromAddr(process, (DWORD64)addr, NULL, pSymbol)) { 141 printf("%s\n", pSymbol->Name); 142 } else { 143 printf("??\n"); 144 } 145 } 146 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 147 if (SymGetLineFromAddr64(process, (DWORD64)addr, &dummy, &line)) { 148 printf("%s:%d\n", line.FileName, (int)line.LineNumber); 149 } else { 150 printf("??:0\n"); 151 } 152 } 153 SymUnloadModule64(process, module_base); 154 SymCleanup(process); 155 return rv; 156 } 157