Home | History | Annotate | Download | only in static_initializers
      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.
     11 static 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.
     81 static 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 
     89 static 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 
    108 static 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 
    151 int 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