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 |