From 7241ff0e20725e63511f66596b85d9bf169de785 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Mon, 12 Dec 2011 06:40:34 +0200 Subject: [PATCH] started implementing dumping --debug-dump=frames --- elftools/dwarf/callframe.py | 13 +++++++++---- elftools/dwarf/constants.py | 8 ++++++++ elftools/dwarf/descriptions.py | 9 +++++++++ scripts/readelf.py | 33 ++++++++++++++++++++++++++++++++- 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/elftools/dwarf/callframe.py b/elftools/dwarf/callframe.py index cfb2d07..2d51317 100644 --- a/elftools/dwarf/callframe.py +++ b/elftools/dwarf/callframe.py @@ -29,10 +29,12 @@ class CallFrameInstruction(object): class CIE(object): """ CIE - Common Information Entry. Contains a header and a list of instructions (CallFrameInstruction). + offset: the offset of this entry from the beginning of the section """ - def __init__(self, header, instructions): + def __init__(self, header, instructions, offset): self.header = header self.instructions = instructions + self.offset = offset def __getitem__(self, name): """ Implement dict-like access to header entries @@ -44,10 +46,12 @@ class FDE(object): """ FDE - Frame Description Entry. Contains a header, a list of instructions (CallFrameInstruction) and a reference to the CIE object associated with this FDE. + offset: the offset of this entry from the beginning of the section """ - def __init__(self, header, instructions, cie): + def __init__(self, header, instructions, offset, cie): self.header = header self.instructions = instructions + self.offset = offset self.cie = cie def __getitem__(self, name): @@ -148,12 +152,13 @@ class CallFrameInfo(object): if is_CIE: self._entry_cache[offset] = CIE( - header=header, instructions=instructions) + header=header, instructions=instructions, offset=offset) else: # FDE with preserve_stream_pos(self.stream): cie = self._parse_entry_at(header['CIE_pointer']) self._entry_cache[offset] = FDE( - header=header, instructions=instructions, cie=cie) + header=header, instructions=instructions, offset=offset, + cie=cie) return self._entry_cache[offset] def _parse_instructions(self, structs, offset, end_offset): diff --git a/elftools/dwarf/constants.py b/elftools/dwarf/constants.py index 745bd6d..8bf38e8 100644 --- a/elftools/dwarf/constants.py +++ b/elftools/dwarf/constants.py @@ -139,6 +139,14 @@ DW_LNE_define_file = 0x03 # Call frame instructions # +# Note that the first 3 instructions have the so-called "primary opcode" +# (as described in DWARFv3 7.23), so only their highest 2 bits take part +# in the opcode decoding. They are kept as constants with the low bits masked +# out, and the callframe module knows how to handle this. +# The other instructions use an "extended opcode" encoded just in the low 6 +# bits, with the high 2 bits, so these constants are exactly as they would +# appear in an actual file. +# DW_CFA_advance_loc = 0b01000000 DW_CFA_offset = 0b10000000 DW_CFA_restore = 0b11000000 diff --git a/elftools/dwarf/descriptions.py b/elftools/dwarf/descriptions.py index f7afcd8..b400310 100644 --- a/elftools/dwarf/descriptions.py +++ b/elftools/dwarf/descriptions.py @@ -37,6 +37,15 @@ def describe_attr_value(attr, die, section_offset): return str(val_description) + '\t' + extra_info +def describe_CFI_instruction(instruction, entry, context): + # ZZZ: just get a list of instructions and keep the context internally!! + """ Given a CFI instruction, return its textual description. Also needs the + entry that contains this instruction. + context is a + """ + return '' + + def describe_reg_name(regnum, machine_arch): """ Provide a textual description for a register name, given its serial number. The number is expected to be valid. diff --git a/scripts/readelf.py b/scripts/readelf.py index 335d5ee..01c4d1f 100755 --- a/scripts/readelf.py +++ b/scripts/readelf.py @@ -36,9 +36,10 @@ from elftools.elf.descriptions import ( ) from elftools.dwarf.dwarfinfo import DWARFInfo from elftools.dwarf.descriptions import ( - describe_attr_value, set_global_machine_arch) + describe_attr_value, set_global_machine_arch, describe_CFI_instruction) from elftools.dwarf.constants import ( DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file) +from elftools.dwarf.callframe import CIE, FDE class ReadElf(object): @@ -432,6 +433,8 @@ class ReadElf(object): self._dump_debug_info() elif dump_what == 'decodedline': self._dump_debug_line_programs() + elif dump_what == 'frames': + self._dump_debug_frames() else: self._emitline('debug dump not yet supported for "%s"' % dump_what) @@ -598,6 +601,34 @@ class ReadElf(object): # Another readelf oddity... self._emitline() + def _dump_debug_frames(self): + """ Dump the raw frame information from .debug_frame + """ + self._emitline('Contents of the .debug_frame section:') + + for entry in self._dwarfinfo.CFI_entries(): + if isinstance(entry, CIE): + self._emitline('\n%08x %08x %08x CIE' % ( + entry.offset, entry['length'], entry['CIE_id'])) + self._emitline(' Version: %d' % entry['version']) + self._emitline(' Augmentation: "%s"' % entry['augmentation']) + self._emitline(' Code alignment factor: %u' % entry['code_alignment_factor']) + self._emitline(' Data alignment factor: %d' % entry['data_alignment_factor']) + self._emitline(' Return address column: %d' % entry['return_address_register']) + else: # FDE + self._emitline('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % ( + entry.offset, + entry['length'], + entry['CIE_pointer'], + entry.cie.offset, + entry['initial_location'], + entry['initial_location'] + entry['address_range'])) + + if len(entry.instructions) > 0: + self._emitline('') + for instr in entry.instructions: + self._emitline(describe_CFI_instruction(instr, entry)) + def _emit(self, s=''): """ Emit an object to output """ -- 2.30.2