From 9ffa0b515b9a24495e81b36fcc698c2376af27de Mon Sep 17 00:00:00 2001 From: Seva Alekseyev Date: Wed, 28 Jun 2023 22:31:30 -0400 Subject: [PATCH] Reporting the real attribute form for DW_FORM_indirect (#475) * Reporting the real attribute form for DW_FORM_indirect * Fixes * Unit test * Comments * Typo --------- Co-authored-by: Seva Alekseyev --- elftools/dwarf/die.py | 52 ++++++++++++++------ test/test_dwarf_formindirect.py | 27 ++++++++++ test/testfiles_for_unittests/gmtime_r.o.elf | Bin 0 -> 22016 bytes 3 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 test/test_dwarf_formindirect.py create mode 100644 test/testfiles_for_unittests/gmtime_r.o.elf diff --git a/elftools/dwarf/die.py b/elftools/dwarf/die.py index ef6d908..2b18a50 100755 --- a/elftools/dwarf/die.py +++ b/elftools/dwarf/die.py @@ -35,8 +35,12 @@ from .dwarf_util import _resolve_via_offset_table, _get_base_offset # Offset of this attribute's value in the stream (absolute offset, relative # the beginning of the whole stream) # +# indirection_length: +# If the form of the attribute is DW_FORM_indirect, the form will contain +# the resolved form, and this will contain the length of the indirection chain. +# 0 means no indirection. AttributeValue = namedtuple( - 'AttributeValue', 'name form value raw_value offset') + 'AttributeValue', 'name form value raw_value offset indirection_length') class DIE(object): @@ -244,11 +248,16 @@ class DIE(object): form = spec.form name = spec.name attr_offset = self.stream.tell() + indirection_length = 0 # Special case here: the attribute value is stored in the attribute # definition in the abbreviation spec, not in the DIE itself. if form == 'DW_FORM_implicit_const': value = spec.value raw_value = value + # Another special case: the attribute value is a form code followed by the real value in that form + elif form == 'DW_FORM_indirect': + (form, raw_value, indirection_length) = self._resolve_indirect() + value = self._translate_attr_value(form, raw_value) else: raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream) value = self._translate_attr_value(form, raw_value) @@ -257,10 +266,34 @@ class DIE(object): form=form, value=value, raw_value=raw_value, - offset=attr_offset) + offset=attr_offset, + indirection_length = indirection_length) self.size = self.stream.tell() - self.offset + def _resolve_indirect(self): + # Supports arbitrary indirection nesting (the standard doesn't prohibit that). + # Expects the stream to be at the real form. + # Returns (form, raw_value, length). + structs = self.cu.structs + length = 1 + real_form_code = struct_parse(structs.Dwarf_uleb128(''), self.stream) # Numeric form code + while True: + try: + real_form = DW_FORM_raw2name[real_form_code] # Form name or exception if bogus code + except KeyError as err: + raise DWARFError('Found DW_FORM_indirect with unknown real form 0x%x' % real_form_code) + + raw_value = struct_parse(structs.Dwarf_dw_form[real_form], self.stream) + + if real_form != 'DW_FORM_indirect': # Happy path: one level of indirection + return (real_form, raw_value, length) + else: # Indirection cascade + length += 1 + real_form_code = raw_value + # And continue parsing + # No explicit infinite loop guard because the stream will end eventually + def _translate_attr_value(self, form, raw_value): """ Translate a raw attr value according to the form """ @@ -286,18 +319,6 @@ class DIE(object): value = not raw_value == 0 elif form == 'DW_FORM_flag_present': value = True - elif form == 'DW_FORM_indirect': - try: - form = DW_FORM_raw2name[raw_value] - except KeyError as err: - raise DWARFError( - 'Found DW_FORM_indirect with unknown raw_value=' + - str(raw_value)) - - raw_value = struct_parse( - self.cu.structs.Dwarf_dw_form[form], self.stream) - # Let's hope this doesn't get too deep :-) - return self._translate_attr_value(form, raw_value) elif form in ('DW_FORM_addrx', 'DW_FORM_addrx1', 'DW_FORM_addrx2', 'DW_FORM_addrx3', 'DW_FORM_addrx4') and translate_indirect: value = self.cu.dwarfinfo.get_addr(self.cu, raw_value) elif form in ('DW_FORM_strx', 'DW_FORM_strx1', 'DW_FORM_strx2', 'DW_FORM_strx3', 'DW_FORM_strx4') and translate_indirect: @@ -333,4 +354,5 @@ class DIE(object): form=attr.form, value=self._translate_attr_value(attr.form, attr.raw_value), raw_value=attr.raw_value, - offset=attr.offset) + offset=attr.offset, + indirection_length=attr.indirection_length) diff --git a/test/test_dwarf_formindirect.py b/test/test_dwarf_formindirect.py new file mode 100644 index 0000000..6c8a4b0 --- /dev/null +++ b/test/test_dwarf_formindirect.py @@ -0,0 +1,27 @@ +#------------------------------------------------------------------------------- +# elftools tests +# +# Seva Alekseyev (sevaa@sprynet.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +import unittest +import os + +from elftools.elf.elffile import ELFFile + +class TestFormIndirect(unittest.TestCase): + def test_formindirect(self): + path = os.path.join('test', 'testfiles_for_unittests', + 'gmtime_r.o.elf') + with open(path, 'rb') as f: + elffile = ELFFile(f) + dwarfinfo = elffile.get_dwarf_info(follow_links=False) + cu = next(dwarfinfo.iter_CUs()) + # That DIE in that binary has an attribute with form DW_FORM_indirect + die = next(die for die in cu.iter_DIEs() if die.tag == 'DW_TAG_pointer_type') + attr = die.attributes["DW_AT_type"] + self.assertEqual(attr.form, "DW_FORM_ref2") # That's the real form + self.assertEqual(attr.indirection_length, 1) # But the fact of indirection is captured + +if __name__ == '__main__': + unittest.main() diff --git a/test/testfiles_for_unittests/gmtime_r.o.elf b/test/testfiles_for_unittests/gmtime_r.o.elf new file mode 100644 index 0000000000000000000000000000000000000000..668f7ed715ee6beef6c2d30cac3bfdde819eb2ab GIT binary patch literal 22016 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