Home | History | Annotate | Download | only in windows
      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