Fix for `CFIEntry.get_decoded()` (#232)
authorDmitry Koltunov <koltunov@ispras.ru>
Tue, 30 Jul 2019 03:11:38 +0000 (06:11 +0300)
committerEli Bendersky <eliben@users.noreply.github.com>
Tue, 30 Jul 2019 03:11:38 +0000 (20:11 -0700)
* test: test `CFIEntry.get_decoded()`

This test detects an error in `CFIEntry.get_decoded()`, that occurs when
decodes the `DW_CFA_def_cfa_register` instruction without some CFA
definition previously.

Signed-off-by: Koltunov Dmitry <koltunov@ispras.ru>
* add empty `cfa` for fixup decode of the `DW_CFA_def_cfa_register`

Signed-off-by: Koltunov Dmitry <koltunov@ispras.ru>
elftools/dwarf/callframe.py
test/test_callframe.py
test/testfiles_for_unittests/simple_mipsel.c [new file with mode: 0644]
test/testfiles_for_unittests/simple_mipsel.elf [new file with mode: 0755]

index bcef78d79a2b901d6e753876501e817ea8c9689b..46116ca1b2d11ad2dd0127434b959af1e1c5e1d5 100644 (file)
@@ -467,7 +467,7 @@ class CFIEntry(object):
         if isinstance(self, CIE):
             # For a CIE, initialize cur_line to an "empty" line
             cie = self
-            cur_line = dict(pc=0, cfa=None)
+            cur_line = dict(pc=0, cfa=CFARule(reg=None, offset=0))
             reg_order = []
         else: # FDE
             # For a FDE, we need to decode the attached CIE first, because its
@@ -479,7 +479,7 @@ class CFIEntry(object):
                 last_line_in_CIE = copy.copy(cie_decoded_table.table[-1])
                 cur_line = copy.copy(last_line_in_CIE)
             else:
-                cur_line = dict(cfa=None)
+                cur_line = dict(cfa=CFARule(reg=None, offset=0))
             cur_line['pc'] = self['initial_location']
             reg_order = copy.copy(cie_decoded_table.reg_order)
 
@@ -575,7 +575,7 @@ class CFIEntry(object):
 
         # The current line is appended to the table after all instructions
         # have ended, if there were instructions.
-        if cur_line['cfa'] is not None or len(cur_line) > 2:
+        if cur_line['cfa'].reg is not None or len(cur_line) > 2:
             table.append(cur_line)
 
         return DecodedCallFrameTable(table=table, reg_order=reg_order)
index 5be2717f7d4627dc6a8110210ceda7801fb6b1d9..0fb9dde75967156d7399950e5905951c259da92c 100644 (file)
@@ -9,10 +9,12 @@ import unittest
 from elftools.common.py3compat import BytesIO
 from elftools.dwarf.callframe import (
     CallFrameInfo, CIE, FDE, instruction_name, CallFrameInstruction,
-    RegisterRule)
+    RegisterRule, DecodedCallFrameTable, CFARule)
 from elftools.dwarf.structs import DWARFStructs
 from elftools.dwarf.descriptions import (describe_CFI_instructions,
     set_global_machine_arch)
+from elftools.elf.elffile import ELFFile
+from os.path import join
 
 
 class TestCallFrame(unittest.TestCase):
@@ -145,6 +147,25 @@ class TestCallFrame(unittest.TestCase):
             (   '  DW_CFA_def_cfa: r7 (edi) ofs 2\n' +
                 '  DW_CFA_expression: r2 (edx) (DW_OP_addr: 201; DW_OP_deref; DW_OP_deref)\n'))
 
+    def test_CFIEntry_get_decoded(self):
+        oracle_decoded = DecodedCallFrameTable(
+            table = [
+                {'pc': 0, 'cfa': CFARule(reg = 29, offset = 0, expr = None)}
+            ],
+            reg_order = []
+        )
+
+        test_dir = join('test', 'testfiles_for_unittests')
+        with open(join(test_dir, 'simple_mipsel.elf'), 'rb') as f:
+            elf = ELFFile(f)
+            di = elf.get_dwarf_info()
+            entries = di.CFI_entries()
+            decoded = entries[0].get_decoded()
+            self.assertEqual(oracle_decoded.table[0]['cfa'].reg,
+                decoded.table[0]['cfa'].reg
+            )
+            self.assertEqual(oracle_decoded.table[0]['cfa'].offset,
+                decoded.table[0]['cfa'].offset)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/test/testfiles_for_unittests/simple_mipsel.c b/test/testfiles_for_unittests/simple_mipsel.c
new file mode 100644 (file)
index 0000000..601434b
--- /dev/null
@@ -0,0 +1,14 @@
+/* Generated by compiling with any GCC version for MIPS Little Endian.
+** GCC 5.4.0 is fine.
+
+/usr/bin/mipsel-linux-gnu-gcc -g -O0 ./simple_mipsel.c -o ./simple_mipsel.elf
+*/
+
+void main(void)
+{
+    int a = 1, b = 2, res;
+
+    res = a + b;
+
+    return;
+}
diff --git a/test/testfiles_for_unittests/simple_mipsel.elf b/test/testfiles_for_unittests/simple_mipsel.elf
new file mode 100755 (executable)
index 0000000..86c2561
Binary files /dev/null and b/test/testfiles_for_unittests/simple_mipsel.elf differ