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

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

Powered by Google App Engine
This is Rietveld 408576698