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 '<unknown %s>' % opcode_name
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
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(
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(
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))
(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.
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))>>
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
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)
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 <End of list>" % (last.entry_offset + last_len))
+
def _display_arch_specific_arm(self):
""" Display the ARM architecture-specific info contained in the file.
"""
action='store', dest='debug_dump_what', metavar='<what>',
help=(
'Display the contents of DWARF debug sections. <what> 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'
'--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]