OLD | NEW |
1 # Copyright 2017 The Chromium Authors. All rights reserved. | 1 # Copyright 2017 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Main Python API for analyzing binary size.""" | 5 """Main Python API for analyzing binary size.""" |
6 | 6 |
7 import argparse | 7 import argparse |
8 import calendar | 8 import calendar |
9 import collections | 9 import collections |
10 import datetime | 10 import datetime |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 """ | 85 """ |
86 found_prefixes = set() | 86 found_prefixes = set() |
87 for symbol in raw_symbols: | 87 for symbol in raw_symbols: |
88 if symbol.full_name.startswith('*'): | 88 if symbol.full_name.startswith('*'): |
89 # See comment in _CalculatePadding() about when this | 89 # See comment in _CalculatePadding() about when this |
90 # can happen. | 90 # can happen. |
91 symbol.template_name = symbol.full_name | 91 symbol.template_name = symbol.full_name |
92 symbol.name = symbol.full_name | 92 symbol.name = symbol.full_name |
93 continue | 93 continue |
94 | 94 |
| 95 # Remove [clone] suffix, and set flag accordingly. |
| 96 # Search from left-to-right, as multiple [clone]s can exist. |
| 97 # Example name suffixes: |
| 98 # [clone .part.322] # GCC |
| 99 # [clone .isra.322] # GCC |
| 100 # [clone .constprop.1064] # GCC |
| 101 # [clone .11064] # clang |
| 102 # http://unix.stackexchange.com/questions/223013/function-symbol-gets-part-s
uffix-after-compilation |
| 103 idx = symbol.full_name.find(' [clone ') |
| 104 if idx != -1: |
| 105 symbol.full_name = symbol.full_name[:idx] |
| 106 symbol.flags |= models.FLAG_CLONE |
| 107 |
95 # E.g.: vtable for FOO | 108 # E.g.: vtable for FOO |
96 idx = symbol.full_name.find(' for ', 0, 30) | 109 idx = symbol.full_name.find(' for ', 0, 30) |
97 if idx != -1: | 110 if idx != -1: |
98 found_prefixes.add(symbol.full_name[:idx + 4]) | 111 found_prefixes.add(symbol.full_name[:idx + 4]) |
99 symbol.full_name = ( | 112 symbol.full_name = ( |
100 symbol.full_name[idx + 5:] + ' [' + symbol.full_name[:idx] + ']') | 113 symbol.full_name[idx + 5:] + ' [' + symbol.full_name[:idx] + ']') |
101 | 114 |
102 # E.g.: virtual thunk to FOO | 115 # E.g.: virtual thunk to FOO |
103 idx = symbol.full_name.find(' to ', 0, 30) | 116 idx = symbol.full_name.find(' to ', 0, 30) |
104 if idx != -1: | 117 if idx != -1: |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 # We don't have source info for prebuilt .a files. | 170 # We don't have source info for prebuilt .a files. |
158 if not os.path.isabs(object_path) and not object_path.startswith('..'): | 171 if not os.path.isabs(object_path) and not object_path.startswith('..'): |
159 source_path = source_mapper.FindSourceForPath(object_path) | 172 source_path = source_mapper.FindSourceForPath(object_path) |
160 if source_path: | 173 if source_path: |
161 return _NormalizeSourcePath(source_path) | 174 return _NormalizeSourcePath(source_path) |
162 return False, '' | 175 return False, '' |
163 | 176 |
164 | 177 |
165 def _ExtractSourcePaths(raw_symbols, source_mapper): | 178 def _ExtractSourcePaths(raw_symbols, source_mapper): |
166 """Fills in the |source_path| attribute.""" | 179 """Fills in the |source_path| attribute.""" |
167 logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count) | |
168 for symbol in raw_symbols: | 180 for symbol in raw_symbols: |
169 object_path = symbol.object_path | 181 object_path = symbol.object_path |
170 if object_path and not symbol.source_path: | 182 if object_path and not symbol.source_path: |
171 symbol.generated_source, symbol.source_path = ( | 183 symbol.generated_source, symbol.source_path = ( |
172 _SourcePathForObjectPath(object_path, source_mapper)) | 184 _SourcePathForObjectPath(object_path, source_mapper)) |
173 | 185 |
174 | 186 |
175 def _ComputeAnscestorPath(path_list): | 187 def _ComputeAnscestorPath(path_list): |
176 """Returns the common anscestor of the given paths.""" | 188 """Returns the common anscestor of the given paths.""" |
177 # Ignore missing paths. | 189 # Ignore missing paths. |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 output_directory: Build output directory. If None, source_paths and symbol | 430 output_directory: Build output directory. If None, source_paths and symbol |
419 alias information will not be recorded. | 431 alias information will not be recorded. |
420 """ | 432 """ |
421 source_mapper = None | 433 source_mapper = None |
422 if output_directory: | 434 if output_directory: |
423 # Start by finding the elf_object_paths, so that nm can run on them while | 435 # Start by finding the elf_object_paths, so that nm can run on them while |
424 # the linker .map is being parsed. | 436 # the linker .map is being parsed. |
425 logging.info('Parsing ninja files.') | 437 logging.info('Parsing ninja files.') |
426 source_mapper, elf_object_paths = ninja_parser.Parse( | 438 source_mapper, elf_object_paths = ninja_parser.Parse( |
427 output_directory, elf_path) | 439 output_directory, elf_path) |
| 440 logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count) |
428 assert not elf_path or elf_object_paths, ( | 441 assert not elf_path or elf_object_paths, ( |
429 'Failed to find link command in ninja files for ' + | 442 'Failed to find link command in ninja files for ' + |
430 os.path.relpath(elf_path, output_directory)) | 443 os.path.relpath(elf_path, output_directory)) |
431 | 444 |
432 if elf_path: | 445 if elf_path: |
433 # Run nm on the elf file to retrieve the list of symbol names per-address. | 446 # Run nm on the elf file to retrieve the list of symbol names per-address. |
434 # This list is required because the .map file contains only a single name | 447 # This list is required because the .map file contains only a single name |
435 # for each address, yet multiple symbols are often coalesced when they are | 448 # for each address, yet multiple symbols are often coalesced when they are |
436 # identical. This coalescing happens mainly for small symbols and for C++ | 449 # identical. This coalescing happens mainly for small symbols and for C++ |
437 # templates. Such symbols make up ~500kb of libchrome.so on Android. | 450 # templates. Such symbols make up ~500kb of libchrome.so on Android. |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 logging.warning('Packed section not present: %s', packed_section_name) | 701 logging.warning('Packed section not present: %s', packed_section_name) |
689 else: | 702 else: |
690 size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( | 703 size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( |
691 unstripped_section_sizes.get(packed_section_name)) | 704 unstripped_section_sizes.get(packed_section_name)) |
692 | 705 |
693 logging.info('Recording metadata: \n %s', | 706 logging.info('Recording metadata: \n %s', |
694 '\n '.join(describe.DescribeMetadata(size_info.metadata))) | 707 '\n '.join(describe.DescribeMetadata(size_info.metadata))) |
695 logging.info('Saving result to %s', args.size_file) | 708 logging.info('Saving result to %s', args.size_file) |
696 file_format.SaveSizeInfo(size_info, args.size_file) | 709 file_format.SaveSizeInfo(size_info, args.size_file) |
697 logging.info('Done') | 710 logging.info('Done') |
OLD | NEW |