1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <dia2.h> 6#include <stdio.h> 7 8#include <string> 9 10// Create an IDiaData source and open a PDB file. 11static bool LoadDataFromPdb(const wchar_t* filename, 12 IDiaDataSource** source, 13 IDiaSession** session, 14 IDiaSymbol** global, 15 DWORD* machine_type) { 16 // Alternate path to search for debug data. 17 const wchar_t search_path[] = L"SRV**\\\\symbols\\symbols"; 18 DWORD mach_type = 0; 19 HRESULT hr = CoInitialize(NULL); 20 21 // Obtain access to the provider. 22 hr = CoCreateInstance(__uuidof(DiaSource), 23 NULL, 24 CLSCTX_INPROC_SERVER, 25 __uuidof(IDiaDataSource), 26 (void**)source); 27 28 if (FAILED(hr)) { 29 printf("CoCreateInstance failed - HRESULT = %08lX\n", hr); 30 return false; 31 } 32 33 wchar_t ext[MAX_PATH]; 34 _wsplitpath_s(filename, NULL, 0, NULL, 0, NULL, 0, ext, MAX_PATH); 35 36 // Open and prepare the debug data associated with the executable. 37 hr = (*source)->loadDataForExe(filename, search_path, NULL); 38 if (FAILED(hr)) { 39 printf("loadDataForExe failed - HRESULT = %08lX\n", hr); 40 return false; 41 } 42 43 // Open a session for querying symbols. 44 hr = (*source)->openSession(session); 45 46 if (FAILED(hr)) { 47 printf("openSession failed - HRESULT = %08lX\n", hr); 48 return false; 49 } 50 51 // Retrieve a reference to the global scope. 52 hr = (*session)->get_globalScope(global); 53 54 if (FAILED(hr)) { 55 printf("get_globalScope failed\n"); 56 return false; 57 } 58 59 // Set machine type for getting correct register names. 60 if (SUCCEEDED((*global)->get_machineType(&mach_type))) { 61 switch (mach_type) { 62 case IMAGE_FILE_MACHINE_I386: 63 *machine_type = CV_CFL_80386; 64 break; 65 case IMAGE_FILE_MACHINE_IA64: 66 *machine_type = CV_CFL_IA64; 67 break; 68 case IMAGE_FILE_MACHINE_AMD64: 69 *machine_type = CV_CFL_AMD64; 70 break; 71 default: 72 printf("unexpected machine type\n"); 73 return false; 74 } 75 } 76 77 return true; 78} 79 80// Release DIA objects and CoUninitialize. 81static void Cleanup(IDiaSymbol* global_symbol, IDiaSession* dia_session) { 82 if (global_symbol) 83 global_symbol->Release(); 84 if (dia_session) 85 dia_session->Release(); 86 CoUninitialize(); 87} 88 89static void PrintIfDynamicInitializer(const std::wstring& module, 90 IDiaSymbol* symbol) { 91 DWORD symtag; 92 93 if (FAILED(symbol->get_symTag(&symtag))) 94 return; 95 96 if (symtag != SymTagFunction && symtag != SymTagBlock) 97 return; 98 99 BSTR bstr_name; 100 if (SUCCEEDED(symbol->get_name(&bstr_name))) { 101 if (wcsstr(bstr_name, L"`dynamic initializer for '")) { 102 wprintf(L"%s: %s\n", module.c_str(), bstr_name); 103 SysFreeString(bstr_name); 104 } 105 } 106} 107 108static bool DumpStaticInitializers(IDiaSymbol* global_symbol) { 109 // Retrieve the compilands first. 110 IDiaEnumSymbols* enum_symbols; 111 if (FAILED(global_symbol->findChildren( 112 SymTagCompiland, NULL, nsNone, &enum_symbols))) { 113 return false; 114 } 115 116 IDiaSymbol* compiland; 117 ULONG element_count = 0; 118 119 std::wstring current_module; 120 while (SUCCEEDED(enum_symbols->Next(1, &compiland, &element_count)) && 121 (element_count == 1)) { 122 BSTR bstr_name; 123 if (FAILED(compiland->get_name(&bstr_name))) { 124 current_module = L"<unknown>"; 125 } else { 126 current_module = bstr_name; 127 SysFreeString(bstr_name); 128 } 129 130 // Find all the symbols defined in this compiland, and print them if they 131 // have the name corresponding to an initializer. 132 IDiaEnumSymbols* enum_children; 133 if (SUCCEEDED(compiland->findChildren( 134 SymTagNull, NULL, nsNone, &enum_children))) { 135 IDiaSymbol* symbol; 136 ULONG children = 0; 137 while (SUCCEEDED(enum_children->Next(1, &symbol, &children)) && 138 children == 1) { // Enumerate until we don't get any more symbols. 139 PrintIfDynamicInitializer(current_module, symbol); 140 symbol->Release(); 141 } 142 enum_children->Release(); 143 } 144 compiland->Release(); 145 } 146 147 enum_symbols->Release(); 148 return true; 149} 150 151int wmain(int argc, wchar_t* argv[]) { 152 if (argc != 2) { 153 wprintf(L"usage: %ls binary_name\n", argv[0]); 154 return 1; 155 } 156 157 IDiaDataSource* dia_data_source; 158 IDiaSession* dia_session; 159 IDiaSymbol* global_symbol; 160 DWORD machine_type = CV_CFL_80386; 161 if (!LoadDataFromPdb(argv[1], 162 &dia_data_source, 163 &dia_session, 164 &global_symbol, 165 &machine_type)) { 166 wprintf(L"Couldn't load data from pdb.\n"); 167 return 1; 168 } 169 170 wprintf(L"Static initializers in %s:\n", argv[1]); 171 172 if (!DumpStaticInitializers(global_symbol)) 173 return 1; 174 175 Cleanup(global_symbol, dia_session); 176 177 return 0; 178} 179