summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-06 22:51:01 +0000
committerevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-06 22:51:01 +0000
commitcf4cc26dcda805ab251e90fd852bfd7d7ddd298d (patch)
treeab028a366234ffb983478e7f6b311058637009f6 /tools
parent19d963f72826c669179b9fa2c9c11ad40465a701 (diff)
downloadchromium_src-cf4cc26dcda805ab251e90fd852bfd7d7ddd298d.zip
chromium_src-cf4cc26dcda805ab251e90fd852bfd7d7ddd298d.tar.gz
chromium_src-cf4cc26dcda805ab251e90fd852bfd7d7ddd298d.tar.bz2
Check in a tool to dump static initializers from a binary
BUG=94925 Review URL: http://codereview.chromium.org/7837013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99852 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rwxr-xr-xtools/linux/dump-static-initializers.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/tools/linux/dump-static-initializers.py b/tools/linux/dump-static-initializers.py
new file mode 100755
index 0000000..959c53d
--- /dev/null
+++ b/tools/linux/dump-static-initializers.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+# Copyright (c) 2011 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.
+
+"""Dump functions called by static intializers in a Linux Release binary.
+
+Usage example:
+ tools/linux/dump-static-intializers.py out/Release/chrome
+
+A brief overview of static initialization:
+1) the compiler writes out, per object file, a function that contains
+ the static intializers for that file.
+2) the compiler also writes out a pointer to that function in a special
+ section.
+3) at link time, the linker concatenates the function pointer sections
+ into a single list of all initializers.
+4) at run time, on startup the binary runs all function pointers.
+
+The functions in (1) all have mangled names of the form
+ _GLOBAL__I_foobar.cc
+using objdump, we can disassemble those functions and dump all symbols that
+they reference.
+"""
+
+import re
+import subprocess
+import sys
+
+# A map of symbol => informative text about it.
+NOTES = {
+ '__cxa_atexit@plt': 'registers a dtor to run at exit',
+ 'std::__ioinit': '#includes <iostream>, use <ostream> instead',
+}
+
+class Demangler(object):
+ """A wrapper around c++filt to provide a function to demangle symbols."""
+ def __init__(self):
+ self.cppfilt = subprocess.Popen(['c++filt'],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+
+ def Demangle(self, sym):
+ """Given mangled symbol |sym|, return its demangled form."""
+ self.cppfilt.stdin.write(sym + '\n')
+ return self.cppfilt.stdout.readline().strip()
+
+
+# Regex matching nm output for the symbols we're interested in.
+# Example line:
+# 0000000001919920 0000000000000008 b _ZN12_GLOBAL__N_119g_nine_box_prelightE
+nm_re = re.compile(r'(\S+) (\S+) t _GLOBAL__I_(.*)')
+def ParseNm(binary):
+ """Given a binary, yield static initializers as (start, size, file) pairs."""
+
+ nm = subprocess.Popen(['nm', '-S', binary], stdout=subprocess.PIPE)
+ for line in nm.stdout:
+ match = nm_re.match(line)
+ if match:
+ addr, size, filename = match.groups()
+ yield int(addr, 16), int(size, 16), filename
+
+
+# Regex matching objdump output for the symbols we're interested in.
+# Example line:
+# 12354ab: (disassembly, including <FunctionReference>)
+disassembly_re = re.compile(r'^\s+[0-9a-f]+:.*<(\S+)>')
+def ExtractSymbolReferences(binary, start, end):
+ """Given a span of addresses, yields symbol references from disassembly."""
+ cmd = ['objdump', binary, '--disassemble',
+ '--start-address=0x%x' % start, '--stop-address=0x%x' % end]
+ objdump = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+
+ refs = set()
+ for line in objdump.stdout:
+ match = disassembly_re.search(line)
+ if match:
+ (ref,) = match.groups()
+ if ref.startswith('.LC') or ref.startswith('_DYNAMIC'):
+ # Ignore these, they are uninformative.
+ continue
+ if ref.startswith('_GLOBAL__I_'):
+ # Probably a relative jump within this function.
+ continue
+ refs.add(ref)
+ continue
+ if '__static_initialization_and_destruction' in line:
+ raise RuntimeError, ('code mentions '
+ '__static_initialization_and_destruction; '
+ 'did you accidentally use a Debug binary?')
+
+ for ref in sorted(refs):
+ yield ref
+
+
+(binary,) = sys.argv[1:]
+demangler = Demangler()
+for addr, size, filename in ParseNm(binary):
+ if size == 2:
+ # gcc generates a two-byte 'repz retq' initializer when there is nothing
+ # to do. jyasskin tells me this is fixed in gcc 4.6.
+ # Two bytes is too small to do anything, so just ignore it.
+ continue
+
+ print '%s (0x%x 0x%x)' % (filename, addr, addr+size)
+ for ref in ExtractSymbolReferences(binary, addr, addr+size):
+ ref = demangler.Demangle(ref)
+ if ref in NOTES:
+ print ' ', '%s [%s]' % (ref, NOTES[ref])
+ else:
+ print ' ', ref
+ print
+