blob: 88d207bbedc1ad22ffeef630f3ac2bec431a97cd [file] [log] [blame]
Brian Silverman20350ac2021-11-17 18:19:55 -08001/* -*- Mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */
Austin Schuh745610d2015-09-06 18:19:50 -07002/* Copyright (c) 2008, Google Inc.
3 * All rights reserved.
Brian Silverman20350ac2021-11-17 18:19:55 -08004 *
Austin Schuh745610d2015-09-06 18:19:50 -07005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
Brian Silverman20350ac2021-11-17 18:19:55 -08008 *
Austin Schuh745610d2015-09-06 18:19:50 -07009 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
Brian Silverman20350ac2021-11-17 18:19:55 -080018 *
Austin Schuh745610d2015-09-06 18:19:50 -070019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * ---
32 * Author: David Vitek
33 *
34 * Dump function addresses using Microsoft debug symbols. This works
35 * on PDB files. Note that this program will download symbols to
36 * c:\websymbols without asking.
37 */
38
Brian Silverman20350ac2021-11-17 18:19:55 -080039#ifndef WIN32_LEAN_AND_MEAN
Austin Schuh745610d2015-09-06 18:19:50 -070040#define WIN32_LEAN_AND_MEAN
Brian Silverman20350ac2021-11-17 18:19:55 -080041#endif
42
43#ifndef _CRT_SECURE_NO_WARNINGS
Austin Schuh745610d2015-09-06 18:19:50 -070044#define _CRT_SECURE_NO_WARNINGS
Brian Silverman20350ac2021-11-17 18:19:55 -080045#endif
46
47#ifndef _CRT_SECURE_NO_DEPRECATE
Austin Schuh745610d2015-09-06 18:19:50 -070048#define _CRT_SECURE_NO_DEPRECATE
Brian Silverman20350ac2021-11-17 18:19:55 -080049#endif
Austin Schuh745610d2015-09-06 18:19:50 -070050
51#include <stdio.h>
52#include <stdlib.h>
53
54#include <windows.h>
55#include <dbghelp.h>
56
57#define SEARCH_CAP (1024*1024)
58#define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
59
60void usage() {
Brian Silverman20350ac2021-11-17 18:19:55 -080061 fprintf(stderr, "usage: addr2line-pdb "
62 "[-f|--functions] [-C|--demangle] [-e|--exe filename]\n");
Austin Schuh745610d2015-09-06 18:19:50 -070063 fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n");
64}
65
66int main(int argc, char *argv[]) {
67 DWORD error;
68 HANDLE process;
69 ULONG64 module_base;
70 int i;
71 char* search;
72 char buf[256]; /* Enough to hold one hex address, I trust! */
73 int rv = 0;
74 /* We may add SYMOPT_UNDNAME if --demangle is specified: */
75 DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES;
76 char* filename = "a.out"; /* The default if -e isn't specified */
77 int print_function_name = 0; /* Set to 1 if -f is specified */
78
79 for (i = 1; i < argc; i++) {
80 if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) {
81 print_function_name = 1;
82 } else if (strcmp(argv[i], "--demangle") == 0 ||
83 strcmp(argv[i], "-C") == 0) {
84 symopts |= SYMOPT_UNDNAME;
Brian Silverman20350ac2021-11-17 18:19:55 -080085 } else if (strcmp(argv[i], "--exe") == 0 ||
86 strcmp(argv[i], "-e") == 0) {
Austin Schuh745610d2015-09-06 18:19:50 -070087 if (i + 1 >= argc) {
88 fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n");
89 return 1;
90 }
91 filename = argv[i+1];
92 i++; /* to skip over filename too */
93 } else if (strcmp(argv[i], "--help") == 0) {
94 usage();
95 exit(0);
96 } else {
97 usage();
98 exit(1);
99 }
100 }
101
102 process = GetCurrentProcess();
103
104 if (!SymInitialize(process, NULL, FALSE)) {
105 error = GetLastError();
Brian Silverman20350ac2021-11-17 18:19:55 -0800106 fprintf(stderr, "SymInitialize returned error : %lu\n", error);
Austin Schuh745610d2015-09-06 18:19:50 -0700107 return 1;
108 }
109
110 search = malloc(SEARCH_CAP);
111 if (SymGetSearchPath(process, search, SEARCH_CAP)) {
112 if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) {
113 fprintf(stderr, "Search path too long\n");
114 SymCleanup(process);
115 return 1;
116 }
117 strcat(search, ";" WEBSYM);
118 } else {
119 error = GetLastError();
Brian Silverman20350ac2021-11-17 18:19:55 -0800120 fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error);
Austin Schuh745610d2015-09-06 18:19:50 -0700121 rv = 1; /* An error, but not a fatal one */
122 strcpy(search, WEBSYM); /* Use a default value */
123 }
124 if (!SymSetSearchPath(process, search)) {
125 error = GetLastError();
Brian Silverman20350ac2021-11-17 18:19:55 -0800126 fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error);
Austin Schuh745610d2015-09-06 18:19:50 -0700127 rv = 1; /* An error, but not a fatal one */
128 }
129
130 SymSetOptions(symopts);
131 module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0);
132 if (!module_base) {
133 /* SymLoadModuleEx failed */
134 error = GetLastError();
Brian Silverman20350ac2021-11-17 18:19:55 -0800135 fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n",
Austin Schuh745610d2015-09-06 18:19:50 -0700136 error, filename);
137 SymCleanup(process);
138 return 1;
139 }
140
141 buf[sizeof(buf)-1] = '\0'; /* Just to be safe */
142 while (fgets(buf, sizeof(buf)-1, stdin)) {
143 /* GNU addr2line seems to just do a strtol and ignore any
144 * weird characters it gets, so we will too.
145 */
Brian Silverman20350ac2021-11-17 18:19:55 -0800146 unsigned __int64 reladdr = _strtoui64(buf, NULL, 16);
Austin Schuh745610d2015-09-06 18:19:50 -0700147 ULONG64 buffer[(sizeof(SYMBOL_INFO) +
148 MAX_SYM_NAME*sizeof(TCHAR) +
149 sizeof(ULONG64) - 1)
150 / sizeof(ULONG64)];
Brian Silverman20350ac2021-11-17 18:19:55 -0800151 memset(buffer, 0, sizeof(buffer));
Austin Schuh745610d2015-09-06 18:19:50 -0700152 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
153 IMAGEHLP_LINE64 line;
154 DWORD dummy;
Brian Silverman20350ac2021-11-17 18:19:55 -0800155
156 // Just ignore overflow. In an overflow scenario, the resulting address
157 // will be lower than module_base which hasn't been mapped by any prior
158 // SymLoadModuleEx() command. This will cause SymFromAddr() and
159 // SymGetLineFromAddr64() both to return failures and print the correct
160 // ?? and ??:0 message variant.
161 ULONG64 absaddr = reladdr + module_base;
162
Austin Schuh745610d2015-09-06 18:19:50 -0700163 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
Brian Silverman20350ac2021-11-17 18:19:55 -0800164 // The length of the name is not including the null-terminating character.
165 pSymbol->MaxNameLen = MAX_SYM_NAME - 1;
Austin Schuh745610d2015-09-06 18:19:50 -0700166 if (print_function_name) {
Brian Silverman20350ac2021-11-17 18:19:55 -0800167 if (SymFromAddr(process, (DWORD64)absaddr, NULL, pSymbol)) {
Austin Schuh745610d2015-09-06 18:19:50 -0700168 printf("%s\n", pSymbol->Name);
169 } else {
170 printf("??\n");
171 }
172 }
173 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
Brian Silverman20350ac2021-11-17 18:19:55 -0800174 if (SymGetLineFromAddr64(process, (DWORD64)absaddr, &dummy, &line)) {
Austin Schuh745610d2015-09-06 18:19:50 -0700175 printf("%s:%d\n", line.FileName, (int)line.LineNumber);
176 } else {
177 printf("??:0\n");
178 }
179 }
180 SymUnloadModule64(process, module_base);
181 SymCleanup(process);
182 return rv;
183}