Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ranges autotest take 2 #505

Merged
merged 6 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions elftools/dwarf/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
DW_CC_normal = 0x1
DW_CC_program = 0x2
DW_CC_nocall = 0x3
DW_CC_pass_by_reference = 0x4
DW_CC_pass_by_valuee = 0x5


# Ordering
Expand Down
2 changes: 2 additions & 0 deletions elftools/dwarf/descriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ def _describe_attr_block(attr, die, section_offset):
DW_CC_normal: '(normal)',
DW_CC_program: '(program)',
DW_CC_nocall: '(nocall)',
DW_CC_pass_by_reference: '(pass by ref)',
DW_CC_pass_by_valuee: '(pass by value)',
}

_DESCR_DW_ORD = {
Expand Down
5 changes: 5 additions & 0 deletions elftools/dwarf/ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def iter_CU_range_lists_ex(self, cu):
section dumper should check if one is present.
"""
return self._rnglists.iter_CU_range_lists_ex(cu)

def translate_v5_entry(self, entry, cu):
"""Forwards a V5 entry translation request to the V5 section
"""
return self._rnglists.translate_v5_entry(entry, cu)

class RangeLists(object):
""" A single range list is a Python list consisting of RangeEntry or
Expand Down
94 changes: 57 additions & 37 deletions scripts/readelf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,18 @@ def _dump_debug_ranges(self):
else:
self._dump_debug_rangesection(di, range_lists_sec)

def _dump_debug_rnglists_CU_header(self, cu):
self._emitline(' Table at Offset: %s:' % self._format_hex(cu.cu_offset, alternate=True))
self._emitline(' Length: %s' % self._format_hex(cu.unit_length, alternate=True))
self._emitline(' DWARF version: %d' % cu.version)
self._emitline(' Address size: %d' % cu.address_size)
self._emitline(' Segment size: %d' % cu.segment_selector_size)
self._emitline(' Offset entries: %d\n' % cu.offset_count)
if cu.offsets and len(cu.offsets):
self._emitline(' Offsets starting at 0x%x:' % cu.offset_table_offset)
for i_offset in enumerate(cu.offsets):
self._emitline(' [%6d] 0x%x' % i_offset)

def _dump_debug_rangesection(self, di, range_lists_sec):
# Last amended to match readelf 2.41
ver5 = range_lists_sec.version >= 5
Expand All @@ -1639,53 +1651,48 @@ def _dump_debug_rangesection(self, di, range_lists_sec):
addr_width = addr_size * 2 # In hex digits, 8 or 16
line_template = " %%08x %%0%dx %%0%dx %%s" % (addr_width, addr_width)
base_template = " %%08x %%0%dx (base address)" % (addr_width)
base_template_indexed = " %%08x %%0%dx (base address index) %%0%dx (base address)" % (addr_width, addr_width)

# In order to determine the base address of the range
# We need to know the corresponding CU.
cu_map = {die.attributes['DW_AT_ranges'].value : cu # Range list offset => CU
for cu in di.iter_CUs()
for die in cu.iter_DIEs()
if 'DW_AT_ranges' in die.attributes}

if ver5: # Dump by CUs - unsure at this point what does readelf do, ranges dump is buggy in 2.41
self._emitline('Contents of the %s section:\n\n\n' % section_name)
for cu in range_lists_sec.iter_CUs():
self._emitline(' Table at Offset: %s:' % self._format_hex(cu.cu_offset, alternate=True))
self._emitline(' Length: %s' % self._format_hex(cu.unit_length, alternate=True))
self._emitline(' DWARF version: %d' % cu.version)
self._emitline(' Address size: %d' % cu.address_size)
self._emitline(' Segment size: %d' % cu.segment_selector_size)
self._emitline(' Offset entries: %d\n' % cu.offset_count)
# Is the offset table dumped too?
for (i, range_list) in enumerate(range_lists_sec.iter_CU_range_lists_ex(cu)):
list_offset = range_list[0].entry_offset
range_list = list(range_lists_sec.translate_v5_entry(entry, cu_map[list_offset]) for entry in range_list)
self._emitline(' Offset: %s, Index: %d' % (self._format_hex(list_offset, alternate=True), i))
self._emitline(' Offset Begin End')
self._dump_rangelist(range_list, cu_map, ver5, line_template, base_template)
else: # Dump by DIE reference offset
range_lists = list(range_lists_sec.iter_range_lists())
if len(range_lists) == 0:
# Present but empty ranges section - readelf outputs a message
self._emitline("\nSection '%s' has no debugging data." % section_name)
return

self._emitline('Contents of the %s section:\n\n\n' % section_name)
if 'DW_AT_ranges' in die.attributes}

rcus = list(range_lists_sec.iter_CUs()) if ver5 else None
rcu_index = 0
next_rcu_offset = 0

range_lists = list(range_lists_sec.iter_range_lists())
if len(range_lists) == 0:
# Present but empty ranges section - readelf outputs a message
self._emitline("\nSection '%s' has no debugging data." % section_name)
return

self._emitline('Contents of the %s section:\n\n\n' % section_name)
if not ver5:
self._emitline(' Offset Begin End')

for range_list in range_lists:
if len(range_list) == 0: # working around a bogus behavior in readelf 2.41
# No entries means no offset. Dirty hack: peek the stream position
range_list_offset = range_lists_sec.stream.tell() - self._dwarfinfo.config.default_address_size*2
self._emitline(' %08x <End of list>' % (range_list_offset))
else:
self._dump_rangelist(range_list, cu_map, ver5, line_template, base_template)
for range_list in range_lists:
# Emit CU headers before the curernt rangelist
if ver5 and range_list[0].entry_offset > next_rcu_offset:
while range_list[0].entry_offset > next_rcu_offset:
rcu = rcus[rcu_index]
self._dump_debug_rnglists_CU_header(rcu)
next_rcu_offset = rcu.offset_after_length + rcu.unit_length
rcu_index += 1
self._emitline(' Offset Begin End')
self._dump_rangelist(range_list, cu_map, ver5, line_template, base_template, base_template_indexed, range_lists_sec)

# TODO: trailing empty CUs, if any?

def _dump_rangelist(self, range_list, cu_map, ver5, line_template, base_template):
def _dump_rangelist(self, range_list, cu_map, ver5, line_template, base_template, base_template_indexed, range_lists_sec):
# Weird discrepancy in binutils: for DWARFv5 it outputs entry offset,
# for DWARF<=4 list offset.
first = range_list[0]
base_ip = _get_cu_base(cu_map[first.entry_offset])
raw_v5_rangelist = None
for entry in range_list:
if isinstance(entry, RangeEntry):
postfix = ' (start == end)' if entry.begin_offset == entry.end_offset else ''
Expand All @@ -1696,9 +1703,22 @@ def _dump_rangelist(self, range_list, cu_map, ver5, line_template, base_template
postfix))
elif isinstance(entry,RangeBaseAddressEntry):
base_ip = entry.base_address
self._emitline(base_template % (
entry.entry_offset if ver5 else first.entry_offset,
entry.base_address))
# V5 base entries with index are reported differently in readelf - need to go back to the raw V5 format
# Maybe other subtypes too, but no such cases in the test corpus
raw_v5_entry = None
if ver5:
if not raw_v5_rangelist:
raw_v5_rangelist = range_lists_sec.get_range_list_at_offset_ex(range_list[0].entry_offset)
raw_v5_entry = next(re for re in raw_v5_rangelist if re.entry_offset == entry.entry_offset)
if raw_v5_entry and raw_v5_entry.entry_type == 'DW_RLE_base_addressx':
self._emitline(base_template_indexed % (
entry.entry_offset,
raw_v5_entry.index,
entry.base_address))
else:
self._emitline(base_template % (
entry.entry_offset if ver5 else first.entry_offset,
entry.base_address))
else:
raise NotImplementedError("Unknown object in a range list")
last = range_list[-1]
Expand Down
Binary file modified test/external_tools/readelf
Binary file not shown.
5 changes: 0 additions & 5 deletions test/run_readelf_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ def run_test_on_file(filename, verbose=False, opt=None):
else:
options = [opt]

# TODO(sevaa): excluding two files from the --debug-dump=Ranges test until the maintainers
# of GNU binutils fix https://sourceware.org/bugzilla/show_bug.cgi?id=30781
if filename.endswith('dwarf_test_versions_mix.elf') or filename.endswith('dwarf_v5ops.so.elf'):
options.remove('--debug-dump=Ranges')

for option in options:
if verbose: testlog.info("..option='%s'" % option)

Expand Down