# Guided by the attributes listed in the abbreviation declaration, parse
# values from the stream.
- for name, form in abbrev_decl.iter_attr_specs():
+ for spec in abbrev_decl['attr_spec']:
+ form = spec.form
+ name = spec.name
attr_offset = self.stream.tell()
- raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream)
-
- value = self._translate_attr_value(form, raw_value)
+ # 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
+ else:
+ raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream)
+ value = self._translate_attr_value(form, raw_value)
self.attributes[name] = AttributeValue(
name=name,
form=form,
if form == 'DW_FORM_strp':
with preserve_stream_pos(self.stream):
value = self.dwarfinfo.get_string_from_table(raw_value)
+ elif form == 'DW_FORM_line_strp':
+ with preserve_stream_pos(self.stream):
+ value = self.dwarfinfo.get_string_from_linetable(raw_value)
elif form == 'DW_FORM_flag':
value = not raw_value == 0
elif form == 'DW_FORM_flag_present':
debug_pubtypes_sec,
debug_pubnames_sec,
debug_addr_sec,
- debug_str_offsets_sec):
+ debug_str_offsets_sec,
+ debug_line_str_sec):
""" config:
A DwarfConfig object
self.debug_loc_sec = debug_loc_sec
self.debug_ranges_sec = debug_ranges_sec
self.debug_line_sec = debug_line_sec
+ self.debug_line_str_sec = debug_line_str_sec
self.debug_pubtypes_sec = debug_pubtypes_sec
self.debug_pubnames_sec = debug_pubnames_sec
"""
return parse_cstring_from_stream(self.debug_str_sec.stream, offset)
+ def get_string_from_linetable(self, offset):
+ """ Obtain a string from the string table section, given an offset
+ relative to the section.
+ """
+ return parse_cstring_from_stream(self.debug_line_str_sec.stream, offset)
+
def line_program_for_CU(self, CU):
""" Given a CU object, fetch the line program it points to from the
.debug_line section.
obj.name == 'DW_AT_null' and obj.form == 'DW_FORM_null',
Struct('attr_spec',
Enum(self.Dwarf_uleb128('name'), **ENUM_DW_AT),
- Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM))))
+ Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM),
+ If(lambda ctx: ctx['form'] == 'DW_FORM_implicit_const',
+ self.Dwarf_sleb128('value')))))
def _create_dw_form(self):
self.Dwarf_dw_form = dict(
DW_FORM_string=CString(''),
DW_FORM_strp=self.Dwarf_offset(''),
+ DW_FORM_line_strp=self.Dwarf_offset(''),
DW_FORM_strx1=self.Dwarf_uint8(''),
DW_FORM_strx2=self.Dwarf_uint16(''),
# DW_FORM_strx3=self.Dwarf_uint24(''), # TODO
section_names = ('.debug_info', '.debug_aranges', '.debug_abbrev',
'.debug_str', '.debug_line', '.debug_frame',
'.debug_loc', '.debug_ranges', '.debug_pubtypes',
- '.debug_pubnames', '.debug_addr', '.debug_str_offsets')
+ '.debug_pubnames', '.debug_addr',
+ '.debug_str_offsets', '.debug_line_str')
+
compressed = bool(self.get_section_by_name('.zdebug_info'))
if compressed:
debug_str_sec_name, debug_line_sec_name, debug_frame_sec_name,
debug_loc_sec_name, debug_ranges_sec_name, debug_pubtypes_name,
debug_pubnames_name, debug_addr_name, debug_str_offsets_name,
- eh_frame_sec_name) = section_names
+ debug_line_str_name, eh_frame_sec_name) = section_names
debug_sections = {}
for secname in section_names:
debug_pubnames_sec=debug_sections[debug_pubnames_name],
debug_addr_sec=debug_sections[debug_addr_name],
debug_str_offsets_sec=debug_sections[debug_str_offsets_name],
+ debug_line_str_sec=debug_sections[debug_line_str_name]
)
def has_ehabi_info(self):
--- /dev/null
+# The dwarf_v5_forms.debug file was generated as follows, using gcc 11.2.0 on
+# an x86_64 machine.
+# $ cat dwarf_v5_forms.c
+# int main();
+# {
+# char ** val;
+# return 0;
+# }
+# $ gcc -O0 -gdwarf-5 dwarf_v5_forms.c -o dwarf_v5_forms.debug
+# $ strip --only-keep-debug dwarf_v5_forms.debug
+import unittest
+import os
+
+
+from elftools.elf.elffile import ELFFile
+
+class TestDWARFV5_forms(unittest.TestCase):
+
+ def test_DW_FORM_implicit_const(self):
+ path = os.path.join('test', 'testfiles_for_unittests',
+ 'dwarf_v5_forms.debug')
+ with open(path, 'rb') as f:
+ elffile = ELFFile(f)
+ dwarfinfo = elffile.get_dwarf_info()
+ # File is very small, so load all DIEs.
+ dies = []
+ for cu in dwarfinfo.iter_CUs():
+ dies.extend(cu.iter_DIEs())
+ # Locate the "var" DIE.
+ for die in dies:
+ # There should be only one
+ if (die.tag == "DW_TAG_variable" and
+ die.attributes["DW_AT_name"].value == b'val'):
+ # In the dwarfinfo, it's type is sized using a
+ # DW_FORM_implicit_const: check it is parsed correctly
+ break
+ dietype = cu.get_DIE_from_refaddr(die.attributes["DW_AT_type"].value)
+ byte_size_attr = dietype.attributes["DW_AT_byte_size"]
+ self.assertEqual(byte_size_attr.form, "DW_FORM_implicit_const")
+ self.assertEqual(byte_size_attr.value, 8)
+
+ def test_DW_FORM_linestrp(self):
+ path = os.path.join('test', 'testfiles_for_unittests',
+ 'dwarf_v5_forms.debug')
+ with open(path, 'rb') as f:
+ elffile = ELFFile(f)
+ dwarfinfo = elffile.get_dwarf_info()
+ cu = next(dwarfinfo.iter_CUs())
+ top_die = cu.get_top_DIE()
+ name_attr = top_die.attributes["DW_AT_name"]
+ self.assertEqual(name_attr.form, "DW_FORM_line_strp")
+ self.assertEqual(name_attr.value, b"dwarf_v5_forms.c")
debug_pubnames_sec = None,
debug_addr_sec=None,
debug_str_offsets_sec=None,
+ debug_line_str_sec=None,
)
CUs = [cu for cu in di.iter_CUs()]