| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright 2017 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Tool for analyzing binary size of executables using nm or linker map files. | |
| 7 | |
| 8 Map files can be created by passing "-Map Foo.map" to the linker. If a map file | |
| 9 is unavailable, this tool can also be pointed at an unstripped executable, but | |
| 10 the information does not seem to be as accurate in this case. | |
| 11 | |
| 12 Inspired by SymbolSort for Windows: | |
| 13 https://github.com/adrianstone55/SymbolSort | |
| 14 """ | |
| 15 | |
| 16 import argparse | |
| 17 import code | |
| 18 import contextlib | |
| 19 import logging | |
| 20 import readline | |
| 21 import subprocess | |
| 22 import sys | |
| 23 | |
| 24 import analyze | |
| 25 import helpers | |
| 26 import symbols | |
| 27 | |
| 28 | |
| 29 # Number of lines before using less for Print(). | |
| 30 _THRESHOLD_FOR_PAGER = 30 | |
| 31 | |
| 32 | |
| 33 @contextlib.contextmanager | |
| 34 def _LessPipe(): | |
| 35 """Output to `less`. Yields the write function.""" | |
| 36 try: | |
| 37 proc = subprocess.Popen(['less'], stdin=subprocess.PIPE, stdout=sys.stdout) | |
| 38 yield proc.stdin.write | |
| 39 proc.stdin.close() | |
| 40 | |
| 41 proc.wait() | |
| 42 except IOError: | |
| 43 pass # Happens when less is quit before all data is written. | |
| 44 except KeyboardInterrupt: | |
| 45 pass # Assume used to break out of less. | |
| 46 | |
| 47 | |
| 48 def _PrintSymbolGroup(group, show_elided=True, use_pager=None): | |
| 49 """Prints out the given list of symbols. | |
| 50 | |
| 51 Args: | |
| 52 show_elided: Whether to print out group.filtered_symbols. | |
| 53 """ | |
| 54 by_size = group.Sorted() | |
| 55 # TODO(agrieve): Taking line-wrapping into account for groups vs. symbols | |
| 56 # would make sense here. | |
| 57 if use_pager is None: | |
| 58 count = sum(1 if s.IsGroup() else 2 for s in group) | |
| 59 if show_elided and group.filtered_symbols: | |
| 60 count += 1 | |
| 61 use_pager = count > _THRESHOLD_FOR_PAGER | |
| 62 | |
| 63 def write_to_func(write): | |
| 64 write('Showing {:,} results with total size: {:,} bytes\n'.format( | |
| 65 len(group), group.size)) | |
| 66 for s in by_size: | |
| 67 if s.IsGroup(): | |
| 68 write('{} {:<9,} {} ({})\n'.format(s.section, s.size, s.name, len(s))) | |
| 69 else: | |
| 70 template = '{}@0x{:<8x} {:<7} {}\n{:22}{}\n' | |
| 71 write(template.format(s.section, s.address, s.size, | |
| 72 s.path or '<no path>', '', s.name or '<no name>')) | |
| 73 if show_elided and group.filtered_symbols: | |
| 74 elided = group.Inverted() | |
| 75 write('* Filtered out {:,} symbols comprising {:<7,} bytes.\n'.format( | |
| 76 len(elided), elided.size)) | |
| 77 | |
| 78 if use_pager: | |
| 79 with _LessPipe() as write: | |
| 80 write_to_func(write) | |
| 81 else: | |
| 82 write_to_func(sys.stdout.write) | |
| 83 | |
| 84 | |
| 85 def main(): | |
| 86 parser = argparse.ArgumentParser() | |
| 87 parser.add_argument('--query', | |
| 88 help='Print the result of the given snippet. Example: ' | |
| 89 'all_syms.WhereInSection("d").WhereBiggerThan(100)') | |
| 90 analyze.AddOptions(parser) | |
| 91 args = helpers.AddCommonOptionsAndParseArgs(parser) | |
| 92 | |
| 93 result = analyze.AnalyzeWithArgs(args) | |
| 94 | |
| 95 variables = { | |
| 96 'Print': _PrintSymbolGroup, | |
| 97 'all_syms': result.symbol_group, | |
| 98 } | |
| 99 | |
| 100 if args.query: | |
| 101 logging.info('Running query from command-line.') | |
| 102 eval_result = eval(args.query, locals=variables) | |
| 103 if isinstance(eval_result, symbols.SymbolGroup): | |
| 104 _PrintSymbolGroup(eval_result, show_elided=False, use_pager=False) | |
| 105 return | |
| 106 | |
| 107 logging.info('Entering interactive console.') | |
| 108 | |
| 109 print '*' * 80 | |
| 110 print 'Entering interactive Python shell. Here is some inspiration:' | |
| 111 print | |
| 112 print '# Show two levels of .text, grouped by first two subdirectories' | |
| 113 print 'text_syms = all_syms.WhereInSection("t")' | |
| 114 print 'by_path = text_syms.GroupByPath(depth=2)' | |
| 115 print 'Print(by_path.WhereBiggerThan(1024, include_filtered=True))' | |
| 116 print | |
| 117 print '# Show all non-vtable generated symbols' | |
| 118 print 'Print(all_syms.WhereNameMatches(r"(?<!vtable)(?<!\[)\]$"))' | |
| 119 print | |
| 120 print '*' * 80 | |
| 121 print | |
| 122 print 'locals:', variables.keys() | |
| 123 print 'method quick reference:', ( | |
| 124 [m for m in dir(symbols.SymbolGroup) if m[0].isupper()]) | |
| 125 print | |
| 126 print '*' * 80 | |
| 127 | |
| 128 # Without initializing readline, arrow keys don't even work! | |
| 129 readline.parse_and_bind('tab: complete') | |
| 130 code.InteractiveConsole(locals=variables).interact() | |
| 131 | |
| 132 | |
| 133 if __name__ == '__main__': | |
| 134 main() | |
| OLD | NEW |