OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 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 """Patch an orderfile. | 6 """Patch an orderfile. |
7 | 7 |
8 Starting with a list of symbols in a binary and an orderfile (ordered list of | 8 Starting with a list of symbols in a binary and an orderfile (ordered list of |
9 symbols), matches the symbols in the orderfile and augments each symbol with the | 9 symbols), matches the symbols in the orderfile and augments each symbol with the |
10 symbols residing at the same address (due to having identical code). | 10 symbols residing at the same address (due to having identical code). |
11 | 11 |
12 Note: It is possible to have. | 12 Note: It is possible to have. |
13 - Several symbols mapping to the same offset in the binary. | 13 - Several symbols mapping to the same offset in the binary. |
14 - Several offsets for a given symbol (because we strip the ".clone." suffix) | 14 - Several offsets for a given symbol (because we strip the ".clone." suffix) |
15 | 15 |
16 TODO(lizeb): Since the suffix ".clone." is only used with -O3 that we don't | 16 TODO(lizeb): Since the suffix ".clone." is only used with -O3 that we don't |
17 currently use, simplify the logic by removing the suffix handling. | 17 currently use, simplify the logic by removing the suffix handling. |
18 | 18 |
19 The general pipeline is: | 19 The general pipeline is: |
20 1. Get the symbol infos (offset, length, name) from the binary | 20 1. Get the symbol infos (offset, length, name) from the binary |
21 2. Get the symbol names from the orderfile | 21 2. Get the symbol names from the orderfile |
22 3. Find the orderfile symbol names in the symbols coming from the binary | 22 3. Find the orderfile symbol names in the symbols coming from the binary |
23 4. For each symbol found, get all the symbols at the same address | 23 4. For each symbol found, get all the symbols at the same address |
24 5. Output them to an updated orderfile, with several different prefixes | 24 5. Output them to an updated orderfile, with several different prefixes |
25 """ | 25 """ |
26 | 26 |
27 import collections | 27 import collections |
28 import logging | 28 import logging |
29 import subprocess | |
30 import sys | 29 import sys |
31 | 30 |
| 31 import symbol_extractor |
| 32 |
32 # Prefixes for the symbols. We strip them from the incoming symbols, and add | 33 # Prefixes for the symbols. We strip them from the incoming symbols, and add |
33 # them back in the output file. | 34 # them back in the output file. |
34 _PREFIXES = ('.text.startup.', '.text.hot.', '.text.unlikely.', '.text.') | 35 _PREFIXES = ('.text.startup.', '.text.hot.', '.text.unlikely.', '.text.') |
35 | 36 |
36 | 37 |
37 SymbolInfo = collections.namedtuple('SymbolInfo', ['offset', 'size', 'name']) | |
38 | |
39 | |
40 def _RemoveClone(name): | 38 def _RemoveClone(name): |
41 """Return name up to the ".clone." marker.""" | 39 """Return name up to the ".clone." marker.""" |
42 clone_index = name.find('.clone.') | 40 clone_index = name.find('.clone.') |
43 if clone_index != -1: | 41 if clone_index != -1: |
44 return name[:clone_index] | 42 return name[:clone_index] |
45 return name | 43 return name |
46 | 44 |
47 | 45 |
48 def _GetSymbolInfosFromStream(nm_lines): | 46 def _GroupSymbolInfos(symbol_infos): |
49 """Parses the output of nm, and get all the symbols from a binary. | 47 """Group the symbol infos by name and offset. |
50 | 48 |
51 Args: | 49 Args: |
52 nm_lines: An iterable of lines | 50 symbol_infos: an iterable of SymbolInfo |
53 | 51 |
54 Returns: | 52 Returns: |
55 The same output as GetSymbolsFromBinary. | 53 The same output as _GroupSymbolInfosFromBinary. |
56 """ | 54 """ |
57 # TODO(lizeb): Consider switching to objdump to simplify parsing. | |
58 symbol_infos = [] | |
59 for line in nm_lines: | |
60 # We are interested in two types of lines: | |
61 # This: | |
62 # 00210d59 00000002 t _ZN34BrowserPluginHostMsg_Attach_ParamsD2Ev | |
63 # offset size <symbol_type> symbol_name | |
64 # And that: | |
65 # 0070ee8c T WebRtcSpl_ComplexBitReverse | |
66 # In the second case we don't have a size, so use -1 as a sentinel | |
67 parts = line.split() | |
68 if len(parts) == 4: | |
69 symbol_infos.append(SymbolInfo( | |
70 offset=int(parts[0], 16), size=int(parts[1], 16), name=parts[3])) | |
71 elif len(parts) == 3: | |
72 symbol_infos.append(SymbolInfo( | |
73 offset=int(parts[0], 16), size=-1, name=parts[2])) | |
74 # Map the addresses to symbols. | 55 # Map the addresses to symbols. |
75 offset_to_symbol_infos = collections.defaultdict(list) | 56 offset_to_symbol_infos = collections.defaultdict(list) |
76 name_to_symbol_infos = collections.defaultdict(list) | 57 name_to_symbol_infos = collections.defaultdict(list) |
77 for symbol in symbol_infos: | 58 for symbol in symbol_infos: |
78 symbol = SymbolInfo(symbol[0], symbol[1], _RemoveClone(symbol[2])) | 59 symbol = symbol_extractor.SymbolInfo(name=_RemoveClone(symbol.name), |
| 60 offset=symbol.offset, |
| 61 size=symbol.size, |
| 62 section=symbol.section) |
79 offset_to_symbol_infos[symbol.offset].append(symbol) | 63 offset_to_symbol_infos[symbol.offset].append(symbol) |
80 name_to_symbol_infos[symbol.name].append(symbol) | 64 name_to_symbol_infos[symbol.name].append(symbol) |
81 return (offset_to_symbol_infos, name_to_symbol_infos) | 65 return (dict(offset_to_symbol_infos), dict(name_to_symbol_infos)) |
82 | 66 |
83 | 67 |
84 def _GetSymbolInfosFromBinary(binary_filename): | 68 def _GroupSymbolInfosFromBinary(binary_filename): |
85 """Runs nm to get all the symbols from a binary. | 69 """Group all the symbols from a binary by name and offset. |
86 | 70 |
87 Args: | 71 Args: |
88 binary_filename: path to the binary. | 72 binary_filename: path to the binary. |
89 | 73 |
90 Returns: | 74 Returns: |
91 A tuple of collection.defaultdict: | 75 A tuple of dict: |
92 (offset_to_symbol_infos, name_to_symbol_infos): | 76 (offset_to_symbol_infos, name_to_symbol_infos): |
93 - offset_to_symbol_infos: {offset: [symbol_info1, ...]} | 77 - offset_to_symbol_infos: {offset: [symbol_info1, ...]} |
94 - name_to_symbol_infos: {name: [symbol_info1, ...]} | 78 - name_to_symbol_infos: {name: [symbol_info1, ...]} |
95 """ | 79 """ |
96 command = 'nm -S -n %s | egrep "( t )|( W )|( T )"' % binary_filename | 80 symbol_infos = symbol_extractor.SymbolInfosFromBinary(binary_filename) |
97 p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) | 81 return _GroupSymbolInfos(symbol_infos) |
98 try: | |
99 result = _GetSymbolInfosFromStream(p.stdout) | |
100 return result | |
101 finally: | |
102 p.wait() | |
103 | 82 |
104 | 83 |
105 def _StripPrefix(line): | 84 def _StripPrefix(line): |
106 """Get the symbol from a line with a linker section name. | 85 """Get the symbol from a line with a linker section name. |
107 | 86 |
108 Args: | 87 Args: |
109 line: a line from an orderfile, usually in the form: | 88 line: a line from an orderfile, usually in the form: |
110 .text.SymbolName | 89 .text.SymbolName |
111 | 90 |
112 Returns: | 91 Returns: |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 output_file.write(linker_section + '\n') | 202 output_file.write(linker_section + '\n') |
224 unique_outputs.add(linker_section) | 203 unique_outputs.add(linker_section) |
225 | 204 |
226 | 205 |
227 def main(argv): | 206 def main(argv): |
228 if len(argv) != 3: | 207 if len(argv) != 3: |
229 print 'Usage: %s <unpatched_orderfile> <libchrome.so>' % argv[0] | 208 print 'Usage: %s <unpatched_orderfile> <libchrome.so>' % argv[0] |
230 return 1 | 209 return 1 |
231 orderfile_filename = argv[1] | 210 orderfile_filename = argv[1] |
232 binary_filename = argv[2] | 211 binary_filename = argv[2] |
233 (offset_to_symbol_infos, name_to_symbol_infos) = _GetSymbolInfosFromBinary( | 212 (offset_to_symbol_infos, name_to_symbol_infos) = _GroupSymbolInfosFromBinary( |
234 binary_filename) | 213 binary_filename) |
235 profiled_symbols = _GetSymbolsFromOrderfile(orderfile_filename) | 214 profiled_symbols = _GetSymbolsFromOrderfile(orderfile_filename) |
236 expanded_symbols = _ExpandSymbols( | 215 expanded_symbols = _ExpandSymbols( |
237 profiled_symbols, name_to_symbol_infos, offset_to_symbol_infos) | 216 profiled_symbols, name_to_symbol_infos, offset_to_symbol_infos) |
238 _PrintSymbolsWithPrefixes(expanded_symbols, sys.stdout) | 217 _PrintSymbolsWithPrefixes(expanded_symbols, sys.stdout) |
239 # The following is needed otherwise Gold only applies a partial sort. | 218 # The following is needed otherwise Gold only applies a partial sort. |
240 print '.text' # gets methods not in a section, such as assembly | 219 print '.text' # gets methods not in a section, such as assembly |
241 print '.text.*' # gets everything else | 220 print '.text.*' # gets everything else |
242 return 0 | 221 return 0 |
243 | 222 |
244 | 223 |
245 if __name__ == '__main__': | 224 if __name__ == '__main__': |
246 logging.basicConfig(level=logging.INFO) | 225 logging.basicConfig(level=logging.INFO) |
247 sys.exit(main(sys.argv)) | 226 sys.exit(main(sys.argv)) |
OLD | NEW |