From e3d0e51841c42b377585b5bff6a692750003643f Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Sun, 11 Dec 2011 06:48:48 +0200 Subject: [PATCH] starting tests for callframes --- elftools/dwarf/callframe.py | 23 +++++++++- examples/elfclass_address_size.py | 7 +-- tests/test_callframe.py | 74 +++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 tests/test_callframe.py diff --git a/elftools/dwarf/callframe.py b/elftools/dwarf/callframe.py index 77ccbb1..570fe5d 100644 --- a/elftools/dwarf/callframe.py +++ b/elftools/dwarf/callframe.py @@ -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 diff --git a/examples/elfclass_address_size.py b/examples/elfclass_address_size.py index c0cd94b..e131496 100644 --- a/examples/elfclass_address_size.py +++ b/examples/elfclass_address_size.py @@ -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 index 0000000..7a45090 --- /dev/null +++ b/tests/test_callframe.py @@ -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() + + -- 2.30.2