started implementing dumping --debug-dump=frames
authorEli Bendersky <eliben@gmail.com>
Mon, 12 Dec 2011 04:40:34 +0000 (06:40 +0200)
committerEli Bendersky <eliben@gmail.com>
Mon, 12 Dec 2011 04:40:34 +0000 (06:40 +0200)
elftools/dwarf/callframe.py
elftools/dwarf/constants.py
elftools/dwarf/descriptions.py
scripts/readelf.py

index cfb2d07205fc33fba3fed77a26b3934cb0990353..2d51317a0bb7cc40147b8ac2262e4cb7a684b3c8 100644 (file)
@@ -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):
index 745bd6dc220378baa71432f7f13eb0825f7b0061..8bf38e870ea6202ab197d9a255491939e8d503c0 100644 (file)
@@ -139,6 +139,14 @@ DW_LNE_define_file = 0x03
 \r
 # Call frame instructions\r
 #\r
+# Note that the first 3 instructions have the so-called "primary opcode"\r
+# (as described in DWARFv3 7.23), so only their highest 2 bits take part\r
+# in the opcode decoding. They are kept as constants with the low bits masked\r
+# out, and the callframe module knows how to handle this.\r
+# The other instructions use an "extended opcode" encoded just in the low 6\r
+# bits, with the high 2 bits, so these constants are exactly as they would\r
+# appear in an actual file.\r
+#\r
 DW_CFA_advance_loc = 0b01000000\r
 DW_CFA_offset = 0b10000000\r
 DW_CFA_restore = 0b11000000\r
index f7afcd80f1352337b13eee2b4dc0561e707ab626..b40031049e67fe8b99be5ccaf932cab6c486d70d 100644 (file)
@@ -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.
index 335d5eec8a5212b1654ad747928644a99f3fdbbb..01c4d1f3e2493919a8fb61dce89558bc41cb03be 100755 (executable)
@@ -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
         """