| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Dump functions called by static intializers in a Linux Release binary. | 6 """Dump functions called by static intializers in a Linux Release binary. |
| 7 | 7 |
| 8 Usage example: | 8 Usage example: |
| 9 tools/linux/dump-static-intializers.py out/Release/chrome | 9 tools/linux/dump-static-intializers.py out/Release/chrome |
| 10 | 10 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 self.cppfilt = subprocess.Popen(['c++filt'], | 40 self.cppfilt = subprocess.Popen(['c++filt'], |
| 41 stdin=subprocess.PIPE, | 41 stdin=subprocess.PIPE, |
| 42 stdout=subprocess.PIPE) | 42 stdout=subprocess.PIPE) |
| 43 | 43 |
| 44 def Demangle(self, sym): | 44 def Demangle(self, sym): |
| 45 """Given mangled symbol |sym|, return its demangled form.""" | 45 """Given mangled symbol |sym|, return its demangled form.""" |
| 46 self.cppfilt.stdin.write(sym + '\n') | 46 self.cppfilt.stdin.write(sym + '\n') |
| 47 return self.cppfilt.stdout.readline().strip() | 47 return self.cppfilt.stdout.readline().strip() |
| 48 | 48 |
| 49 | 49 |
| 50 # Regex matching nm output for the symbols we're interested in. | 50 # Regex matching nm output. |
| 51 # Example line: | 51 # Example bss section symbol: |
| 52 # 0000000001919920 0000000000000008 b _ZN12_GLOBAL__N_119g_nine_box_prelightE | 52 # 0000000004021a20 0000000000000008 b _ZGVZL16GetProcessLocalevE6locale |
| 53 bss_section_re = re.compile(r'\S+ \S+ b (.*)') |
| 54 def GetBSSFromNm(binary): |
| 55 """Given a binary, return a set of symbols from the BSS section.""" |
| 56 bss_section = set() |
| 57 nm = subprocess.Popen(['nm', '-S', binary], stdout=subprocess.PIPE) |
| 58 for line in nm.stdout: |
| 59 match = bss_section_re.match(line) |
| 60 if match: |
| 61 bss_section.add(match.groups()[0]) |
| 62 return bss_section |
| 63 |
| 64 |
| 65 # Regex matching nm output. |
| 66 # Example static initializer section line to yield: |
| 67 # 0000000001919920 0000000000000008 t _ZN12_GLOBAL__I_safe_browsing_service.cc |
| 53 nm_re = re.compile(r'(\S+) (\S+) t _GLOBAL__I_(.*)') | 68 nm_re = re.compile(r'(\S+) (\S+) t _GLOBAL__I_(.*)') |
| 54 def ParseNm(binary): | 69 def GetStaticInitializersFromNm(binary): |
| 55 """Given a binary, yield static initializers as (start, size, file) pairs.""" | 70 """Given a binary, yield static initializers as (start, size, file) pairs.""" |
| 56 | 71 |
| 57 nm = subprocess.Popen(['nm', '-S', binary], stdout=subprocess.PIPE) | 72 nm = subprocess.Popen(['nm', '-S', binary], stdout=subprocess.PIPE) |
| 58 for line in nm.stdout: | 73 for line in nm.stdout: |
| 59 match = nm_re.match(line) | 74 match = nm_re.match(line) |
| 60 if match: | 75 if match: |
| 61 addr, size, filename = match.groups() | 76 addr, size, filename = match.groups() |
| 62 yield int(addr, 16), int(size, 16), filename | 77 yield int(addr, 16), int(size, 16), filename |
| 63 | 78 |
| 64 | 79 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 91 continue | 106 continue |
| 92 | 107 |
| 93 for ref in sorted(refs): | 108 for ref in sorted(refs): |
| 94 yield ref | 109 yield ref |
| 95 | 110 |
| 96 | 111 |
| 97 def main(): | 112 def main(): |
| 98 parser = optparse.OptionParser(usage='%prog filename') | 113 parser = optparse.OptionParser(usage='%prog filename') |
| 99 parser.add_option('-i', '--instances', dest='calculate_instances', | 114 parser.add_option('-i', '--instances', dest='calculate_instances', |
| 100 action='store_true', default=False, | 115 action='store_true', default=False, |
| 101 help='Only print out the number of static initializers') | 116 help='Only print out the number of files with ' |
| 117 'static initializers') |
| 118 parser.add_option('-I', '--show-instances', dest='show_instances', |
| 119 action='store_true', default=False, |
| 120 help='Only print out the static initializers without' |
| 121 'references') |
| 102 opts, args = parser.parse_args() | 122 opts, args = parser.parse_args() |
| 103 if len(args) != 1: | 123 if len(args) != 1: |
| 104 parser.error('missing filename argument') | 124 parser.error('missing filename argument') |
| 105 return 1 | 125 return 1 |
| 126 if opts.calculate_instances and opts.show_instances: |
| 127 parser.error('-i and -I are mutually exclusive') |
| 128 return 1 |
| 106 binary = args[0] | 129 binary = args[0] |
| 107 | 130 |
| 108 demangler = Demangler() | 131 demangler = Demangler() |
| 109 static_initializers_count = 0 | 132 static_initializers_count = 0 |
| 110 for addr, size, filename in ParseNm(binary): | 133 if opts.calculate_instances or opts.show_instances: |
| 134 bss_section = GetBSSFromNm(binary) |
| 135 |
| 136 for addr, size, filename in GetStaticInitializersFromNm(binary): |
| 111 if size == 2: | 137 if size == 2: |
| 112 # gcc generates a two-byte 'repz retq' initializer when there is nothing | 138 # gcc generates a two-byte 'repz retq' initializer when there is nothing |
| 113 # to do. jyasskin tells me this is fixed in gcc 4.6. | 139 # to do. jyasskin tells me this is fixed in gcc 4.6. |
| 114 # Two bytes is too small to do anything, so just ignore it. | 140 # Two bytes is too small to do anything, so just ignore it. |
| 115 continue | 141 continue |
| 116 | 142 |
| 117 if (opts.calculate_instances): | 143 if opts.calculate_instances: |
| 118 static_initializers_count += 1 | 144 for ref in ExtractSymbolReferences(binary, addr, addr+size): |
| 119 continue | 145 if ref in bss_section: |
| 120 | 146 static_initializers_count += 1 |
| 121 print '%s (initializer offset 0x%x size 0x%x)' % (filename, addr, size) | 147 else: |
| 122 for ref in ExtractSymbolReferences(binary, addr, addr+size): | 148 print '%s (initializer offset 0x%x size 0x%x)' % (filename, addr, size) |
| 123 ref = demangler.Demangle(ref) | 149 for ref in ExtractSymbolReferences(binary, addr, addr+size): |
| 124 if ref in NOTES: | 150 if opts.show_instances and ref not in bss_section: |
| 125 print ' ', '%s [%s]' % (ref, NOTES[ref]) | 151 continue |
| 126 else: | 152 ref = demangler.Demangle(ref) |
| 127 print ' ', ref | 153 if ref in NOTES: |
| 128 print | 154 print ' ', '%s [%s]' % (ref, NOTES[ref]) |
| 155 else: |
| 156 print ' ', ref |
| 157 print |
| 129 | 158 |
| 130 if opts.calculate_instances: | 159 if opts.calculate_instances: |
| 131 print static_initializers_count | 160 print static_initializers_count |
| 161 |
| 132 return 0 | 162 return 0 |
| 133 | 163 |
| 134 | 164 |
| 135 if '__main__' == __name__: | 165 if '__main__' == __name__: |
| 136 sys.exit(main()) | 166 sys.exit(main()) |
| OLD | NEW |