Skip to content

Commit 3181eed

Browse files
authored
DW_FORM_ref_sig8 support (#595)
* DW_FORM_ref_sig8 support * Nitpicks addressed * Minor fixes * More minor fixes
1 parent e405fed commit 3181eed

File tree

9 files changed

+78
-14
lines changed

9 files changed

+78
-14
lines changed

elftools/dwarf/datatype_cpp.py

+2
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ def DIE_is_ptr_to_member_struct(type_die):
229229

230230
def _strip_type_tag(die):
231231
"""Given a DIE with DW_TAG_foo_type, returns foo"""
232+
if isinstance(die.tag, int): # User-defined tag
233+
return ""
232234
return die.tag[7:-5]
233235

234236
def _array_subtype_size(sub):

elftools/dwarf/die.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ def get_DIE_from_attribute(self, name):
118118
elif attr.form in ('DW_FORM_ref_addr'):
119119
return self.cu.dwarfinfo.get_DIE_from_refaddr(attr.raw_value)
120120
elif attr.form in ('DW_FORM_ref_sig8'):
121-
# Implement search type units for matching signature
122-
raise NotImplementedError('%s (type unit by signature)' % attr.form)
121+
return self.cu.dwarfinfo.get_DIE_by_sig8(attr.raw_value)
123122
elif attr.form in ('DW_FORM_ref_sup4', 'DW_FORM_ref_sup8', 'DW_FORM_GNU_ref_alt'):
124123
if self.dwarfinfo.supplementary_dwarfinfo:
125124
return self.dwarfinfo.supplementary_dwarfinfo.get_DIE_from_refaddr(attr.raw_value)

elftools/dwarf/dwarfinfo.py

+41-7
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def __init__(self,
139139
self._cu_cache = []
140140
self._cu_offsets_map = []
141141

142-
# DWARF v4 type units by sig8 - OrderedDict created on Reference
142+
# DWARF v4 type units by sig8 - OrderedDict created when needed
143143
self._type_units_by_sig = None
144144

145145
@property
@@ -179,6 +179,32 @@ def get_DIE_from_refaddr(self, refaddr, cu=None):
179179
if cu is None:
180180
cu = self.get_CU_containing(refaddr)
181181
return cu.get_DIE_from_refaddr(refaddr)
182+
183+
def get_DIE_by_sig8(self, sig8):
184+
""" Find and return a DIE referenced by its type signature.
185+
sig8:
186+
The 8 byte signature (as a 64-bit unsigned integer)
187+
Returns the DIE with the given type signature by searching
188+
for the Type Unit with the matching signature then finding
189+
the DIE at the offset given by the type_die field in the
190+
Type Unit header.
191+
Signatures are an 64-bit unsigned integers computed by the
192+
DWARF producer as specified in the DWARF standard. Each
193+
Type Unit contains one signature and the offset to the
194+
corresponding DW_AT_type DIE in its unit header.
195+
Describing a type can generate several DIEs. By moving
196+
a DIE and its related DIEs to a Type Unit and generating
197+
a hash of the DIEs and attributes in a flattened form
198+
multiple Compile Units in a linked object can reference
199+
the same DIE in the overall DWARF structure.
200+
In DWARF v4 type units are identified by their appearance in the
201+
.debug_types section.
202+
"""
203+
self._parse_debug_types()
204+
tu = self._type_units_by_sig.get(sig8)
205+
if tu is None:
206+
raise KeyError("Signature %016x not found in .debug_types" % sig8)
207+
return tu._get_cached_DIE(tu.tu_offset + tu['type_offset'])
182208

183209
def get_CU_containing(self, refaddr):
184210
""" Find the CU that includes the given reference address in the
@@ -478,8 +504,8 @@ def _parse_TUs_iter(self, offset=0):
478504

479505
def _parse_debug_types(self):
480506
""" Check if the .debug_types section is previously parsed. If not,
481-
parse all TUs and store them in an OrderedDict using their unique
482-
64-bit signature as the key.
507+
parse all TUs and store them in an OrderedDict using their unique
508+
64-bit signature as the key.
483509
484510
See .get_TU_by_sig8().
485511
"""
@@ -490,9 +516,16 @@ def _parse_debug_types(self):
490516
if self.debug_types_sec is None:
491517
return
492518

493-
# Collect all Type Units in the .debug_types section for access using
494-
# their 8-byte unique signature
495-
for tu in self._parse_TUs_iter():
519+
# Parse all the Type Units in the types section for access by sig8
520+
offset = 0
521+
while offset < self.debug_types_sec.size:
522+
tu = self._parse_TU_at_offset(offset)
523+
# Compute the offset of the next TU in the section. The unit_length
524+
# field of the TU header contains its size not including the length
525+
# field itself.
526+
offset = (offset +
527+
tu['unit_length'] +
528+
tu.structs.initial_length_field_size())
496529
self._type_units_by_sig[tu['signature']] = tu
497530

498531
def _cached_CU_at_offset(self, offset):
@@ -583,7 +616,8 @@ def _parse_TU_at_offset(self, offset):
583616
dwarf_format = 64 if initial_length == 0xFFFFFFFF else 32
584617

585618
# Temporary structs for parsing the header
586-
# The structs for the rest of the TUs depend on the header data.
619+
# The structs for the rest of the TU depend on the header data.
620+
#
587621
tu_structs = DWARFStructs(
588622
little_endian=self.config.little_endian,
589623
dwarf_format=dwarf_format,

elftools/dwarf/enums.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@
9090
DW_TAG_skeleton_unit = 0x4a,
9191
DW_TAG_immutable_type = 0x4b,
9292

93-
93+
# Tags between 0x4080 and 0xffff are user-defined.
94+
# different implementations may overlap?
9495

9596
DW_TAG_lo_user = 0x4080,
9697
DW_TAG_GNU_template_template_param = 0x4106,
@@ -272,6 +273,8 @@
272273
DW_AT_MIPS_assumed_shape_dopetype = 0x2010,
273274
DW_AT_MIPS_assumed_size = 0x2011,
274275

276+
DW_AT_HP_opt_level = 0x2014,
277+
275278
DW_AT_sf_names = 0x2101,
276279
DW_AT_src_info = 0x2102,
277280
DW_AT_mac_info = 0x2103,

elftools/dwarf/typeunit.py

+16
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,22 @@ def iter_DIE_children(self, die):
185185

186186
cur_offset = child._terminator.offset + child._terminator.size
187187

188+
def get_DIE_from_refaddr(self, refaddr):
189+
""" Obtain a DIE contained in this CU from a reference.
190+
refaddr:
191+
The offset into the .debug_info section, which must be
192+
contained in this CU or a DWARFError will be raised.
193+
When using a reference class attribute with a form that is
194+
relative to the compile unit, add unit add the compile unit's
195+
.cu_addr before calling this function.
196+
"""
197+
# All DIEs are after the cu header and within the unit
198+
dwarf_assert(
199+
self.cu_die_offset <= refaddr < self.cu_offset + self.size,
200+
'refaddr %s not in DIE range of CU %s' % (refaddr, self.cu_offset))
201+
202+
return self._get_cached_DIE(refaddr)
203+
188204
#------ PRIVATE ------#
189205

190206
def __getitem__(self, name):

scripts/dwarfdump.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@ def _safe_DIE_linkage_name(die, default=None):
8484
def _desc_ref(attr, die, extra=''):
8585
if extra:
8686
extra = " \"%s\"" % extra
87+
if attr.form == 'DW_FORM_ref_addr':
88+
return "0x%016x%s" % (attr.value, extra)
89+
if attr.form == 'DW_FORM_ref_sig8':
90+
return "0x%016x" % attr.value
8791
# TODO: leading zeros on the addend to CU - sometimes present, sometimes not.
88-
# Check by the LLVM sources.
92+
# Check by the LLVM sources.
8993
return "cu + 0x%04x => {0x%08x}%s" % (
9094
attr.raw_value,
9195
die.cu.cu_offset + attr.raw_value,
@@ -225,7 +229,8 @@ def _arch(cu):
225229
return cu.dwarfinfo.config.machine_arch
226230

227231
def _desc_reg(reg_no, cu):
228-
return describe_reg_name(reg_no, _arch(cu), True).upper()
232+
reg_name = describe_reg_name(reg_no, _arch(cu), False)
233+
return reg_name.upper() if reg_name else ""
229234

230235
def _desc_operation(op, op_name, args, cu):
231236
# Not sure about regx(regno) and bregx(regno, offset)
@@ -346,7 +351,7 @@ def __init__(self, filename, file, output):
346351
self.elffile = ELFFile(file)
347352
self.output = output
348353
self._dwarfinfo = self.elffile.get_dwarf_info()
349-
arches = {"EM_386": "i386", "EM_X86_64": "x86-64", "EM_ARM": "littlearm", "EM_AARCH64": "littleaarch64", "EM_LOONGARCH": "loongarch", "EM_RISCV": "littleriscv", "EM_MIPS": "mips"}
354+
arches = {"EM_386": "i386", "EM_X86_64": "x86-64", "EM_ARM": "littlearm", "EM_AARCH64": "littleaarch64", "EM_LOONGARCH": "loongarch", "EM_RISCV": "littleriscv", "EM_MIPS": "mips", "EM_TI_C2000": "unknown"}
350355
arch = arches[self.elffile['e_machine']]
351356
bits = self.elffile.elfclass
352357
self._emitline("%s: file format elf%d-%s" % (filename, bits, arch))
@@ -387,7 +392,7 @@ def dump_info(self):
387392
if not die.is_null():
388393
self._emitline("0x%08x: %s [%d] %s %s" % (
389394
die.offset,
390-
die.tag,
395+
die.tag if isinstance(die.tag, str) else "DW_TAG_unknown_%x" % die.tag,
391396
die.abbrev_code,
392397
'*' if die.has_children else '',
393398
'(0x%08x)' % die.get_parent().offset if die.get_parent() is not None else ''))
@@ -540,6 +545,7 @@ def main(stream=None):
540545
del ENUM_DW_TAG["DW_TAG_template_value_param"]
541546
ENUM_DW_TAG['DW_TAG_template_type_parameter'] = 0x2f
542547
ENUM_DW_TAG['DW_TAG_template_value_parameter'] = 0x30
548+
del ENUM_DW_TAG['DW_TAG_lo_user'] # dwarfdump dumps it as unknown
543549

544550
with open(args.file, 'rb') as file:
545551
try:

test/run_readelf_tests.py

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ def run_test_on_file(filename, verbose=False, opt=None):
7878
# https://sourceware.org/bugzilla/show_bug.cgi?id=31973
7979
options.remove('--debug-dump=frames')
8080
options.remove('--debug-dump=frames-interp')
81+
# TODO: Stream parsing errors out with the .debug_aranges section
82+
# generated by IAR EWARM 9.20.4.
83+
# https://github.com/STMicroelectronics/STM32CubeWB/issues/109
84+
options.remove('--debug-dump=aranges')
8185

8286
for option in options:
8387
if verbose: testlog.info("..option='%s'" % option)
Binary file not shown.
58.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)