From 9a7f1d21fde8be8022a1ebb5ddf19b31f707b2d3 Mon Sep 17 00:00:00 2001 From: Juraj Oravec Date: Fri, 10 May 2024 23:34:00 +0200 Subject: [PATCH] Make it work (somewhat) Signed-off-by: Juraj Oravec --- main.py | 267 ++++++++++++++++++++------------------------------------ 1 file changed, 93 insertions(+), 174 deletions(-) diff --git a/main.py b/main.py index 4a0ef00..eb53385 100644 --- a/main.py +++ b/main.py @@ -1,13 +1,12 @@ #!/bin/python import sys +import math from bear import formats from elftools.dwarf.locationlists import LocationParser, LocationExpr from elftools.dwarf.dwarf_expr import DWARFExprParser, DWARFExprOp, DW_OP_opcode2name from bear.dwarfone import DWARFExprParserV1 -from pprint import pprint - configuration = { "include_file_name": False, @@ -31,6 +30,7 @@ def decorate_die(die, i): die._children = None return die + def load_children(parent_die): # Load and cache child DIEs in the parent DIE, if necessary # Assumes the check if the DIE has children has been already performed @@ -47,8 +47,7 @@ def load_children(parent_die): 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 @@ -64,6 +63,7 @@ class Bear(): # Some cached top level stuff # Notably, iter_CUs doesn't cache di._ranges = None # Loaded on first use + def decorate_cu(cu, i): cu._i = i cu._lineprogram = None @@ -80,7 +80,7 @@ class Bear(): self.dwarfinfo = di self.filename = filename - except AssertionError as ass: # Covers exeptions during parsing + except AssertionError as ass: # Covers exeptions during parsing raise DWARFParseError(ass, di) # A list containing variables in a disctionary @@ -91,6 +91,7 @@ class Bear(): # address: absolute address of the variable # children: a dictionary of child elements self.myVariables = [] + self.flat_list = [] self.top_dies = [decorate_die(CU.get_top_DIE(), i) for (i, CU) in enumerate(di._CUs)] for top_die in self.top_dies: @@ -99,11 +100,10 @@ class Bear(): # Preload children load_children(top_die) - children_dies = [] + children_dies = list() for child_die in top_die._children: if child_die.tag == 'DW_TAG_variable': - # pprint(child_die) entry = { # Name should be on every element, if not set something so it can be printed 'name': safe_DIE_name(child_die, '?') @@ -112,8 +112,6 @@ class Bear(): if 'DW_AT_location' in child_die.attributes: 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']) - # pprint(ll.loc_expr) - # pprint(self.dump_expr(child_die, ll.loc_expr)) lloc = self.dump_expr(child_die, ll.loc_expr) # print(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: 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) @@ -133,19 +131,16 @@ class Bear(): 'children': children_dies }) - pprint(self.myVariables) - - def resolve_type(self, die_type): + def truly_resolve_type(self, entry, die_type): if die_type.tag == 'DW_TAG_volatile_type': die_type = die_type.get_DIE_from_attribute('DW_AT_type') - entry = { - # Name should be on every element, if not set something so it can be printed - 'name': safe_DIE_name(die_type, '?') - } + entry['type'] = safe_DIE_name(die_type, '?') if 'DW_AT_data_member_location' in die_type.attributes: 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']: # Check if the type is a redefinition of a base type @@ -156,192 +151,120 @@ class Bear(): die_type = die_type_test 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': - 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": load_children(die_type) child_dies = [] + child_offset = 0 + child_offset_bit = 0 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) - entry['children'] = child_dies; + entry['children'] = child_dies 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) - children_num = die_type._children[0].attributes['DW_AT_upper_bound'].value - 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 + entry['number_of_elements'] = die_type._children[0].attributes['DW_AT_upper_bound'].value + 1 elif die_type.tag == 'DW_TAG_union_type': load_children(die_type) child_entries = [] 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) entry['children'] = child_entries else: 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): - # 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: - vars.append(CU['name']) - for child in CU['children']: if configuration["include_file_name"]: - vars.append(self.flatten_child(child, CU['name'])) + self.pettanko(child, CU['name']) else: - vars.append(self.flatten_child(child)) - return vars + self.pettanko(child) - def flatten_child(self, child, name='', address=0): - var = {} - kids = [] - - if name: - var['name'] = '{parent}.{child}'.format(parent=name, child=child['name']) + def pettanko(self, entry : dict, a_parent_name : str = ""): + flat_entry = dict() + if a_parent_name: + flat_entry['name'] = '{0}.{1}'.format(a_parent_name, entry['name']) else: - var['name'] = child['name'] + flat_entry['name'] = entry['name'] - if address: - var['address'] = address - else: - var['address'] = child['address'] + if 'address' in entry: + flat_entry['address'] = entry['address'] - if 'children' in child: - for kid in child['children']: - self.flatten_child(kid, var['name'], var['address']) + if 'size_byte' in entry: + flat_entry['size_byte'] = entry['size_byte'] + if 'number_of_elements' in entry: + flat_entry['size_byte'] = flat_entry['size_byte'] * entry['number_of_elements'] - if 'type' in child: - self.flatten_child() + if 'type' in entry: + 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): - vars = [] - # Iterate over CUs - # - 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) + for entry in self.flat_list: + print('{address}\t{variable_name}'.format(address=entry['address'], variable_name=entry['name'])) def parse_location(self, die, attr): di = die.dwarfinfo if di._locparser is None: 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 # Returns a list of strings for ops @@ -365,13 +288,9 @@ def main(): monkeypatch() bear = Bear("/home/juraj/projects/Playground_C/build/playground_c") - vars = bear.flatten_type() - pprint(vars) + bear.flatten_type() + bear.pretty_print() - #bear = Bear("main.elf") - # bear = Bear("LED_Cube.elf") - # bear = Bear("serialplay") - pass if __name__ == "__main__": main()