secure-hid/mapparse.py
2017-07-30 15:36:45 +02:00

129 lines
4.9 KiB
Python

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))