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) |
79 offset_to_symbol_infos[symbol.offset].append(symbol) | 62 offset_to_symbol_infos[symbol.offset].append(symbol) |
80 name_to_symbol_infos[symbol.name].append(symbol) | 63 name_to_symbol_infos[symbol.name].append(symbol) |
81 return (offset_to_symbol_infos, name_to_symbol_infos) | 64 return (dict(offset_to_symbol_infos), dict(name_to_symbol_infos)) |
82 | 65 |
83 | 66 |
84 def _GetSymbolInfosFromBinary(binary_filename): | 67 def _GroupSymbolInfosFromBinary(binary_filename): |
85 """Runs nm to get all the symbols from a binary. | 68 """Group all the symbols from a binary by name and offset. |
86 | 69 |
87 Args: | 70 Args: |
88 binary_filename: path to the binary. | 71 binary_filename: path to the binary. |
89 | 72 |
90 Returns: | 73 Returns: |
91 A tuple of collection.defaultdict: | 74 A tuple of dict: |
92 (offset_to_symbol_infos, name_to_symbol_infos): | 75 (offset_to_symbol_infos, name_to_symbol_infos): |
93 - offset_to_symbol_infos: {offset: [symbol_info1, ...]} | 76 - offset_to_symbol_infos: {offset: [symbol_info1, ...]} |
94 - name_to_symbol_infos: {name: [symbol_info1, ...]} | 77 - name_to_symbol_infos: {name: [symbol_info1, ...]} |
95 """ | 78 """ |
96 command = 'nm -S -n %s | egrep "( t )|( W )|( T )"' % binary_filename | 79 symbol_infos = symbol_extractor.SymbolInfosFromBinary(binary_filename) |
97 p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) | 80 return _GroupSymbolInfos(symbol_infos) |
98 try: | |
99 result = _GetSymbolInfosFromStream(p.stdout) | |
100 return result | |
101 finally: | |
102 p.wait() | |
103 | 81 |
104 | 82 |
105 def _StripPrefix(line): | 83 def _StripPrefix(line): |
106 """Get the symbol from a line with a linker section name. | 84 """Get the symbol from a line with a linker section name. |
107 | 85 |
108 Args: | 86 Args: |
109 line: a line from an orderfile, usually in the form: | 87 line: a line from an orderfile, usually in the form: |
110 .text.SymbolName | 88 .text.SymbolName |
111 | 89 |
112 Returns: | 90 Returns: |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 output_file.write(linker_section + '\n') | 201 output_file.write(linker_section + '\n') |
224 unique_outputs.add(linker_section) | 202 unique_outputs.add(linker_section) |
225 | 203 |
226 | 204 |
227 def main(argv): | 205 def main(argv): |
228 if len(argv) != 3: | 206 if len(argv) != 3: |
229 print 'Usage: %s <unpatched_orderfile> <libchrome.so>' % argv[0] | 207 print 'Usage: %s <unpatched_orderfile> <libchrome.so>' % argv[0] |
230 return 1 | 208 return 1 |
231 orderfile_filename = argv[1] | 209 orderfile_filename = argv[1] |
232 binary_filename = argv[2] | 210 binary_filename = argv[2] |
233 (offset_to_symbol_infos, name_to_symbol_infos) = _GetSymbolInfosFromBinary( | 211 (offset_to_symbol_infos, name_to_symbol_infos) = _GroupSymbolInfosFromBinary( |
234 binary_filename) | 212 binary_filename) |
235 profiled_symbols = _GetSymbolsFromOrderfile(orderfile_filename) | 213 profiled_symbols = _GetSymbolsFromOrderfile(orderfile_filename) |
236 expanded_symbols = _ExpandSymbols( | 214 expanded_symbols = _ExpandSymbols( |
237 profiled_symbols, name_to_symbol_infos, offset_to_symbol_infos) | 215 profiled_symbols, name_to_symbol_infos, offset_to_symbol_infos) |
238 _PrintSymbolsWithPrefixes(expanded_symbols, sys.stdout) | 216 _PrintSymbolsWithPrefixes(expanded_symbols, sys.stdout) |
239 # The following is needed otherwise Gold only applies a partial sort. | 217 # The following is needed otherwise Gold only applies a partial sort. |
240 print '.text' # gets methods not in a section, such as assembly | 218 print '.text' # gets methods not in a section, such as assembly |
241 print '.text.*' # gets everything else | 219 print '.text.*' # gets everything else |
242 return 0 | 220 return 0 |
243 | 221 |
244 | 222 |
245 if __name__ == '__main__': | 223 if __name__ == '__main__': |
246 logging.basicConfig(level=logging.INFO) | 224 logging.basicConfig(level=logging.INFO) |
247 sys.exit(main(sys.argv)) | 225 sys.exit(main(sys.argv)) |
OLD | NEW |