starting tests for callframes
authorEli Bendersky <eliben@gmail.com>
Sun, 11 Dec 2011 04:48:48 +0000 (06:48 +0200)
committerEli Bendersky <eliben@gmail.com>
Sun, 11 Dec 2011 04:48:48 +0000 (06:48 +0200)
elftools/dwarf/callframe.py
examples/elfclass_address_size.py
tests/test_callframe.py [new file with mode: 0644]

index 77ccbb150dbbd92405a3aed0ff0ebc8cff72406e..570fe5ddad72709a5c464a334da8ec1d7099abe7 100644 (file)
@@ -44,6 +44,26 @@ class FDE(object):
 
 
 class CallFrameInfo(object):
+    """ DWARF CFI (Call Frame Info)
+        
+        stream, size:
+            A stream holding the .debug_frame section, and the size of the
+            section in it.
+
+        base_structs:
+            The structs to be used as the base for parsing this section.
+            Eventually, each entry gets its own structs based on the initial
+            length field it starts with. The address_size, however, is taken
+            from base_structs. This appears to be a limitation of the DWARFv3
+            standard, fixed in v4 (where an address_size field exists for each
+            CFI. I had a discussion about this on dwarf-discuss that confirms
+            this.
+            Currently for base_structs I simply use the elfclass of the
+            containing file, but more sophisticated methods are used by
+            libdwarf and others, such as guessing which CU contains which FDEs
+            (based on their address ranges) and taking the address_size from
+            those CUs.
+    """
     def __init__(self, stream, size, base_structs):
         self.stream = stream
         self.size = size
@@ -102,7 +122,7 @@ class CallFrameInfo(object):
             entries.append(new_entry_class(
                 header=header,
                 instructions=instructions))
-            # ZZZ: for FDE's, I need some offset->CIE mapping cache stored
+             # ZZZ: for FDE's, I need some offset->CIE mapping cache stored
             offset = self.stream.tell()
         return entries
 
@@ -167,7 +187,6 @@ class CallFrameInfo(object):
                 dwarf_assert(False, 'Unknown CFI opcode: 0x%x' % opcode)
 
             instructions.append(CallFrameInstruction(opcode=opcode, args=args))
-            print instructions[-1]
             offset = self.stream.tell()
         return instructions
 
index c0cd94bd1d7c436faa8f93fa983af5596204f20c..e1314960faee9dc5a3bb173138bd33ffbbd41f04 100644 (file)
@@ -22,12 +22,7 @@ def process_file(filename):
                 print '  CU at offset 0x%x. address_size is %s' % (
                     CU.cu_offset, CU['address_size'])
 
-
-def main():
+if __name__ == '__main__':
     for filename in sys.argv[1:]:
         process_file(filename)
 
-
-if __name__ == '__main__':
-    main()
-
diff --git a/tests/test_callframe.py b/tests/test_callframe.py
new file mode 100644 (file)
index 0000000..7a45090
--- /dev/null
@@ -0,0 +1,74 @@
+import sys, unittest
+from cStringIO import StringIO
+
+sys.path.extend(['.', '..'])
+from elftools.dwarf.callframe import (
+    CallFrameInfo, CIE, FDE, instruction_name, CallFrameInstruction)
+from elftools.dwarf.structs import DWARFStructs
+
+
+class TestCallFrame(unittest.TestCase):
+    def assertInstruction(self, instr, name, args):
+        self.assertIsInstance(instr, CallFrameInstruction)
+        self.assertEqual(instruction_name(instr.opcode), name)
+        self.assertEqual(instr.args, args)
+        
+    def test_spec_sample_d6(self):
+        # D.6 sample in DWARFv3
+        s = StringIO()
+        data = ('' +
+            # first comes the CIE
+            '\x20\x00\x00\x00' +        # length
+            '\xff\xff\xff\xff' +        # CIE_id
+            '\x03\x00\x04\x7c' +        # version, augmentation, caf, daf
+            '\x08' +                    # return address
+            '\x0c\x07\x00' +
+            '\x08\x00' +
+            '\x07\x01' +
+            '\x07\x02' +
+            '\x07\x03' +
+            '\x08\x04' +
+            '\x08\x05' +
+            '\x08\x06' +
+            '\x08\x07' +
+            '\x09\x08\x01' +
+            '\x00' +
+            
+            # then comes the FDE
+            '\x28\x00\x00\x00' +        # length
+            '\x00\x00\x00\x00' +        # CIE_pointer (to CIE at 0)
+            '\x44\x33\x22\x11' +        # initial_location
+            '\x54\x00\x00\x00' +        # address range
+            '\x41' +
+            '\x0e\x0c' + '\x41' +
+            '\x88\x01' + '\x41' +
+            '\x86\x02' + '\x41' +
+            '\x0d\x06' + '\x41' +
+            '\x84\x03' + '\x4b' +
+            '\xc4' + '\x41' +
+            '\xc6' +
+            '\x0d\x07' + '\x41' +
+            '\xc8' + '\x41' +
+            '\x0e\x00' +
+            '\x00\x00'
+            )
+        s.write(data)
+
+        structs = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
+        cfi = CallFrameInfo(s, len(data), structs)
+        entries = cfi.get_entries()
+
+        self.assertEqual(len(entries), 2)
+        self.assertIsInstance(entries[0], CIE)
+        self.assertEqual(entries[0]['length'], 32)
+        self.assertEqual(entries[0]['data_alignment_factor'], -4)
+        self.assertEqual(entries[0]['return_address_register'], 8)
+        self.assertInstruction(entries[0].instructions[0],
+            'DW_CFA_def_cfa', [7, 0])
+
+        self.assertTrue(isinstance(entries[1], FDE))
+
+if __name__ == '__main__':
+    unittest.main()
+
+