From: Seva Alekseyev Date: Mon, 23 Mar 2020 14:16:01 +0000 (-0400) Subject: Support for --debug-dump=loc in readelf.py and in the test (#304) X-Git-Tag: v0.27~33 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=26973296b42c78d7438f9e81ef48edc3d398cca6;p=pyelftools.git Support for --debug-dump=loc in readelf.py and in the test (#304) --- diff --git a/elftools/dwarf/descriptions.py b/elftools/dwarf/descriptions.py index 29f818f..a7a7599 100644 --- a/elftools/dwarf/descriptions.py +++ b/elftools/dwarf/descriptions.py @@ -622,5 +622,7 @@ class ExprDumper(object): return "%s: %d <0x%x>" % (opcode_name, args[0], args[1] + cu_offset) elif opcode_name == 'DW_OP_GNU_const_type': return "%s: <0x%x> %d byte block: %s " % (opcode_name, args[0] + cu_offset, len(args[1]), ' '.join("%x" % b for b in args[1])) + elif opcode_name == 'DW_OP_GNU_regval_type': + return "%s: %d (%s) <0x%x>" % (opcode_name, args[0], describe_reg_name(args[0], _MACHINE_ARCH), args[1] + cu_offset) else: return '' % opcode_name diff --git a/elftools/dwarf/locationlists.py b/elftools/dwarf/locationlists.py index 2f8c51e..a503e43 100644 --- a/elftools/dwarf/locationlists.py +++ b/elftools/dwarf/locationlists.py @@ -12,8 +12,8 @@ from collections import namedtuple from ..common.utils import struct_parse LocationExpr = namedtuple('LocationExpr', 'loc_expr') -LocationEntry = namedtuple('LocationEntry', 'begin_offset end_offset loc_expr') -BaseAddressEntry = namedtuple('BaseAddressEntry', 'base_address') +LocationEntry = namedtuple('LocationEntry', 'entry_offset begin_offset end_offset loc_expr') +BaseAddressEntry = namedtuple('BaseAddressEntry', 'entry_offset base_address') class LocationLists(object): """ A single location list is a Python list consisting of LocationEntry or @@ -46,6 +46,7 @@ class LocationLists(object): def _parse_location_list_from_stream(self): lst = [] while True: + entry_offset = self.stream.tell() begin_offset = struct_parse( self.structs.Dwarf_target_addr(''), self.stream) end_offset = struct_parse( @@ -55,7 +56,7 @@ class LocationLists(object): break elif begin_offset == self._max_addr: # Base address selection entry - lst.append(BaseAddressEntry(base_address=end_offset)) + lst.append(BaseAddressEntry(entry_offset=entry_offset, base_address=end_offset)) else: # Location list entry expr_len = struct_parse( @@ -64,6 +65,7 @@ class LocationLists(object): self.stream) for i in range(expr_len)] lst.append(LocationEntry( + entry_offset=entry_offset, begin_offset=begin_offset, end_offset=end_offset, loc_expr=loc_expr)) diff --git a/examples/reference_output/dwarf_location_info.out b/examples/reference_output/dwarf_location_info.out index 9e1fe8e..01c8933 100644 --- a/examples/reference_output/dwarf_location_info.out +++ b/examples/reference_output/dwarf_location_info.out @@ -5,9 +5,9 @@ Processing file: ./examples/sample_exe64.elf (DW_OP_addr: 400608) Found a compile unit at offset 258, length 156 DIE DW_TAG_subprogram. attr DW_AT_frame_base. - LocationEntry(begin_offset=0, end_offset=1, loc_expr=[119, 8]) <<(DW_OP_breg7 (rsp): 8)>> - LocationEntry(begin_offset=1, end_offset=4, loc_expr=[119, 16]) <<(DW_OP_breg7 (rsp): 16)>> - LocationEntry(begin_offset=4, end_offset=43, loc_expr=[118, 16]) <<(DW_OP_breg6 (rbp): 16)>> + LocationEntry(entry_offset=0, begin_offset=0, end_offset=1, loc_expr=[119, 8]) <<(DW_OP_breg7 (rsp): 8)>> + LocationEntry(entry_offset=20, begin_offset=1, end_offset=4, loc_expr=[119, 16]) <<(DW_OP_breg7 (rsp): 16)>> + LocationEntry(entry_offset=40, begin_offset=4, end_offset=43, loc_expr=[118, 16]) <<(DW_OP_breg6 (rbp): 16)>> DIE DW_TAG_formal_parameter. attr DW_AT_location. (DW_OP_fbreg: -20) DIE DW_TAG_formal_parameter. attr DW_AT_location. @@ -18,16 +18,16 @@ Processing file: ./examples/sample_exe64.elf DIE DW_TAG_subprogram. attr DW_AT_frame_base. (DW_OP_breg7 (rsp): 8) DIE DW_TAG_subprogram. attr DW_AT_frame_base. - LocationEntry(begin_offset=16, end_offset=64, loc_expr=[119, 8]) <<(DW_OP_breg7 (rsp): 8)>> - LocationEntry(begin_offset=64, end_offset=153, loc_expr=[119, 192, 0]) <<(DW_OP_breg7 (rsp): 64)>> + LocationEntry(entry_offset=76, begin_offset=16, end_offset=64, loc_expr=[119, 8]) <<(DW_OP_breg7 (rsp): 8)>> + LocationEntry(entry_offset=96, begin_offset=64, end_offset=153, loc_expr=[119, 192, 0]) <<(DW_OP_breg7 (rsp): 64)>> DIE DW_TAG_formal_parameter. attr DW_AT_location. - LocationEntry(begin_offset=16, end_offset=85, loc_expr=[85]) <<(DW_OP_reg5 (rdi))>> - LocationEntry(begin_offset=85, end_offset=143, loc_expr=[94]) <<(DW_OP_reg14 (r14))>> + LocationEntry(entry_offset=133, begin_offset=16, end_offset=85, loc_expr=[85]) <<(DW_OP_reg5 (rdi))>> + LocationEntry(entry_offset=152, begin_offset=85, end_offset=143, loc_expr=[94]) <<(DW_OP_reg14 (r14))>> DIE DW_TAG_formal_parameter. attr DW_AT_location. - LocationEntry(begin_offset=16, end_offset=85, loc_expr=[84]) <<(DW_OP_reg4 (rsi))>> - LocationEntry(begin_offset=85, end_offset=138, loc_expr=[93]) <<(DW_OP_reg13 (r13))>> + LocationEntry(entry_offset=187, begin_offset=16, end_offset=85, loc_expr=[84]) <<(DW_OP_reg4 (rsi))>> + LocationEntry(entry_offset=206, begin_offset=85, end_offset=138, loc_expr=[93]) <<(DW_OP_reg13 (r13))>> DIE DW_TAG_formal_parameter. attr DW_AT_location. - LocationEntry(begin_offset=16, end_offset=85, loc_expr=[81]) <<(DW_OP_reg1 (rdx))>> - LocationEntry(begin_offset=85, end_offset=133, loc_expr=[92]) <<(DW_OP_reg12 (r12))>> + LocationEntry(entry_offset=241, begin_offset=16, end_offset=85, loc_expr=[81]) <<(DW_OP_reg1 (rdx))>> + LocationEntry(entry_offset=260, begin_offset=85, end_offset=133, loc_expr=[92]) <<(DW_OP_reg12 (r12))>> DIE DW_TAG_variable. attr DW_AT_location. - LocationEntry(begin_offset=92, end_offset=123, loc_expr=[83]) <<(DW_OP_reg3 (rbx))>> + LocationEntry(entry_offset=295, begin_offset=92, end_offset=123, loc_expr=[83]) <<(DW_OP_reg3 (rbx))>> diff --git a/scripts/readelf.py b/scripts/readelf.py index 0c91228..f9750e7 100755 --- a/scripts/readelf.py +++ b/scripts/readelf.py @@ -55,10 +55,11 @@ from elftools.dwarf.dwarfinfo import DWARFInfo from elftools.dwarf.descriptions import ( describe_reg_name, describe_attr_value, set_global_machine_arch, describe_CFI_instructions, describe_CFI_register_rule, - describe_CFI_CFA_rule, + describe_CFI_CFA_rule, describe_DWARF_expr ) from elftools.dwarf.constants import ( DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file) +from elftools.dwarf.locationlists import LocationParser, LocationEntry from elftools.dwarf.callframe import CIE, FDE, ZERO @@ -788,6 +789,8 @@ class ReadElf(object): self._dump_debug_aranges() elif dump_what in { 'pubtypes', 'pubnames' }: self._dump_debug_namelut(dump_what) + elif dump_what == 'loc': + self._dump_debug_locations() else: self._emitline('debug dump not yet supported for "%s"' % dump_what) @@ -1332,6 +1335,70 @@ class ReadElf(object): self._dwarfinfo.debug_frame_sec, self._dwarfinfo.CFI_entries()) + def _dump_debug_locations(self): + """ Dump the location lists from .debug_location section + """ + def _get_cu_base(cu): + top_die = cu.get_top_DIE() + attr = top_die.attributes + if 'DW_AT_low_pc' in attr: + return attr['DW_AT_low_pc'].value + elif 'DW_AT_entry_pc' in attr: + return attr['DW_AT_entry_pc'].value + else: + raise ValueError("Can't find the base IP (low_pc) for a CU") + + di = self._dwarfinfo + loc_lists = di.location_lists() + if not loc_lists: # No locations section - readelf outputs nothing + return + + loc_lists = list(loc_lists.iter_location_lists()) + if len(loc_lists) == 0: + # Present but empty locations section - readelf outputs a message + self._emitline("\nSection '%s' has no debugging data." % di.debug_loc_sec.name) + return + + # To dump a location list, one needs to know the CU. + # Scroll through DIEs once, list the known location list offsets + cu_map = dict() # Loc list offset => CU + for cu in di.iter_CUs(): + for die in cu.iter_DIEs(): + for key in die.attributes: + attr = die.attributes[key] + if (LocationParser.attribute_has_location(attr, cu['version']) and + not LocationParser._attribute_has_loc_expr(attr, cu['version'])): + cu_map[attr.value] = cu + + addr_size = di.config.default_address_size # In bytes, 4 or 8 + addr_width = addr_size * 2 # In hex digits, 8 or 16 + line_template = " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width, addr_width) + + self._emitline('Contents of the %s section:\n' % di.debug_loc_sec.name) + self._emitline(' Offset Begin End Expression') + for loc_list in loc_lists: + cu = cu_map.get(loc_list[0].entry_offset, False) + if not cu: + raise ValueError("Location list can't be tracked to a CU") + base_ip = _get_cu_base(cu) + for entry in loc_list: + # TODO: support BaseAddressEntry lines + expr = describe_DWARF_expr(entry.loc_expr, cu.structs, cu.cu_offset) + postfix = ' (start == end)' if entry.begin_offset == entry.end_offset else '' + self._emitline(line_template % ( + entry.entry_offset, + base_ip + entry.begin_offset, + base_ip + entry.end_offset, + expr, + postfix)) + # Pyelftools doesn't store the terminating entry, + # but readelf emits its offset, so this should too. + last = loc_list[-1] + last_len = 2*addr_size + if isinstance(last, LocationEntry): + last_len += 2 + len(last.loc_expr) + self._emitline(" %08x " % (last.entry_offset + last_len)) + def _display_arch_specific_arm(self): """ Display the ARM architecture-specific info contained in the file. """ @@ -1419,7 +1486,7 @@ def main(stream=None): action='store', dest='debug_dump_what', metavar='', help=( 'Display the contents of DWARF debug sections. can ' + - 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames}')) + 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc}')) argparser.add_argument('--traceback', action='store_true', dest='show_traceback', help='Dump the Python traceback on ELFError' diff --git a/test/run_readelf_tests.py b/test/run_readelf_tests.py index f4d06ae..95cfbd2 100755 --- a/test/run_readelf_tests.py +++ b/test/run_readelf_tests.py @@ -63,7 +63,7 @@ def run_test_on_file(filename, verbose=False, opt=None): '--debug-dump=info', '--debug-dump=decodedline', '--debug-dump=frames', '--debug-dump=frames-interp', '--debug-dump=aranges', '--debug-dump=pubtypes', - '--debug-dump=pubnames' + '--debug-dump=pubnames', '--debug-dump=loc' ] else: options = [opt] diff --git a/test/testfiles_for_readelf/dwarf_gnuops2.o.elf b/test/testfiles_for_readelf/dwarf_gnuops2.o.elf deleted file mode 100644 index 0d3bb20..0000000 Binary files a/test/testfiles_for_readelf/dwarf_gnuops2.o.elf and /dev/null differ diff --git a/test/testfiles_for_readelf/dwarf_gnuops3.o.elf b/test/testfiles_for_readelf/dwarf_gnuops3.o.elf deleted file mode 100644 index 9ae256d..0000000 Binary files a/test/testfiles_for_readelf/dwarf_gnuops3.o.elf and /dev/null differ