Make it work (somewhat)

Signed-off-by: Juraj Oravec <jurajoravec@mailo.com>
This commit is contained in:
Juraj Oravec 2024-05-10 23:34:00 +02:00
parent 3c6b845948
commit 9a7f1d21fd
Signed by: SGOrava
GPG Key ID: 13660A3F1D9F093B

267
main.py
View File

@ -1,13 +1,12 @@
#!/bin/python #!/bin/python
import sys import sys
import math
from bear import formats from bear import formats
from elftools.dwarf.locationlists import LocationParser, LocationExpr from elftools.dwarf.locationlists import LocationParser, LocationExpr
from elftools.dwarf.dwarf_expr import DWARFExprParser, DWARFExprOp, DW_OP_opcode2name from elftools.dwarf.dwarf_expr import DWARFExprParser, DWARFExprOp, DW_OP_opcode2name
from bear.dwarfone import DWARFExprParserV1 from bear.dwarfone import DWARFExprParserV1
from pprint import pprint
configuration = { configuration = {
"include_file_name": False, "include_file_name": False,
@ -31,6 +30,7 @@ def decorate_die(die, i):
die._children = None die._children = None
return die return die
def load_children(parent_die): def load_children(parent_die):
# Load and cache child DIEs in the parent DIE, if necessary # Load and cache child DIEs in the parent DIE, if necessary
# Assumes the check if the DIE has children has been already performed # Assumes the check if the DIE has children has been already performed
@ -47,8 +47,7 @@ def load_children(parent_die):
parent_die._children = [] parent_die._children = []
def safe_DIE_name(die, default=''):
def safe_DIE_name(die, default = ''):
return die.attributes['DW_AT_name'].value.decode('utf-8', errors='ignore') if 'DW_AT_name' in die.attributes else default return die.attributes['DW_AT_name'].value.decode('utf-8', errors='ignore') if 'DW_AT_name' in die.attributes else default
@ -64,6 +63,7 @@ class Bear():
# Some cached top level stuff # Some cached top level stuff
# Notably, iter_CUs doesn't cache # Notably, iter_CUs doesn't cache
di._ranges = None # Loaded on first use di._ranges = None # Loaded on first use
def decorate_cu(cu, i): def decorate_cu(cu, i):
cu._i = i cu._i = i
cu._lineprogram = None cu._lineprogram = None
@ -80,7 +80,7 @@ class Bear():
self.dwarfinfo = di self.dwarfinfo = di
self.filename = filename self.filename = filename
except AssertionError as ass: # Covers exeptions during parsing except AssertionError as ass: # Covers exeptions during parsing
raise DWARFParseError(ass, di) raise DWARFParseError(ass, di)
# A list containing variables in a disctionary # A list containing variables in a disctionary
@ -91,6 +91,7 @@ class Bear():
# address: absolute address of the variable # address: absolute address of the variable
# children: a dictionary of child elements # children: a dictionary of child elements
self.myVariables = [] self.myVariables = []
self.flat_list = []
self.top_dies = [decorate_die(CU.get_top_DIE(), i) for (i, CU) in enumerate(di._CUs)] self.top_dies = [decorate_die(CU.get_top_DIE(), i) for (i, CU) in enumerate(di._CUs)]
for top_die in self.top_dies: for top_die in self.top_dies:
@ -99,11 +100,10 @@ class Bear():
# Preload children # Preload children
load_children(top_die) load_children(top_die)
children_dies = [] children_dies = list()
for child_die in top_die._children: for child_die in top_die._children:
if child_die.tag == 'DW_TAG_variable': if child_die.tag == 'DW_TAG_variable':
# pprint(child_die)
entry = { entry = {
# Name should be on every element, if not set something so it can be printed # Name should be on every element, if not set something so it can be printed
'name': safe_DIE_name(child_die, '?') 'name': safe_DIE_name(child_die, '?')
@ -112,8 +112,6 @@ class Bear():
if 'DW_AT_location' in child_die.attributes: if 'DW_AT_location' in child_die.attributes:
if LocationParser.attribute_has_location(child_die.attributes['DW_AT_location'], child_die.cu['version']): if LocationParser.attribute_has_location(child_die.attributes['DW_AT_location'], child_die.cu['version']):
ll = self.parse_location(child_die, child_die.attributes['DW_AT_location']) ll = self.parse_location(child_die, child_die.attributes['DW_AT_location'])
# pprint(ll.loc_expr)
# pprint(self.dump_expr(child_die, ll.loc_expr))
lloc = self.dump_expr(child_die, ll.loc_expr) lloc = self.dump_expr(child_die, ll.loc_expr)
# print(hex(lloc[0].args[0])) # print(hex(lloc[0].args[0]))
entry['address'] = hex(lloc[0].args[0]) entry['address'] = hex(lloc[0].args[0])
@ -124,7 +122,7 @@ class Bear():
if 'DW_AT_type' in child_die.attributes: if 'DW_AT_type' in child_die.attributes:
typ_die = child_die.get_DIE_from_attribute('DW_AT_type') typ_die = child_die.get_DIE_from_attribute('DW_AT_type')
entry['type'] = self.resolve_type(typ_die) self.truly_resolve_type(entry, typ_die)
children_dies.append(entry) children_dies.append(entry)
@ -133,19 +131,16 @@ class Bear():
'children': children_dies 'children': children_dies
}) })
pprint(self.myVariables) def truly_resolve_type(self, entry, die_type):
def resolve_type(self, die_type):
if die_type.tag == 'DW_TAG_volatile_type': if die_type.tag == 'DW_TAG_volatile_type':
die_type = die_type.get_DIE_from_attribute('DW_AT_type') die_type = die_type.get_DIE_from_attribute('DW_AT_type')
entry = { entry['type'] = safe_DIE_name(die_type, '?')
# Name should be on every element, if not set something so it can be printed
'name': safe_DIE_name(die_type, '?')
}
if 'DW_AT_data_member_location' in die_type.attributes: if 'DW_AT_data_member_location' in die_type.attributes:
entry['offset'] = die_type.attributes['DW_AT_data_member_location'].value * 8 entry['offset'] = die_type.attributes['DW_AT_data_member_location'].value * 8
if 'address' in entry:
entry['address'] = hex(int(entry['address'], 16) + die_type.attributes['DW_AT_data_member_location'].value)
if 'DW_AT_type' in die_type.attributes and die_type.tag not in ['DW_TAG_base_type', 'DW_TAG_structure_type', 'DW_TAG_array_type']: if 'DW_AT_type' in die_type.attributes and die_type.tag not in ['DW_TAG_base_type', 'DW_TAG_structure_type', 'DW_TAG_array_type']:
# Check if the type is a redefinition of a base type # Check if the type is a redefinition of a base type
@ -156,192 +151,120 @@ class Bear():
die_type = die_type_test die_type = die_type_test
break break
if 'DW_AT_byte_size' in die_type.attributes:
entry['size_byte'] = die_type.attributes['DW_AT_byte_size'].value
if die_type.tag == 'DW_TAG_base_type': if die_type.tag == 'DW_TAG_base_type':
entry['type'] = safe_DIE_name(die_type, '?') real_type_name = safe_DIE_name(die_type, '?')
if real_type_name != '?' and real_type_name != entry['type']:
entry['type'] = '{name} ({real})'.format(name=entry['type'], real=safe_DIE_name(die_type, '?'))
elif die_type.tag == "DW_TAG_structure_type": elif die_type.tag == "DW_TAG_structure_type":
load_children(die_type) load_children(die_type)
child_dies = [] child_dies = []
child_offset = 0
child_offset_bit = 0
for child_die in die_type._children: for child_die in die_type._children:
child_entry = self.resolve_type(child_die) if 'DW_AT_type' in child_die.attributes:
typ_die = child_die.get_DIE_from_attribute('DW_AT_type')
child_entry = dict()
child_entry['name'] = safe_DIE_name(child_die, '?')
if 'DW_AT_data_bit_offset' in child_die.attributes:
child_offset_bit = child_die.attributes['DW_AT_data_bit_offset'].value
if child_offset_bit >= 8:
child_offset = child_offset + math.floor(child_offset_bit / 8)
child_offset_bit = child_offset_bit - math.floor(child_offset_bit / 8) * 8
if 'address' in entry:
child_entry['address'] = hex(int(entry['address'], 16) + child_offset)
self.truly_resolve_type(child_entry, typ_die)
if ('size_byte' in child_entry) and ('DW_AT_data_bit_offset' not in child_die.attributes):
child_offset = child_offset + child_entry['size_byte']
child_dies.append(child_entry) child_dies.append(child_entry)
entry['children'] = child_dies; entry['children'] = child_dies
elif die_type.tag == "DW_TAG_array_type": elif die_type.tag == "DW_TAG_array_type":
array_type = self.resolve_type(die_type.get_DIE_from_attribute('DW_AT_type')) self.truly_resolve_type(entry, die_type.get_DIE_from_attribute('DW_AT_type'))
load_children(die_type) load_children(die_type)
children_num = die_type._children[0].attributes['DW_AT_upper_bound'].value entry['number_of_elements'] = die_type._children[0].attributes['DW_AT_upper_bound'].value + 1
child_entries = []
for child in range(0, children_num + 1):
child_entry = array_type.copy()
child_entry['offset'] = array_type['size_bit'] * child
child_entries.append(child_entry)
entry['children'] = child_entries
elif die_type.tag == 'DW_TAG_union_type': elif die_type.tag == 'DW_TAG_union_type':
load_children(die_type) load_children(die_type)
child_entries = [] child_entries = []
for child_die in die_type._children: for child_die in die_type._children:
child_entry = self.resolve_type(child_die) if 'DW_AT_type' in child_die.attributes:
typ_die = child_die.get_DIE_from_attribute('DW_AT_type')
child_entry = dict()
child_entry['name'] = safe_DIE_name(child_die, '?')
if 'address' in entry:
child_entry['address'] = entry['address']
self.truly_resolve_type(child_entry, typ_die)
child_entries.append(child_entry) child_entries.append(child_entry)
entry['children'] = child_entries entry['children'] = child_entries
else: else:
eprint("Unsupported type:", die_type.tag) eprint("Unsupported type:", die_type.tag)
if 'DW_AT_byte_size' in die_type.attributes:
entry['size_bit'] = die_type.attributes['DW_AT_byte_size'].value * 8
return entry
def flatten_type(self, parent=None): def flatten_type(self, parent=None):
# Structure of resulting list of dictionaries
# address - The address
# name - The long name of a variable after out rolling the type
vars = []
# Iterate over CUs
# - name - filename
# - children - variables
for CU in self.myVariables: for CU in self.myVariables:
vars.append(CU['name'])
for child in CU['children']: for child in CU['children']:
if configuration["include_file_name"]: if configuration["include_file_name"]:
vars.append(self.flatten_child(child, CU['name'])) self.pettanko(child, CU['name'])
else: else:
vars.append(self.flatten_child(child)) self.pettanko(child)
return vars
def flatten_child(self, child, name='', address=0): def pettanko(self, entry : dict, a_parent_name : str = ""):
var = {} flat_entry = dict()
kids = [] if a_parent_name:
flat_entry['name'] = '{0}.{1}'.format(a_parent_name, entry['name'])
if name:
var['name'] = '{parent}.{child}'.format(parent=name, child=child['name'])
else: else:
var['name'] = child['name'] flat_entry['name'] = entry['name']
if address: if 'address' in entry:
var['address'] = address flat_entry['address'] = entry['address']
else:
var['address'] = child['address']
if 'children' in child: if 'size_byte' in entry:
for kid in child['children']: flat_entry['size_byte'] = entry['size_byte']
self.flatten_child(kid, var['name'], var['address']) if 'number_of_elements' in entry:
flat_entry['size_byte'] = flat_entry['size_byte'] * entry['number_of_elements']
if 'type' in child: if 'type' in entry:
self.flatten_child() flat_entry['type'] = entry['type']
return kids self.flat_list.append(flat_entry)
if 'children' in entry:
for kid in entry['children']:
self.pettanko(kid, flat_entry['name'])
if 'number_of_elements' in entry:
for index in range(0, entry['number_of_elements']):
kid = flat_entry.copy()
kid['name'] = '{0}[{1}]'.format(flat_entry['name'], index)
kid['address'] = hex(int(flat_entry['address'], 16) + entry['size_byte'] * index)
self.pettanko(kid)
kid_parent = self.flat_list[-1]
if 'children' in entry:
for kid_of_kid in entry['children']:
self.pettanko(kid_of_kid, kid_parent['name'])
def pretty_print(self): def pretty_print(self):
vars = [] for entry in self.flat_list:
# Iterate over CUs print('{address}\t{variable_name}'.format(address=entry['address'], variable_name=entry['name']))
# - name - filename
# - children - variables
for CU in self.myVariables:
vars.append(CU['name'])
for child in CU['children']:
self.pretty_child(child)
return vars
def pretty_child(self, child, prefix='', address=0):
name = ''
if 'children' in child:
pass
else:
pass
def print_top_DIE(self, die):
if die.tag == 'DW_TAG_variable':
name = safe_DIE_name(die)
if name:
typ_name = ''
if 'DW_AT_type' in die.attributes:
typ = die.get_DIE_from_attribute('DW_AT_type')
print(self.describe_type(typ))
# typ_name = safe_DIE_name(typ)
# if not typ_name:
# print (typ)
print('{name} {typ_name}'.format(name=name, typ_name=typ_name))
def print_DIE(self, die, prefix=''):
name = ''
# print(die)
if die.tag == 'DW_TAG_variable':
name = safe_DIE_name(die)
if name and 'DW_AT_type' in die.attributes:
typ = die.get_DIE_from_attribute('DW_AT_type')
if 'DW_AT_location' in die.attributes:
ll = self.parse_location(die, die.attributes['DW_AT_location'])
# if isinstance(ll, LocationExpr):
# print(self.dump_expr(die, ll.loc_expr))
self.print_DIE(typ, name)
return
# print(typ)
elif die.tag == 'DW_TAG_compile_unit':
name = safe_DIE_name(die, '.')
elif prefix and die.tag == 'DW_TAG_base_type':
name = safe_DIE_name(die)
elif prefix and die.tag == 'DW_TAG_const_type':
if 'DW_AT_type' in die.attributes:
typ = die.get_DIE_from_attribute('DW_AT_type')
self.print_DIE(typ, prefix)
return
elif prefix and die.tag == 'DW_TAG_array_type':
if 'DW_AT_type' in die.attributes:
typ = die.get_DIE_from_attribute('DW_AT_type')
name = prefix + '[]'
self.print_DIE(typ, name)
load_children(die)
if die._children:
for child in die._children:
print(child)
self.print_DIE(child, name)
return
elif prefix and die.tag == 'DW_TAG_volatile_type':
if 'DW_AT_type' in die.attributes:
typ = die.get_DIE_from_attribute('DW_AT_type')
self.print_DIE(typ, prefix)
return
elif prefix and die.tag == 'DW_TAG_typedef':
print(die.attributes["DW_AT_name"].value)
if 'DW_AT_type' in die.attributes:
typ = die.get_DIE_from_attribute('DW_AT_type')
name = prefix + '[]'
self.print_DIE(typ, name)
load_children(die)
if die._children:
for child in die._children:
print(child)
self.print_DIE(child, name)
elif prefix and die.tag == 'DW_TAG_enumeration_type':
# print(die.attributes["DW_AT_name"].value)
print ("mylittlepony")
print(die)
if 'DW_AT_type' in die.attributes:
typ = die.get_DIE_from_attribute('DW_AT_type')
name = prefix
self.print_DIE(typ, name)
load_children(die)
print (typ)
elif prefix:
print (prefix)
print(die)
if name:
if prefix:
print (prefix, name)
else:
print (name)
def parse_location(self, die, attr): def parse_location(self, die, attr):
di = die.dwarfinfo di = die.dwarfinfo
if di._locparser is None: if di._locparser is None:
di._locparser = LocationParser(di.location_lists()) di._locparser = LocationParser(di.location_lists())
return di._locparser.parse_from_attribute(attr, die.cu['version'], die = die) return di._locparser.parse_from_attribute(attr, die.cu['version'], die=die)
# Expr is an expression blob # Expr is an expression blob
# Returns a list of strings for ops # Returns a list of strings for ops
@ -365,13 +288,9 @@ def main():
monkeypatch() monkeypatch()
bear = Bear("/home/juraj/projects/Playground_C/build/playground_c") bear = Bear("/home/juraj/projects/Playground_C/build/playground_c")
vars = bear.flatten_type() bear.flatten_type()
pprint(vars) bear.pretty_print()
#bear = Bear("main.elf")
# bear = Bear("LED_Cube.elf")
# bear = Bear("serialplay")
pass
if __name__ == "__main__": if __name__ == "__main__":
main() main()