Add size tracing tool
This commit is contained in:
parent
03e8443e2e
commit
bf7e8701c7
5 changed files with 596 additions and 0 deletions
129
controller/fw/tools/mapparse.py
Normal file
129
controller/fw/tools/mapparse.py
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
|
||||
import re
|
||||
from collections import defaultdict, namedtuple
|
||||
|
||||
Section = namedtuple('Section', ['name', 'offset', 'objects'])
|
||||
ObjectEntry = namedtuple('ObjectEntry', ['filename', 'object', 'offset', 'size'])
|
||||
FileEntry = namedtuple('FileEntry', ['section', 'object', 'offset', 'length'])
|
||||
|
||||
class Memory:
|
||||
def __init__(self, name, origin, length, attrs=''):
|
||||
self.name, self.origin, self.length, self.attrs = name, origin, length, attrs
|
||||
self.sections = {}
|
||||
self.files = defaultdict(lambda: [])
|
||||
self.totals = defaultdict(lambda: 0)
|
||||
|
||||
def add_toplevel(self, name, offx, length):
|
||||
self.sections[name] = Section(offx, length, [])
|
||||
|
||||
def add_obj(self, name, offx, length, fn, obj):
|
||||
base_section, sep, subsec = name[1:].partition('.')
|
||||
base_section = '.'+base_section
|
||||
if base_section in self.sections:
|
||||
sec = secname, secoffx, secobjs = self.sections[base_section]
|
||||
secobjs.append(ObjectEntry(fn, obj, offx, length))
|
||||
else:
|
||||
sec = None
|
||||
self.files[fn].append(FileEntry(sec, obj, offx, length))
|
||||
self.totals[fn] += length
|
||||
|
||||
class MapFile:
|
||||
def __init__(self, s):
|
||||
self._lines = s.splitlines()
|
||||
self.memcfg = {}
|
||||
self.defaultmem = Memory('default', 0, 0xffffffffffffffff)
|
||||
self._parse()
|
||||
|
||||
def __getitem__(self, offx_or_name):
|
||||
''' Lookup a memory area by name or address '''
|
||||
if offx_or_name in self.memcfg:
|
||||
return self.memcfg[offx_or_name]
|
||||
|
||||
elif isinstance(offx_or_name, int):
|
||||
for mem in self.memcfg.values():
|
||||
if mem.origin <= offx_or_name < mem.origin+mem.length:
|
||||
return mem
|
||||
else:
|
||||
return self.defaultmem
|
||||
|
||||
raise ValueError('Invalid argument type for indexing')
|
||||
|
||||
def _skip(self, regex):
|
||||
matcher = re.compile(regex)
|
||||
for l in self:
|
||||
if matcher.match(l):
|
||||
break
|
||||
|
||||
def __iter__(self):
|
||||
while self._lines:
|
||||
yield self._lines.pop(0)
|
||||
|
||||
def _parse(self):
|
||||
self._skip('^Memory Configuration')
|
||||
|
||||
# Parse memory segmentation info
|
||||
self._skip('^Name')
|
||||
for l in self:
|
||||
if not l:
|
||||
break
|
||||
name, origin, length, *attrs = l.split()
|
||||
if not name.startswith('*'):
|
||||
self.memcfg[name] = Memory(name, int(origin, 16), int(length, 16), attrs[0] if attrs else '')
|
||||
|
||||
# Parse section information
|
||||
toplevel_m = re.compile('^(\.[a-zA-Z0-9_.]+)\s+(0x[0-9a-fA-F]+)\s+(0x[0-9a-fA-F]+)')
|
||||
secondlevel_m = re.compile('^ (\.[a-zA-Z0-9_.]+)\s+(0x[0-9a-fA-F]+)\s+(0x[0-9a-fA-F]+)\s+(.*)$')
|
||||
secondlevel_linebreak_m = re.compile('^ (\.[a-zA-Z0-9_.]+)\n')
|
||||
filelike = re.compile('^(/?[^()]*\.[a-zA-Z0-9-_]+)(\(.*\))?')
|
||||
linebreak_section = None
|
||||
for l in self:
|
||||
# Toplevel section
|
||||
match = toplevel_m.match(l)
|
||||
if match:
|
||||
name, offx, length = match.groups()
|
||||
offx, length = int(offx, 16), int(length, 16)
|
||||
self[offx].add_toplevel(name, offx, length)
|
||||
|
||||
match = secondlevel_linebreak_m.match(l)
|
||||
if match:
|
||||
linebreak_section, = match.groups()
|
||||
continue
|
||||
|
||||
if linebreak_section:
|
||||
l = ' {} {}'.format(linebreak_section, l)
|
||||
linebreak_section = None
|
||||
|
||||
# Second-level section
|
||||
match = secondlevel_m.match(l)
|
||||
if match:
|
||||
name, offx, length, misc = match.groups()
|
||||
match = filelike.match(misc)
|
||||
if match:
|
||||
fn, obj = match.groups()
|
||||
obj = obj.strip('()') if obj else None
|
||||
offx, length = int(offx, 16), int(length, 16)
|
||||
self[offx].add_obj(name, offx, length, fn, obj)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description='Parser GCC map file')
|
||||
parser.add_argument('mapfile', type=argparse.FileType('r'), help='The GCC .map file to parse')
|
||||
parser.add_argument('-m', '--memory', type=str, help='The memory segments to print, comma-separated')
|
||||
args = parser.parse_args()
|
||||
mf = MapFile(args.mapfile.read())
|
||||
args.mapfile.close()
|
||||
|
||||
mems = args.memory.split(',') if args.memory else mf.memcfg.keys()
|
||||
|
||||
for name in mems:
|
||||
mem = mf.memcfg[name]
|
||||
print('Symbols by file for memory', name)
|
||||
for tot, fn in reversed(sorted( (tot, fn) for fn, tot in mem.totals.items() )):
|
||||
print(' {:>8} {}'.format(tot, fn))
|
||||
for length, offx, sec, obj in reversed(sorted(( (length, offx, sec, obj) for sec, obj, offx, length in
|
||||
mem.files[fn] ), key=lambda e: e[0] )):
|
||||
name = sec.name if sec else None
|
||||
print(' {:>8} {:>#08x} {}'.format(length, offx, obj))
|
||||
#print('{:>16} 0x{:016x} 0x{:016x} ({:>24}) {}'.format(name, origin, length, length, attrs))
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue