def _describe_attr_ref(attr, die, section_offset):
return '<0x%x>' % (attr.value + die.cu.cu_offset)
+def _describe_attr_ref_sig8(attr, die, section_offset):
+ return 'signature: 0x%x' % (attr.value)
+
def _describe_attr_value_passthrough(attr, die, section_offset):
return attr.value
DW_FORM_block=_describe_attr_block,
DW_FORM_flag_present=_describe_attr_present,
DW_FORM_exprloc=_describe_attr_block,
- DW_FORM_ref_sig8=_describe_attr_ref,
+ DW_FORM_ref_sig8=_describe_attr_ref_sig8,
)
_FORM_CLASS = dict(
class DWARFInfo(object):
""" Acts also as a "context" to other major objects, bridging between
- various parts of the debug infromation.
+ various parts of the debug information.
"""
def __init__(self,
config,
# Cache for abbrev tables: a dict keyed by offset
self._abbrevtable_cache = {}
-
+ # Cache for program lines tables: a dict keyed by offset
+ self._linetable_cache = {}
+
# Cache of compile units and map of their offsets for bisect lookup.
# Access with .iter_CUs(), .get_CU_containing(), and/or .get_CU_at().
self._cu_cache = []
"""
return 2 <= version <= 5
- def _parse_line_program_at_offset(self, debug_line_offset, structs):
+ def _parse_line_program_at_offset(self, offset, structs):
""" Given an offset to the .debug_line section, parse the line program
starting at this offset in the section and return it.
structs is the DWARFStructs object used to do this parsing.
"""
+
+ if offset in self._linetable_cache:
+ return self._linetable_cache[offset]
+
lineprog_header = struct_parse(
structs.Dwarf_lineprog_header,
self.debug_line_sec.stream,
- debug_line_offset)
+ offset)
# DWARF5: resolve names
def resolve_strings(self, lineprog_header, format_field, data_field):
for e in lineprog_header.file_names)
# Calculate the offset to the next line program (see DWARF 6.2.4)
- end_offset = ( debug_line_offset + lineprog_header['unit_length'] +
+ end_offset = ( offset + lineprog_header['unit_length'] +
structs.initial_length_field_size())
- return LineProgram(
+ lineprogram = LineProgram(
header=lineprog_header,
stream=self.debug_line_sec.stream,
structs=structs,
program_start_offset=self.debug_line_sec.stream.tell(),
program_end_offset=end_offset)
+ self._linetable_cache[offset] = lineprogram
+ return lineprogram
+
def parse_debugsupinfo(self):
"""
Extract a filename from either .debug_sup or .gnu_debualtlink sections.
self.Dwarf_sleb128 = SLEB128
def _create_cu_header(self):
+ dwarfv4_CU_header = Struct('',
+ self.Dwarf_offset('debug_abbrev_offset'),
+ self.Dwarf_uint8('address_size')
+ )
+ # DWARFv5 reverses the order of address_size and debug_abbrev_offset.
+ # DWARFv5 7.5.1.1
+ dwarfv5_CP_CU_header = Struct('',
+ self.Dwarf_uint8('address_size'),
+ self.Dwarf_offset('debug_abbrev_offset')
+ )
+ # DWARFv5 7.5.1.2
+ dwarfv5_SS_CU_header = Struct('',
+ self.Dwarf_uint8('address_size'),
+ self.Dwarf_offset('debug_abbrev_offset'),
+ self.Dwarf_uint64('dwo_id')
+ )
+ # DWARFv5 7.5.1.3
+ dwarfv5_TS_CU_header = Struct('',
+ self.Dwarf_uint8('address_size'),
+ self.Dwarf_offset('debug_abbrev_offset'),
+ self.Dwarf_uint64('type_signature'),
+ self.Dwarf_offset('type_offset')
+ )
+ dwarfv5_CU_header = Struct('',
+ Enum(self.Dwarf_uint8('unit_type'), **ENUM_DW_UT),
+ Embed(Switch('', lambda ctx: ctx.unit_type,
+ {
+ 'DW_UT_compile' : dwarfv5_CP_CU_header,
+ 'DW_UT_partial' : dwarfv5_CP_CU_header,
+ 'DW_UT_skeleton' : dwarfv5_SS_CU_header,
+ 'DW_UT_split_compile' : dwarfv5_SS_CU_header,
+ 'DW_UT_type' : dwarfv5_TS_CU_header,
+ 'DW_UT_split_type' : dwarfv5_TS_CU_header,
+ })))
self.Dwarf_CU_header = Struct('Dwarf_CU_header',
self.Dwarf_initial_length('unit_length'),
self.Dwarf_uint16('version'),
- # DWARFv5 reverses the order of address_size and debug_abbrev_offset.
IfThenElse('', lambda ctx: ctx['version'] >= 5,
- Embed(Struct('',
- self.Dwarf_uint8('unit_type'),
- self.Dwarf_uint8('address_size'),
- self.Dwarf_offset('debug_abbrev_offset'))),
- Embed(Struct('',
- self.Dwarf_offset('debug_abbrev_offset'),
- self.Dwarf_uint8('address_size'))),
+ Embed(dwarfv5_CU_header),
+ Embed(dwarfv4_CU_header),
))
def _create_abbrev_declaration(self):
self._emitline(".debug_info contents:")
for cu in self._dwarfinfo.iter_CUs():
if cu.header.version >= 5:
- ut = next(k for (k,v) in ENUM_DW_UT.items() if v == cu.header.unit_type)
- unit_type_str = " unit_type = %s," % ut
+ unit_type_str = " unit_type = %s," % cu.header.unit_type
else:
unit_type_str = ''
self._format_hex(cu['unit_length']),
'%s-bit' % cu.dwarf_format()))
self._emitline(' Version: %s' % cu['version'])
- if cu.header.get("unit_type", False):
- ut = next((key for key, value in ENUM_DW_UT.items() if value == cu.header.unit_type), '?')
- self._emitline(' Unit Type: %s (%d)' % (ut, cu.header.unit_type))
- self._emitline(' Abbrev Offset: %s' % (
- self._format_hex(cu['debug_abbrev_offset']))),
- self._emitline(' Pointer Size: %s' % cu['address_size'])
+ if cu['version'] >= 5:
+ if cu.header.get("unit_type", ''):
+ unit_type = cu.header.unit_type
+ self._emitline(' Unit Type: %s (%d)' % (
+ unit_type, ENUM_DW_UT.get(cu.header.unit_type, 0)))
+ self._emitline(' Abbrev Offset: %s' % (
+ self._format_hex(cu['debug_abbrev_offset'])))
+ self._emitline(' Pointer Size: %s' % cu['address_size'])
+ if unit_type in ('DW_UT_skeleton', 'DW_UT_split_compile'):
+ self._emitline(' Dwo id: %s' % cu['dwo_id'])
+ elif unit_type in ('DW_UT_type', 'DW_UT_split_type'):
+ self._emitline(' Signature: 0x%x' % cu['type_signature'])
+ self._emitline(' Type Offset: 0x%x' % cu['type_offset'])
+ else:
+ self._emitline(' Abbrev Offset: %s' % (
+ self._format_hex(cu['debug_abbrev_offset']))),
+ self._emitline(' Pointer Size: %s' % cu['address_size'])
# The nesting depth of each DIE within the tree of DIEs must be
# displayed. To implement this, a counter is incremented each time
return
self._emitline('Contents of the %s section:' % self._dwarfinfo.debug_line_sec.name)
self._emitline()
+ lineprogram_list = []
for cu in self._dwarfinfo.iter_CUs():
+ # Avoid dumping same lineprogram multiple times
lineprogram = self._dwarfinfo.line_program_for_CU(cu)
+
+ if lineprogram in lineprogram_list:
+ continue
+
+ lineprogram_list.append(lineprogram)
ver5 = lineprogram.header.version >= 5
cu_filename = bytes2str(lineprogram['file_entry'][0].name)