Commit 6a6b5169 authored by scottmg@chromium.org's avatar scottmg@chromium.org

Static initializers tool for Windows

A tool to print out static initializers in the format below.

These static initializers cause problems for some sneakier CRT initialization
tricks we do, and they also were measured to have an appreciable slowdown
on startup time (at least on CrOS) so generally trending towards 0 is
desirable.

The basic approach is looking for symbols that have the magic VS name
`dynamic initializer for ' which is the demangled name that's used for
global C++ initializers. The binary is processed by using the DIA SDK
(some of the code is from the Dia2Dump sample), which means that the
target binary requires being built with symbols for this tool to work.

The intention is that a run of this tool will be hooked into the 'sizes'
step on clobber builders on the waterfall, similar to Linux and Mac.

===
Static initializers in a.exe:
d:\src\cr2\src\tools\win\static-initializers\a.obj: `dynamic initializer for 'std::_Error_objects<int>::_Generic_object''
d:\src\cr2\src\tools\win\static-initializers\a.obj: `dynamic initializer for 'std::_Error_objects<int>::_Iostream_object''
d:\src\cr2\src\tools\win\static-initializers\a.obj: `dynamic initializer for 'std::_Error_objects<int>::_System_object''
d:\src\cr2\src\tools\win\static-initializers\a.obj: `dynamic initializer for 'std::num_put<char,std::back_insert_iterator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >::id''
...
===

See https://code.google.com/p/chromium/issues/detail?id=341941#c7 for logs of those found in Chromium.

R=cpu@chromium.org
BUG=341941

Review URL: https://codereview.chromium.org/66613003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251144 0039d316-1c4b-4281-b951-d872f2087c98
parent 0c48b7d5
......@@ -192,6 +192,7 @@
'../sandbox/sandbox.gyp:*',
'<(angle_path)/src/build_angle.gyp:*',
'../third_party/bspatch/bspatch.gyp:*',
'../tools/win/static_initializers/static_initializers.gyp:*',
],
}, {
'dependencies': [
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <dia2.h>
#include <stdio.h>
#include <string>
// Create an IDiaData source and open a PDB file.
static bool LoadDataFromPdb(const wchar_t* filename,
IDiaDataSource** source,
IDiaSession** session,
IDiaSymbol** global,
DWORD* machine_type) {
// Alternate path to search for debug data.
const wchar_t search_path[] = L"SRV**\\\\symbols\\symbols";
DWORD mach_type = 0;
HRESULT hr = CoInitialize(NULL);
// Obtain access to the provider.
hr = CoCreateInstance(__uuidof(DiaSource),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDiaDataSource),
(void**)source);
if (FAILED(hr)) {
printf("CoCreateInstance failed - HRESULT = %08X\n", hr);
return false;
}
wchar_t ext[MAX_PATH];
_wsplitpath_s(filename, NULL, 0, NULL, 0, NULL, 0, ext, MAX_PATH);
// Open and prepare the debug data associated with the executable.
hr = (*source)->loadDataForExe(filename, search_path, NULL);
if (FAILED(hr)) {
printf("loadDataForExe failed - HRESULT = %08X\n", hr);
return false;
}
// Open a session for querying symbols.
hr = (*source)->openSession(session);
if (FAILED(hr)) {
printf("openSession failed - HRESULT = %08X\n", hr);
return false;
}
// Retrieve a reference to the global scope.
hr = (*session)->get_globalScope(global);
if (FAILED(hr)) {
printf("get_globalScope failed\n");
return false;
}
// Set machine type for getting correct register names.
if (SUCCEEDED((*global)->get_machineType(&mach_type))) {
switch (mach_type) {
case IMAGE_FILE_MACHINE_I386:
*machine_type = CV_CFL_80386;
break;
case IMAGE_FILE_MACHINE_IA64:
*machine_type = CV_CFL_IA64;
break;
case IMAGE_FILE_MACHINE_AMD64:
*machine_type = CV_CFL_AMD64;
break;
default:
printf("unexpected machine type\n");
return false;
}
}
return true;
}
// Release DIA objects and CoUninitialize.
static void Cleanup(IDiaSymbol* global_symbol, IDiaSession* dia_session) {
if (global_symbol)
global_symbol->Release();
if (dia_session)
dia_session->Release();
CoUninitialize();
}
static void PrintIfDynamicInitializer(const std::wstring& module,
IDiaSymbol* symbol) {
DWORD symtag;
if (FAILED(symbol->get_symTag(&symtag)))
return;
if (symtag != SymTagFunction && symtag != SymTagBlock)
return;
BSTR bstr_name;
if (SUCCEEDED(symbol->get_name(&bstr_name))) {
if (wcsstr(bstr_name, L"`dynamic initializer for '")) {
wprintf(L"%s: %s\n", module.c_str(), bstr_name);
SysFreeString(bstr_name);
}
}
}
static bool DumpStaticInitializers(IDiaSymbol* global_symbol) {
// Retrieve the compilands first.
IDiaEnumSymbols* enum_symbols;
if (FAILED(global_symbol->findChildren(
SymTagCompiland, NULL, nsNone, &enum_symbols))) {
return false;
}
IDiaSymbol* compiland;
ULONG element_count = 0;
std::wstring current_module;
while (SUCCEEDED(enum_symbols->Next(1, &compiland, &element_count)) &&
(element_count == 1)) {
BSTR bstr_name;
if (FAILED(compiland->get_name(&bstr_name))) {
current_module = L"<unknown>";
} else {
current_module = bstr_name;
SysFreeString(bstr_name);
}
// Find all the symbols defined in this compiland, and print them if they
// have the name corresponding to an initializer.
IDiaEnumSymbols* enum_children;
if (SUCCEEDED(compiland->findChildren(
SymTagNull, NULL, nsNone, &enum_children))) {
IDiaSymbol* symbol;
ULONG children = 0;
while (SUCCEEDED(enum_children->Next(1, &symbol, &children)) &&
children == 1) { // Enumerate until we don't get any more symbols.
PrintIfDynamicInitializer(current_module, symbol);
symbol->Release();
}
enum_children->Release();
}
compiland->Release();
}
enum_symbols->Release();
return true;
}
int wmain(int argc, wchar_t* argv[]) {
if (argc != 2) {
wprintf(L"usage: %ls binary_name\n", argv[0]);
return 1;
}
IDiaDataSource* dia_data_source;
IDiaSession* dia_session;
IDiaSymbol* global_symbol;
DWORD machine_type = CV_CFL_80386;
if (!LoadDataFromPdb(argv[1],
&dia_data_source,
&dia_session,
&global_symbol,
&machine_type)) {
wprintf(L"Couldn't load data from pdb.\n");
return 1;
}
wprintf(L"Static initializers in %s:\n", argv[1]);
if (!DumpStaticInitializers(global_symbol))
return 1;
Cleanup(global_symbol, dia_session);
return 0;
}
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
{
'variables': {
'chromium_code': 1,
},
'targets': [
{
'target_name': 'static_initializers',
'type': 'executable',
'sources': [
'static_initializers.cc',
],
'include_dirs': [
'$(VSInstallDir)/DIA SDK/include',
],
},
],
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment