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