Make it work (somewhat)
Signed-off-by: Juraj Oravec <jurajoravec@mailo.com>
This commit is contained in:
parent
3c6b845948
commit
9a7f1d21fd
267
main.py
267
main.py
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user