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 |