15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2008, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: David Vitek
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Dump function addresses using Microsoft debug symbols.  This works
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * on PDB files.  Note that this program will download symbols to
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * c:\websymbols without asking.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define WIN32_LEAN_AND_MEAN
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _CRT_SECURE_NO_WARNINGS
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _CRT_SECURE_NO_DEPRECATE
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>   // for _strdup
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dbghelp.h>
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Unfortunately, there is no versioning info in dbghelp.h so I can
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// tell whether it has an old-style (circa VC7.1) IMAGEHLP_MODULE64
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// struct, with only a few fields, or a new-style (circa VC8)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IMAGEHLP_MODULE64, with lots of fields.  These fields are just used
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for debugging, so it's fine to just assume the smaller struct, but
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for most people, using a modern MSVC, the full struct is available.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If you are one of those people and would like this extra debugging
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// info, you can uncomment the line below.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//#define VC8_OR_ABOVE
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SEARCH_CAP (1024*1024)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *name;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG64 addr;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG flags;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} SYM;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG64 module_base;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SYM *syms;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD syms_len;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD syms_cap;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} SYM_CONTEXT;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int sym_cmp(const void *_s1, const void *_s2) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SYM *s1 = (const SYM *)_s1;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SYM *s2 = (const SYM *)_s2;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (s1->addr < s2->addr)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (s1->addr > s2->addr)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO symbol_info,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 ULONG symbol_size,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 PVOID user_context) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SYM_CONTEXT *ctx = (SYM_CONTEXT*)user_context;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (symbol_info->Address < ctx->module_base ||
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (symbol_info->Flags & SYMFLAG_TLSREL)) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TRUE;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ctx->syms_len == ctx->syms_cap) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ctx->syms_cap)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ctx->syms_cap++;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ctx->syms_cap *= 2;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ctx->syms = realloc(ctx->syms, sizeof(ctx->syms[0]) * ctx->syms_cap);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ctx->syms[ctx->syms_len].name = _strdup(symbol_info->Name);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ctx->syms[ctx->syms_len].addr = symbol_info->Address;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ctx->syms[ctx->syms_len].flags = symbol_info->Flags;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ctx->syms_len++;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void MaybePrint(const char* var, const char* description) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (var[0])
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("%s: %s\n", description, var);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void PrintAvailability(BOOL var, const char *description) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("s: %s\n", description, (var ? "Available" : "Not available"));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ShowSymbolInfo(HANDLE process, ULONG64 module_base) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Get module information. */
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IMAGEHLP_MODULE64 module_info;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL getmoduleinfo_rv;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Load Address: %I64x\n", module_base);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&module_info, 0, sizeof(module_info));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  module_info.SizeOfStruct = sizeof(module_info);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getmoduleinfo_rv = SymGetModuleInfo64(process, module_base, &module_info);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!getmoduleinfo_rv)  {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("Error: SymGetModuleInfo64() failed. Error code: %u\n",
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           GetLastError());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Display information about symbols, based on kind of symbol. */
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (module_info.SymType)  {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymNone:
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("No symbols available for the module.\n"));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymExport:
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: Exports\n"));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymCoff:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: COFF\n"));
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymCv:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: CodeView\n"));
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymSym:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: SYM\n"));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymVirtual:
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: Virtual\n"));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymPdb:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: PDB\n"));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymDia:
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: DIA\n"));
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SymDeferred:
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: Deferred\n"));  /* not actually loaded */
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf(("Loaded symbols: Unknown format.\n"));
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybePrint("Image name", module_info.ImageName);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybePrint("Loaded image name", module_info.LoadedImageName);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef VC8_OR_ABOVE   /* TODO(csilvers): figure out how to tell */
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybePrint("PDB file name", module_info.LoadedPdbName);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (module_info.PdbUnmatched || module_info.DbgUnmatched)  {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* This can only happen if the debug information is contained in a
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * separate file (.DBG or .PDB)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf(("Warning: Unmatched symbols.\n"));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Contents */
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef VC8_OR_ABOVE   /* TODO(csilvers): figure out how to tell */
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrintAvailability("Line numbers", module_info.LineNumbers);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrintAvailability("Global symbols", module_info.GlobalSymbols);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrintAvailability("Type information", module_info.TypeInfo);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char *argv[]) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD  error;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE process;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG64 module_base;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SYM_CONTEXT ctx;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* search;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* filename = NULL;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = 0;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* We may add SYMOPT_UNDNAME if --demangle is specified: */
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 1; i < argc; i++) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      symopts |= SYMOPT_UNDNAME;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i != argc - 1) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "usage: nm-pdb [-C|--demangle] <module or filename>\n");
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exit(1);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filename = argv[i];
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  process = GetCurrentProcess();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SymInitialize(process, NULL, FALSE)) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error = GetLastError();
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "SymInitialize returned error : %d\n", error);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search = malloc(SEARCH_CAP);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SymGetSearchPath(process, search, SEARCH_CAP)) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fprintf(stderr, "Search path too long\n");
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SymCleanup(process);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strcat(search, ";" WEBSYM);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error = GetLastError();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "SymGetSearchPath returned error : %d\n", error);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = 1;                   /* An error, but not a fatal one */
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strcpy(search, WEBSYM);   /* Use a default value */
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SymSetSearchPath(process, search)) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error = GetLastError();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "SymSetSearchPath returned error : %d\n", error);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = 1;                   /* An error, but not a fatal one */
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SymSetOptions(symopts);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!module_base) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* SymLoadModuleEx failed */
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error = GetLastError();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n",
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            error, filename);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SymCleanup(process);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShowSymbolInfo(process, module_base);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&ctx, 0, sizeof(ctx));
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ctx.module_base = module_base;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SymEnumSymbols(process, module_base, NULL, EnumSymProc, &ctx)) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error = GetLastError();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "SymEnumSymbols returned error: %d\n", error);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = 1;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD j;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    qsort(ctx.syms, ctx.syms_len, sizeof(ctx.syms[0]), sym_cmp);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (j = 0; j < ctx.syms_len; j++) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf("%016I64x X %s\n", ctx.syms[j].addr, ctx.syms[j].name);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* In a perfect world, maybe we'd clean up ctx's memory? */
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SymUnloadModule64(process, module_base);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SymCleanup(process);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
267