| 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 |