| OLD | NEW |
| (Empty) |
| 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 | |
| 3 # found in the LICENSE file. | |
| 4 """Methods for converting model objects to human-readable formats.""" | |
| 5 | |
| 6 import itertools | |
| 7 | |
| 8 import models | |
| 9 | |
| 10 | |
| 11 class Describer(object): | |
| 12 def __init__(self, verbose=False): | |
| 13 self.verbose = verbose | |
| 14 | |
| 15 def _DescribeSectionSizes(self, section_sizes): | |
| 16 relevant_names = models.SECTION_TO_SECTION_NAME.values() | |
| 17 section_names = sorted(k for k in section_sizes.iterkeys() | |
| 18 if k in relevant_names or k.startswith('.data')) | |
| 19 total_bytes = sum(v for k, v in section_sizes.iteritems() | |
| 20 if k in section_names and k != '.bss') | |
| 21 yield 'Section Sizes (Total={:,} bytes):'.format(total_bytes) | |
| 22 for name in section_names: | |
| 23 size = section_sizes[name] | |
| 24 if name == '.bss': | |
| 25 yield '{}: {:,} bytes (not included in totals)'.format(name, size) | |
| 26 else: | |
| 27 percent = float(size) / total_bytes if total_bytes else 0 | |
| 28 yield '{}: {:,} bytes ({:.1%})'.format(name, size, percent) | |
| 29 | |
| 30 def _DescribeSymbol(self, sym): | |
| 31 # SymbolGroups are passed here when we don't want to expand them. | |
| 32 if sym.IsGroup(): | |
| 33 yield '{} {:<8} {} (count={})'.format(sym.section, sym.size, sym.name, | |
| 34 len(sym)) | |
| 35 return | |
| 36 | |
| 37 yield '{}@0x{:<8x} {:<7} {}'.format( | |
| 38 sym.section, sym.address, sym.size, sym.path or '<no path>') | |
| 39 if sym.name: | |
| 40 yield '{:22}{}'.format('', sym.name) | |
| 41 | |
| 42 def _DescribeSymbolGroup(self, group, prefix_func=None): | |
| 43 yield 'Showing {:,} symbols with total size: {:} bytes'.format( | |
| 44 len(group), group.size) | |
| 45 yield 'First columns are: running total, type, size' | |
| 46 | |
| 47 running_total = 0 | |
| 48 prefix = '' | |
| 49 | |
| 50 for s in group.Sorted(): | |
| 51 if group.IsBss() or not s.IsBss(): | |
| 52 running_total += s.size | |
| 53 if prefix_func: | |
| 54 prefix = prefix_func(s) | |
| 55 for l in self._DescribeSymbol(s): | |
| 56 yield '{}{:8} {}'.format(prefix, running_total, l) | |
| 57 | |
| 58 def _DescribeSymbolDiff(self, diff): | |
| 59 template = ('{} symbols added (+), {} changed (~), {} removed (-), ' | |
| 60 '{} unchanged ({})') | |
| 61 unchanged_msg = '=' if self.verbose else 'not shown' | |
| 62 header_str = (template.format( | |
| 63 diff.added_count, diff.changed_count, diff.removed_count, | |
| 64 diff.unchanged_count, unchanged_msg)) | |
| 65 | |
| 66 def prefix_func(sym): | |
| 67 if diff.IsAdded(sym): | |
| 68 return '+ ' | |
| 69 if diff.IsRemoved(sym): | |
| 70 return '- ' | |
| 71 if sym.size: | |
| 72 return '~ ' | |
| 73 return '= ' | |
| 74 | |
| 75 diff = diff if self.verbose else diff.WhereNotUnchanged() | |
| 76 group_desc = self._DescribeSymbolGroup(diff, prefix_func=prefix_func) | |
| 77 return itertools.chain((header_str,), group_desc) | |
| 78 | |
| 79 def GenerateLines(self, obj): | |
| 80 if isinstance(obj, models.SizeInfo): | |
| 81 section_desc = self._DescribeSectionSizes(obj.section_sizes) | |
| 82 group_desc = self.GenerateLines(obj.symbols) | |
| 83 return itertools.chain(section_desc, ('',), group_desc) | |
| 84 | |
| 85 if isinstance(obj, models.SymbolDiff): | |
| 86 return self._DescribeSymbolDiff(obj) | |
| 87 | |
| 88 if isinstance(obj, models.SymbolGroup): | |
| 89 return self._DescribeSymbolGroup(obj) | |
| 90 | |
| 91 if isinstance(obj, models.Symbol): | |
| 92 return self._DescribeSymbol(obj) | |
| 93 | |
| 94 return (repr(obj),) | |
| 95 | |
| 96 | |
| 97 def DescribeSizeInfoCoverage(size_info): | |
| 98 """Yields lines describing how accurate |size_info| is.""" | |
| 99 for section in models.SECTION_TO_SECTION_NAME: | |
| 100 if section == 'd': | |
| 101 expected_size = sum(v for k, v in size_info.section_sizes.iteritems() | |
| 102 if k.startswith('.data')) | |
| 103 else: | |
| 104 expected_size = size_info.section_sizes[ | |
| 105 models.SECTION_TO_SECTION_NAME[section]] | |
| 106 | |
| 107 def one_stat(group): | |
| 108 template = ('Section %s has %.1f%% of %d bytes accounted for from ' | |
| 109 '%d symbols. %d bytes are unaccounted for. Padding ' | |
| 110 'accounts for %d bytes') | |
| 111 actual_size = group.size | |
| 112 count = len(group) | |
| 113 padding = group.padding | |
| 114 size_percent = 100.0 * actual_size / expected_size | |
| 115 return (template % (section, size_percent, actual_size, count, | |
| 116 expected_size - actual_size, padding)) | |
| 117 | |
| 118 in_section = size_info.symbols.WhereInSection(section) | |
| 119 yield one_stat(in_section) | |
| 120 | |
| 121 star_syms = in_section.WhereNameMatches(r'^\*') | |
| 122 attributed_syms = star_syms.Inverted().WhereHasAnyAttribution() | |
| 123 anonymous_syms = attributed_syms.Inverted() | |
| 124 if star_syms or anonymous_syms: | |
| 125 missing_size = star_syms.size + anonymous_syms.size | |
| 126 yield ('+ Without %d merge sections and %d anonymous entries (' | |
| 127 'accounting for %d bytes):') % ( | |
| 128 len(star_syms), len(anonymous_syms), missing_size) | |
| 129 yield '+ ' + one_stat(attributed_syms) | |
| 130 | |
| 131 | |
| 132 def GenerateLines(obj, verbose=False): | |
| 133 return Describer(verbose).GenerateLines(obj) | |
| 134 | |
| 135 | |
| 136 def WriteLines(lines, func): | |
| 137 for l in lines: | |
| 138 func(l) | |
| 139 func('\n') | |
| OLD | NEW |