| OLD | NEW |
| 1 # Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import logging | 5 import logging |
| 6 | 6 |
| 7 import symbols | 7 import models |
| 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 | 8 |
| 16 | 9 |
| 17 class MapFileParser(object): | 10 class MapFileParser(object): |
| 18 """Parses a linker map file (tested only on files from gold linker).""" | 11 """Parses a linker map file (tested only on files from gold linker).""" |
| 19 # Map file writer for gold linker: | 12 # Map file writer for gold linker: |
| 20 # https://github.com/gittup/binutils/blob/HEAD/gold/mapfile.cc | 13 # https://github.com/gittup/binutils/blob/HEAD/gold/mapfile.cc |
| 21 | 14 |
| 22 def __init__(self): | 15 def __init__(self): |
| 23 self._symbols = [] | 16 self._symbols = [] |
| 24 self._section_sizes = {} | 17 self._section_sizes = {} |
| 25 self._lines = None | 18 self._lines = None |
| 26 | 19 |
| 27 def Parse(self, lines): | 20 def Parse(self, lines): |
| 28 """Parses a linker map file. | 21 """Parses a linker map file. |
| 29 | 22 |
| 30 Args: | 23 Args: |
| 31 lines: Iterable of lines. | 24 lines: Iterable of lines. |
| 32 | 25 |
| 33 Returns: | 26 Returns: |
| 34 A ParseResult object. | 27 A SizeInfo object. |
| 35 """ | 28 """ |
| 36 self._lines = iter(lines) | 29 self._lines = iter(lines) |
| 37 logging.info('Parsing common symbols') | 30 logging.info('Parsing common symbols') |
| 38 self._ParseCommonSymbols() | 31 self._ParseCommonSymbols() |
| 39 logging.debug('.bss common entries: %d', len(self._symbols)) | 32 logging.debug('.bss common entries: %d', len(self._symbols)) |
| 40 logging.info('Parsing section symbols') | 33 logging.info('Parsing section symbols') |
| 41 self._ParseSections() | 34 self._ParseSections() |
| 42 return ParseResult(self._symbols, self._section_sizes) | 35 return models.SizeInfo(models.SymbolGroup(self._symbols), |
| 36 self._section_sizes) |
| 43 | 37 |
| 44 def _SkipToLineWithPrefix(self, prefix): | 38 def _SkipToLineWithPrefix(self, prefix): |
| 45 for l in self._lines: | 39 for l in self._lines: |
| 46 if l.startswith(prefix): | 40 if l.startswith(prefix): |
| 47 return l | 41 return l |
| 48 | 42 |
| 49 def _ParsePossiblyWrappedParts(self, line, count): | 43 def _ParsePossiblyWrappedParts(self, line, count): |
| 50 parts = line.split(None, count - 1) | 44 parts = line.split(None, count - 1) |
| 51 if not parts: | 45 if not parts: |
| 52 return None | 46 return None |
| (...skipping 13 matching lines...) Expand all Loading... |
| 66 self._SkipToLineWithPrefix('Common symbol') | 60 self._SkipToLineWithPrefix('Common symbol') |
| 67 next(self._lines) # Skip past blank line | 61 next(self._lines) # Skip past blank line |
| 68 | 62 |
| 69 name, size_str, path = None, None, None | 63 name, size_str, path = None, None, None |
| 70 for l in self._lines: | 64 for l in self._lines: |
| 71 parts = self._ParsePossiblyWrappedParts(l, 3) | 65 parts = self._ParsePossiblyWrappedParts(l, 3) |
| 72 if not parts: | 66 if not parts: |
| 73 break | 67 break |
| 74 name, size_str, path = parts | 68 name, size_str, path = parts |
| 75 self._symbols.append( | 69 self._symbols.append( |
| 76 symbols.Symbol('.bss', 0, int(size_str[2:], 16), name, path)) | 70 models.Symbol('.bss', int(size_str[2:], 16), name=name, path=path)) |
| 77 | 71 |
| 78 def _ParseSections(self): | 72 def _ParseSections(self): |
| 79 # .text 0x0028c600 0x22d3468 | 73 # .text 0x0028c600 0x22d3468 |
| 80 # .text.startup._GLOBAL__sub_I_bbr_sender.cc | 74 # .text.startup._GLOBAL__sub_I_bbr_sender.cc |
| 81 # 0x0028c600 0x38 obj/net/net/bbr_sender.o | 75 # 0x0028c600 0x38 obj/net/net/bbr_sender.o |
| 82 # .text._reset 0x00339d00 0xf0 obj/third_party/icu/icuuc/ucnv.o | 76 # .text._reset 0x00339d00 0xf0 obj/third_party/icu/icuuc/ucnv.o |
| 83 # ** fill 0x0255fb00 0x02 | 77 # ** fill 0x0255fb00 0x02 |
| 84 # .text._ZN4base8AutoLockD2Ev | 78 # .text._ZN4base8AutoLockD2Ev |
| 85 # 0x00290710 0xe obj/net/net/file_name.o | 79 # 0x00290710 0xe obj/net/net/file_name.o |
| 86 # 0x00290711 base::AutoLock::~AutoLock() | 80 # 0x00290711 base::AutoLock::~AutoLock() |
| 87 # 0x00290711 base::AutoLock::~AutoLock() | 81 # 0x00290711 base::AutoLock::~AutoLock() |
| 88 # .text._ZNK5blink15LayoutBlockFlow31mustSeparateMarginAfterForChildERK... | 82 # .text._ZNK5blink15LayoutBlockFlow31mustSeparateMarginAfterForChildERK... |
| 89 # 0xffffffffffffffff 0x46 obj/... | 83 # 0xffffffffffffffff 0x46 obj/... |
| 90 # 0x006808e1 blink::LayoutBlockFlow::... | 84 # 0x006808e1 blink::LayoutBlockFlow::... |
| 91 # .bss | 85 # .bss |
| 92 # .bss._ZGVZN11GrProcessor11initClassIDI10LightingFPEEvvE8kClassID | 86 # .bss._ZGVZN11GrProcessor11initClassIDI10LightingFPEEvvE8kClassID |
| 93 # 0x02d4b294 0x4 obj/skia/skia/SkLightingShader.o | 87 # 0x02d4b294 0x4 obj/skia/skia/SkLightingShader.o |
| 94 # 0x02d4b294 guard variable for void GrProcessor::initClassID | 88 # 0x02d4b294 guard variable for void GrProcessor::initClassID |
| 95 # .data 0x0028c600 0x22d3468 | 89 # .data 0x0028c600 0x22d3468 |
| 96 # .data.rel.ro._ZTVN3gvr7android19ScopedJavaGlobalRefIP12_jfloatArrayEE | 90 # .data.rel.ro._ZTVN3gvr7android19ScopedJavaGlobalRefIP12_jfloatArrayEE |
| 97 # 0x02d1e668 0x10 ../../third_party/.../libfoo.a(bar.o) | 91 # 0x02d1e668 0x10 ../../third_party/.../libfoo.a(bar.o) |
| 98 # 0x02d1e668 vtable for gvr::android::GlobalRef<_jfloatArray*> | 92 # 0x02d1e668 vtable for gvr::android::GlobalRef<_jfloatArray*> |
| 99 # ** merge strings | 93 # ** merge strings |
| 100 # 0x0255fb00 0x1f2424 | 94 # 0x0255fb00 0x1f2424 |
| 101 # ** merge constants | 95 # ** merge constants |
| 102 # 0x0255fb00 0x8 | 96 # 0x0255fb00 0x8 |
| 103 # ** common 0x02db5700 0x13ab48 | 97 # ** common 0x02db5700 0x13ab48 |
| 104 self._SkipToLineWithPrefix('Memory map') | 98 self._SkipToLineWithPrefix('Memory map') |
| 105 syms = self._symbols | 99 syms = self._symbols |
| 100 symbol_gap_count = 0 |
| 106 while True: | 101 while True: |
| 107 line = self._SkipToLineWithPrefix('.') | 102 line = self._SkipToLineWithPrefix('.') |
| 108 if not line: | 103 if not line: |
| 109 break | 104 break |
| 110 section_name = None | 105 section_name = None |
| 111 try: | 106 try: |
| 112 # Parse section name and size. | 107 # Parse section name and size. |
| 113 parts = self._ParsePossiblyWrappedParts(line, 3) | 108 parts = self._ParsePossiblyWrappedParts(line, 3) |
| 114 if not parts: | 109 if not parts: |
| 115 break | 110 break |
| (...skipping 22 matching lines...) Expand all Loading... |
| 138 line = line[zero_index:] | 133 line = line[zero_index:] |
| 139 address_str, size_str = self._ParsePossiblyWrappedParts(line, 2) | 134 address_str, size_str = self._ParsePossiblyWrappedParts(line, 2) |
| 140 line = next(self._lines) | 135 line = next(self._lines) |
| 141 # These bytes are already accounted for. | 136 # These bytes are already accounted for. |
| 142 if name == '** common': | 137 if name == '** common': |
| 143 continue | 138 continue |
| 144 address = int(address_str[2:], 16) | 139 address = int(address_str[2:], 16) |
| 145 size = int(size_str[2:], 16) | 140 size = int(size_str[2:], 16) |
| 146 path = None | 141 path = None |
| 147 syms.append( | 142 syms.append( |
| 148 symbols.Symbol(section_name, address, size, name, path)) | 143 models.Symbol(section_name, size, address=address, name=name, |
| 144 path=path)) |
| 149 else: | 145 else: |
| 150 # A normal symbol entry. | 146 # A normal symbol entry. |
| 151 subsection_name, address_str, size_str, path = ( | 147 subsection_name, address_str, size_str, path = ( |
| 152 self._ParsePossiblyWrappedParts(line, 4)) | 148 self._ParsePossiblyWrappedParts(line, 4)) |
| 153 size = int(size_str[2:], 16) | 149 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), ( | 150 assert subsection_name.startswith(section_name), ( |
| 176 'subsection name was: ' + subsection_name) | 151 'subsection name was: ' + subsection_name) |
| 177 mangled_name = subsection_name[prefix_len:] | 152 mangled_name = subsection_name[prefix_len:] |
| 178 name = None | 153 name = None |
| 154 address_str2 = None |
| 179 while True: | 155 while True: |
| 180 line = next(self._lines).rstrip() | 156 line = next(self._lines).rstrip() |
| 181 if not line or line.startswith(' .'): | 157 if not line or line.startswith(' .'): |
| 182 break | 158 break |
| 183 # clang includes ** fill, but gcc does not. | 159 # clang includes ** fill, but gcc does not. |
| 184 if line.startswith(' ** fill'): | 160 if line.startswith(' ** fill'): |
| 185 # Alignment explicitly recorded in map file. Rather than | 161 # Alignment explicitly recorded in map file. Rather than |
| 186 # record padding based on these entries, we calculate it | 162 # record padding based on these entries, we calculate it |
| 187 # using addresses. We do this because fill lines are not | 163 # using addresses. We do this because fill lines are not |
| 188 # present when compiling with gcc (only for clang). | 164 # present when compiling with gcc (only for clang). |
| 189 continue | 165 continue |
| 190 elif line.startswith(' **'): | 166 elif line.startswith(' **'): |
| 191 break | 167 break |
| 192 elif name is None: | 168 elif name is None: |
| 193 address_str2, name = self._ParsePossiblyWrappedParts(line, 2) | 169 address_str2, name = self._ParsePossiblyWrappedParts(line, 2) |
| 194 if address == -1: | |
| 195 address = int(address_str2[2:], 16) - 1 | |
| 196 | 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 |
| 197 # Merge sym with no second line showing real address. | 199 # Merge sym with no second line showing real address. |
| 198 if address == -1: | 200 if address == -1: |
| 199 address = syms[-1].end_address | 201 address = syms[-1].end_address |
| 200 syms.append(symbols.Symbol(section_name, address, size, | 202 syms.append(models.Symbol(section_name, size, address=address, |
| 201 name or mangled_name, path)) | 203 name=name or mangled_name, path=path)) |
| 202 logging.debug('Symbol count for %s: %d', section_name, | 204 logging.debug('Symbol count for %s: %d', section_name, |
| 203 len(syms) - sym_count_at_start) | 205 len(syms) - sym_count_at_start) |
| 204 except: | 206 except: |
| 205 logging.error('Problem line: %r', line) | 207 logging.error('Problem line: %r', line) |
| 206 logging.error('In section: %r', section_name) | 208 logging.error('In section: %r', section_name) |
| 207 raise | 209 raise |
| OLD | NEW |