1# * Copyright 2015, NICTA
2# *
3# * This software may be distributed and modified according to the terms of
4# * the BSD 2-Clause license. Note that NO WARRANTY is provided.
5# * See "LICENSE_BSD2.txt" for details.
6# *
7# * @TAG(NICTA_BSD)
8
9# parsing code for objdump files. used on a symtab dump to build a python
10# symbol table and on a disassembly of the .rodata section to build a
11# summary of the read-only data
12
13import re
14
15def build_syms (symtab):
16	syms = {}
17	for line in symtab:
18		bits = line.split ()
19		try:
20			addr = int (bits[0], 16)
21			size = int (bits[-2], 16)
22			section = bits[-3]
23			syms[bits[-1]] = (addr, size, section)
24		except ValueError:
25			pass
26		except IndexError:
27			pass
28
29	sections = {}
30	for (addr, size, section) in syms.itervalues ():
31		if not size:
32			continue
33		(start, end) = sections.get (section, (addr, addr))
34		start = min (addr, start)
35		end = max (addr + size - 1, end)
36		sections[section] = (start, end)
37
38	return (syms, sections)
39
40def install_syms (symtab):
41	(syms, sects) = build_syms (symtab)
42	import target_objects
43	target_objects.symbols.update (syms)
44	target_objects.sections.update (sects)
45
46is_rodata_line = re.compile('^\s*[0-9a-fA-F]+:\s+[0-9a-fA-F]+\s+')
47
48def build_rodata (rodata_stream, rodata_ranges = [('Section', '.rodata')]):
49	from syntax import structs, fresh_name, Struct, mk_word32
50	import syntax
51	from target_objects import symbols, sections, trace
52
53	act_rodata_ranges = []
54	for (kind, nm) in rodata_ranges:
55		if kind == 'Symbol':
56			(addr, size, _) = symbols[nm]
57			act_rodata_ranges.append ((addr, addr + size - 1))
58		elif kind == 'Section':
59			if nm in sections:
60				act_rodata_ranges.append (sections[nm])
61			else:
62				# it's reasonable to supply .rodata as the
63				# expected section only for it to be missing
64				trace ('No %r section in objdump.' % nm)
65		else:
66			assert kind in ['Symbol', 'Section'], rodata_ranges
67
68	comb_ranges = []
69	for (start, end) in sorted (act_rodata_ranges):
70		if comb_ranges and comb_ranges[-1][1] + 1 == start:
71			(start, _) = comb_ranges[-1]
72			comb_ranges[-1] = (start, end)
73		else:
74			comb_ranges.append ((start, end))
75
76	rodata = {}
77	for line in rodata_stream:
78		if not is_rodata_line.match (line):
79			continue
80		bits = line.split ()
81		(addr, v) = (int (bits[0][:-1], 16), int (bits[1], 16))
82		if [1 for (start, end) in comb_ranges
83				if start <= addr and addr <= end]:
84			assert addr % 4 == 0, addr
85			rodata[addr] = v
86
87	if len (comb_ranges) == 1:
88		rodata_names = ['rodata_struct']
89	else:
90		rodata_names = ['rodata_struct_%d' % (i + 1)
91			for (i, _) in enumerate (comb_ranges)]
92
93	rodata_ptrs = []
94	for ((start, end), name) in zip (comb_ranges, rodata_names):
95		struct_name = fresh_name (name, structs)
96		struct = Struct (struct_name, (end - start) + 1, 1)
97		structs[struct_name] = struct
98		typ = syntax.get_global_wrapper (struct.typ)
99		rodata_ptrs.append ((mk_word32 (start), typ))
100
101	return (rodata, comb_ranges, rodata_ptrs)
102
103def install_rodata (rodata_stream, rodata_ranges = [('Section', '.rodata')]):
104	import target_objects
105	rodata = build_rodata (rodata_stream, rodata_ranges)
106	target_objects.rodata[:] = rodata
107
108# the prunes file isn't really an objdump file, but this seems the best place
109
110non_var_re = re.compile('[(),\s\[\]]+')
111
112def parse_prunes (prune_stream):
113	prunes = {}
114	for l in prune_stream:
115		[lname, rhs] = l.split ('from [')
116		bits = lname.split ()
117		assert bits[:3] == ['Pruned', 'inputs', 'of']
118		name = bits[3]
119		[lvars, rvars] = rhs.split ('] to [')
120		lvars = [v for v in non_var_re.split (lvars) if v]
121		rvars = [v for v in non_var_re.split (rvars) if v]
122		if not (lvars[-2:] == ['dm', 'm']
123				and rvars[-2:] == ['dm', 'm']):
124			continue
125		lvars = lvars[:-2]
126		rvars = rvars[:-2]
127		prunes['DecompiledFuns.' + name + '_step'] = (lvars, rvars)
128	return prunes
129
130# likewise the signatures produced by the c-parser
131
132def parse_sigs (sig_stream):
133	sigs = {}
134	for l in sig_stream:
135		bits = l.split ()
136		if not bits:
137			continue
138		ret = int (bits[0])
139		nm = bits[1]
140		args = [int(bit) for bit in bits[2:]]
141		sigs[nm] = (args, ret)
142	return sigs
143
144