| OLD | NEW | 
|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python | 
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 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 """Generate a spatial analysis against an arbitrary library. | 6 """Generate a spatial analysis against an arbitrary library. | 
| 7 | 7 | 
| 8 To use, build the 'binary_size_tool' target. Then run this tool, passing | 8 To use, build the 'binary_size_tool' target. Then run this tool, passing | 
| 9 in the location of the library to be analyzed along with any other options | 9 in the location of the library to be analyzed along with any other options | 
| 10 you desire. | 10 you desire. | 
| (...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 537 def _find_in_system_path(binary): | 537 def _find_in_system_path(binary): | 
| 538   """Locate the full path to binary in the system path or return None | 538   """Locate the full path to binary in the system path or return None | 
| 539   if not found.""" | 539   if not found.""" | 
| 540   system_path = os.environ["PATH"].split(os.pathsep) | 540   system_path = os.environ["PATH"].split(os.pathsep) | 
| 541   for path in system_path: | 541   for path in system_path: | 
| 542     binary_path = os.path.join(path, binary) | 542     binary_path = os.path.join(path, binary) | 
| 543     if os.path.isfile(binary_path): | 543     if os.path.isfile(binary_path): | 
| 544       return binary_path | 544       return binary_path | 
| 545   return None | 545   return None | 
| 546 | 546 | 
|  | 547 def CheckDebugFormatSupport(library, addr2line_binary): | 
|  | 548   """Kills the program if debug data is in an unsupported format. | 
|  | 549 | 
|  | 550   There are two common versions of the DWARF debug formats and | 
|  | 551   since we are right now transitioning from DWARF2 to newer formats, | 
|  | 552   it's possible to have a mix of tools that are not compatible. Detect | 
|  | 553   that and abort rather than produce meaningless output.""" | 
|  | 554   tool_output = subprocess.check_output([addr2line_binary, '--version']) | 
|  | 555   version_re = re.compile(r'^GNU [^ ]+ .* (\d+).(\d+).*?$', re.M) | 
|  | 556   parsed_output = version_re.match(tool_output) | 
|  | 557   major = int(parsed_output.group(1)) | 
|  | 558   minor = int(parsed_output.group(2)) | 
|  | 559   supports_dwarf4 = major > 2 or major == 2 and minor > 22 | 
|  | 560 | 
|  | 561   if supports_dwarf4: | 
|  | 562     return | 
|  | 563 | 
|  | 564   print('Checking version of debug information in %s.' % library) | 
|  | 565   debug_info = subprocess.check_output(['readelf', '--debug-dump=info', | 
|  | 566                                        '--dwarf-depth=1', library]) | 
|  | 567   dwarf_version_re = re.compile(r'^\s+Version:\s+(\d+)$', re.M) | 
|  | 568   parsed_dwarf_format_output = dwarf_version_re.search(debug_info) | 
|  | 569   version = int(parsed_dwarf_format_output.group(1)) | 
|  | 570   if version > 2: | 
|  | 571     print('The supplied tools only support DWARF2 debug data but the binary\n' + | 
|  | 572           'uses DWARF%d. Update the tools or compile the binary\n' % version + | 
|  | 573           'with -gdwarf-2.') | 
|  | 574     sys.exit(1) | 
|  | 575 | 
| 547 | 576 | 
| 548 def main(): | 577 def main(): | 
| 549   usage = """%prog [options] | 578   usage = """%prog [options] | 
| 550 | 579 | 
| 551   Runs a spatial analysis on a given library, looking up the source locations | 580   Runs a spatial analysis on a given library, looking up the source locations | 
| 552   of its symbols and calculating how much space each directory, source file, | 581   of its symbols and calculating how much space each directory, source file, | 
| 553   and so on is taking. The result is a report that can be used to pinpoint | 582   and so on is taking. The result is a report that can be used to pinpoint | 
| 554   sources of large portions of the binary, etceteras. | 583   sources of large portions of the binary, etceteras. | 
| 555 | 584 | 
| 556   Under normal circumstances, you only need to pass two arguments, thusly: | 585   Under normal circumstances, you only need to pass two arguments, thusly: | 
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 631         'Use --addr2line-binary to specify location.' | 660         'Use --addr2line-binary to specify location.' | 
| 632 | 661 | 
| 633   if opts.nm_binary: | 662   if opts.nm_binary: | 
| 634     assert os.path.isfile(opts.nm_binary) | 663     assert os.path.isfile(opts.nm_binary) | 
| 635     nm_binary = opts.nm_binary | 664     nm_binary = opts.nm_binary | 
| 636   else: | 665   else: | 
| 637     nm_binary = _find_in_system_path('nm') | 666     nm_binary = _find_in_system_path('nm') | 
| 638     assert nm_binary, 'Unable to find nm in the path. Use --nm-binary '\ | 667     assert nm_binary, 'Unable to find nm in the path. Use --nm-binary '\ | 
| 639         'to specify location.' | 668         'to specify location.' | 
| 640 | 669 | 
|  | 670   print('addr2line: %s' % addr2line_binary) | 
| 641   print('nm: %s' % nm_binary) | 671   print('nm: %s' % nm_binary) | 
| 642   print('addr2line: %s' % addr2line_binary) | 672 | 
|  | 673   CheckDebugFormatSupport(opts.library, addr2line_binary) | 
| 643 | 674 | 
| 644   symbols = GetNmSymbols(opts.nm_in, opts.nm_out, opts.library, | 675   symbols = GetNmSymbols(opts.nm_in, opts.nm_out, opts.library, | 
| 645                          opts.jobs, opts.verbose is True, | 676                          opts.jobs, opts.verbose is True, | 
| 646                          addr2line_binary, nm_binary) | 677                          addr2line_binary, nm_binary) | 
| 647   if not os.path.exists(opts.destdir): | 678   if not os.path.exists(opts.destdir): | 
| 648     os.makedirs(opts.destdir, 0755) | 679     os.makedirs(opts.destdir, 0755) | 
| 649 | 680 | 
| 650 | 681 | 
| 651   if opts.legacy: # legacy report | 682   if opts.legacy: # legacy report | 
| 652     DumpTreemap(symbols, os.path.join(opts.destdir, 'treemap-dump.js')) | 683     DumpTreemap(symbols, os.path.join(opts.destdir, 'treemap-dump.js')) | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
| 681     print('Copying index.html') | 712     print('Copying index.html') | 
| 682     shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir) | 713     shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir) | 
| 683     shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir) | 714     shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir) | 
| 684 | 715 | 
| 685   if opts.verbose: | 716   if opts.verbose: | 
| 686     print 'Report saved to ' + opts.destdir + '/index.html' | 717     print 'Report saved to ' + opts.destdir + '/index.html' | 
| 687 | 718 | 
| 688 | 719 | 
| 689 if __name__ == '__main__': | 720 if __name__ == '__main__': | 
| 690   sys.exit(main()) | 721   sys.exit(main()) | 
| OLD | NEW | 
|---|