Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Side by Side Diff: tools/binary_size/mapfileparser.py

Issue 2778963003: Revert of V2 of //tools/binary_size rewrite (diffs). (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/binary_size/map2size.py ('k') | tools/binary_size/models.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
5 import logging
6
7 import symbols
8
9
10 class ParseResult(object):
11 """Return value for Parse() methods."""
12 def __init__(self, symbol_list, section_sizes=None):
13 self.symbol_group = symbols.SymbolGroup(symbol_list)
14 self.section_sizes = section_sizes # E.g. {'.text': 0}
15
16
17 class MapFileParser(object):
18 """Parses a linker map file (tested only on files from gold linker)."""
19 # Map file writer for gold linker:
20 # https://github.com/gittup/binutils/blob/HEAD/gold/mapfile.cc
21
22 def __init__(self):
23 self._symbols = []
24 self._section_sizes = {}
25 self._lines = None
26
27 def Parse(self, lines):
28 """Parses a linker map file.
29
30 Args:
31 lines: Iterable of lines.
32
33 Returns:
34 A ParseResult object.
35 """
36 self._lines = iter(lines)
37 logging.info('Parsing common symbols')
38 self._ParseCommonSymbols()
39 logging.debug('.bss common entries: %d', len(self._symbols))
40 logging.info('Parsing section symbols')
41 self._ParseSections()
42 return ParseResult(self._symbols, self._section_sizes)
43
44 def _SkipToLineWithPrefix(self, prefix):
45 for l in self._lines:
46 if l.startswith(prefix):
47 return l
48
49 def _ParsePossiblyWrappedParts(self, line, count):
50 parts = line.split(None, count - 1)
51 if not parts:
52 return None
53 if len(parts) != count:
54 line = next(self._lines)
55 parts.extend(line.split(None, count - len(parts) - 1))
56 assert len(parts) == count, 'parts: ' + ' '.join(parts)
57 parts[-1] = parts[-1].rstrip()
58 return parts
59
60 def _ParseCommonSymbols(self):
61 # Common symbol size file
62 #
63 # ff_cos_131072 0x40000 obj/third_party/<snip>
64 # ff_cos_131072_fixed
65 # 0x20000 obj/third_party/<snip>
66 self._SkipToLineWithPrefix('Common symbol')
67 next(self._lines) # Skip past blank line
68
69 name, size_str, path = None, None, None
70 for l in self._lines:
71 parts = self._ParsePossiblyWrappedParts(l, 3)
72 if not parts:
73 break
74 name, size_str, path = parts
75 self._symbols.append(
76 symbols.Symbol('.bss', 0, int(size_str[2:], 16), name, path))
77
78 def _ParseSections(self):
79 # .text 0x0028c600 0x22d3468
80 # .text.startup._GLOBAL__sub_I_bbr_sender.cc
81 # 0x0028c600 0x38 obj/net/net/bbr_sender.o
82 # .text._reset 0x00339d00 0xf0 obj/third_party/icu/icuuc/ucnv.o
83 # ** fill 0x0255fb00 0x02
84 # .text._ZN4base8AutoLockD2Ev
85 # 0x00290710 0xe obj/net/net/file_name.o
86 # 0x00290711 base::AutoLock::~AutoLock()
87 # 0x00290711 base::AutoLock::~AutoLock()
88 # .text._ZNK5blink15LayoutBlockFlow31mustSeparateMarginAfterForChildERK...
89 # 0xffffffffffffffff 0x46 obj/...
90 # 0x006808e1 blink::LayoutBlockFlow::...
91 # .bss
92 # .bss._ZGVZN11GrProcessor11initClassIDI10LightingFPEEvvE8kClassID
93 # 0x02d4b294 0x4 obj/skia/skia/SkLightingShader.o
94 # 0x02d4b294 guard variable for void GrProcessor::initClassID
95 # .data 0x0028c600 0x22d3468
96 # .data.rel.ro._ZTVN3gvr7android19ScopedJavaGlobalRefIP12_jfloatArrayEE
97 # 0x02d1e668 0x10 ../../third_party/.../libfoo.a(bar.o)
98 # 0x02d1e668 vtable for gvr::android::GlobalRef<_jfloatArray*>
99 # ** merge strings
100 # 0x0255fb00 0x1f2424
101 # ** merge constants
102 # 0x0255fb00 0x8
103 # ** common 0x02db5700 0x13ab48
104 self._SkipToLineWithPrefix('Memory map')
105 syms = self._symbols
106 while True:
107 line = self._SkipToLineWithPrefix('.')
108 if not line:
109 break
110 section_name = None
111 try:
112 # Parse section name and size.
113 parts = self._ParsePossiblyWrappedParts(line, 3)
114 if not parts:
115 break
116 section_name, address, size_str = parts
117 self._section_sizes[section_name] = int(size_str[2:], 16)
118 if (section_name in ('.bss', '.rodata', '.text') or
119 section_name.startswith('.data')):
120 logging.info('Parsing %s', section_name)
121 prefix_len = len(section_name) + 1 # + 1 for the trailing .
122 merge_symbol_start_address = 0
123 sym_count_at_start = len(syms)
124 line = next(self._lines)
125 # Parse section symbols.
126 while True:
127 if not line or line.isspace():
128 break
129 if line.startswith(' **'):
130 zero_index = line.find('0')
131 if zero_index == -1:
132 # Line wraps.
133 name = line.strip()
134 line = next(self._lines)
135 else:
136 # Line does not wrap.
137 name = line[:zero_index].strip()
138 line = line[zero_index:]
139 address_str, size_str = self._ParsePossiblyWrappedParts(line, 2)
140 line = next(self._lines)
141 # These bytes are already accounted for.
142 if name == '** common':
143 continue
144 address = int(address_str[2:], 16)
145 size = int(size_str[2:], 16)
146 path = None
147 syms.append(
148 symbols.Symbol(section_name, address, size, name, path))
149 else:
150 # A normal symbol entry.
151 subsection_name, address_str, size_str, path = (
152 self._ParsePossiblyWrappedParts(line, 4))
153 size = int(size_str[2:], 16)
154 if address_str == '0xffffffffffffffff':
155 # The section needs special handling (e.g., a merge section)
156 # It also generally has a large offset after it, so don't
157 # penalize the subsequent symbol for this gap (e.g. a 50kb gap).
158 # TODO(agrieve): Learn more about why this happens.
159 address = -1
160 if syms and syms[-1].address > 0:
161 merge_symbol_start_address = syms[-1].end_address
162 merge_symbol_start_address += size
163 else:
164 address = int(address_str[2:], 16)
165 # Finish off active address gap / merge section.
166 if merge_symbol_start_address:
167 merge_size = address - merge_symbol_start_address
168 sym = symbols.Symbol(
169 section_name, merge_symbol_start_address, merge_size,
170 '** merged symbol: %s' % syms[-1].name, syms[-1].path)
171 logging.debug('Merge symbol of size %d found at:\n %r',
172 merge_size, syms[-1])
173 syms.append(sym)
174 merge_symbol_start_address = 0
175 assert subsection_name.startswith(section_name), (
176 'subsection name was: ' + subsection_name)
177 mangled_name = subsection_name[prefix_len:]
178 name = None
179 while True:
180 line = next(self._lines).rstrip()
181 if not line or line.startswith(' .'):
182 break
183 # clang includes ** fill, but gcc does not.
184 if line.startswith(' ** fill'):
185 # Alignment explicitly recorded in map file. Rather than
186 # record padding based on these entries, we calculate it
187 # using addresses. We do this because fill lines are not
188 # present when compiling with gcc (only for clang).
189 continue
190 elif line.startswith(' **'):
191 break
192 elif name is None:
193 address_str2, name = self._ParsePossiblyWrappedParts(line, 2)
194 if address == -1:
195 address = int(address_str2[2:], 16) - 1
196
197 # Merge sym with no second line showing real address.
198 if address == -1:
199 address = syms[-1].end_address
200 syms.append(symbols.Symbol(section_name, address, size,
201 name or mangled_name, path))
202 logging.debug('Symbol count for %s: %d', section_name,
203 len(syms) - sym_count_at_start)
204 except:
205 logging.error('Problem line: %r', line)
206 logging.error('In section: %r', section_name)
207 raise
OLDNEW
« no previous file with comments | « tools/binary_size/map2size.py ('k') | tools/binary_size/models.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698