readelf --debug-dump=frames-interp initial implementation completed. some tests vs...
authorEli Bendersky <eliben@gmail.com>
Fri, 16 Dec 2011 04:39:49 +0000 (06:39 +0200)
committerEli Bendersky <eliben@gmail.com>
Fri, 16 Dec 2011 04:39:49 +0000 (06:39 +0200)
elftools/dwarf/callframe.py
elftools/dwarf/descriptions.py
scripts/readelf.py
tests/run_readelf_tests.py
tests/test_callframe.py

index 982157293e1cdc2d8d69e5392aa85f97b872cc71..c2a7ec29832bb99196919c8e958ec17caf104466 100644 (file)
@@ -326,8 +326,7 @@ class CFIEntry(object):
             elif name == 'DW_CFA_restore_state':
                 cur_line = line_stack.pop()
 
-        if len(self.instructions) > 0:
-            table.append(cur_line)
+        table.append(cur_line)
         return DecodedCallFrameTable(table=table, reg_order=reg_order)
 
 
index 1cf2633d4c7c00bd64cf9e907d3b10711b1358f4..4647a41b67d3aa6f7a2125486d99c2139564cf25 100644 (file)
@@ -111,6 +111,22 @@ def describe_CFI_instructions(entry):
     return s
 
 
+def describe_CFI_register_rule(rule):
+    s = _DESCR_CFI_REGISTER_RULE_TYPE[rule.type]
+    if rule.type in ('OFFSET', 'VAL_OFFSET'):
+        s += '%+d' % rule.arg
+    elif rule.type == 'REGISTER':
+        s += describe_reg_name(rule.arg)
+    return s
+
+
+def describe_CFI_CFA_rule(rule):
+    if rule.expr:
+        return 'exp'
+    else:
+        return '%s%+d' % (describe_reg_name(rule.reg), rule.offset)
+    
+
 def describe_reg_name(regnum, machine_arch=None):
     """ Provide a textual description for a register name, given its serial
         number. The number is expected to be valid.
@@ -290,6 +306,16 @@ _DESCR_DW_ORD = {
     DW_ORD_col_major: '(column major)',
 }
 
+_DESCR_CFI_REGISTER_RULE_TYPE = dict(
+    UNDEFINED='u',
+    SAME_VALUE='s',
+    OFFSET='c',
+    VAL_OFFSET='v',
+    REGISTER='',
+    EXPRESSION='exp',
+    VAL_EXPRESSION='vexp',
+    ARCHITECTURAL='a',
+)
 
 def _make_extra_mapper(mapping, default, default_interpolate_value=False):
     """ Create a mapping function from attribute parameters to an extra
index 10b17acc6d85d193830a81626177d2b3e44dd479..a7296f52feee3bff039b83ed2a06da7b0ef9fdb8 100755 (executable)
@@ -9,6 +9,7 @@
 #-------------------------------------------------------------------------------
 import os, sys
 from optparse import OptionParser
+from itertools import ifilter
 import string
 
 
@@ -36,8 +37,10 @@ from elftools.elf.descriptions import (
     )
 from elftools.dwarf.dwarfinfo import DWARFInfo
 from elftools.dwarf.descriptions import (
-    describe_reg_name,
-    describe_attr_value, set_global_machine_arch, describe_CFI_instructions)
+    describe_reg_name, describe_attr_value, set_global_machine_arch,
+    describe_CFI_instructions, describe_CFI_register_rule,
+    describe_CFI_CFA_rule,
+    )
 from elftools.dwarf.constants import (
     DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file)
 from elftools.dwarf.callframe import CIE, FDE
@@ -651,6 +654,7 @@ class ReadElf(object):
                     entry['code_alignment_factor'],
                     entry['data_alignment_factor'],
                     entry['return_address_register']))
+                ra_regnum = entry['return_address_register']
             else: # FDE
                 self._emitline('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
                     entry.offset,
@@ -659,19 +663,43 @@ class ReadElf(object):
                     entry.cie.offset,
                     entry['initial_location'],
                     entry['initial_location'] + entry['address_range']))
+                ra_regnum = entry.cie['return_address_register']
 
             # Print the heading row for the decoded table
             self._emit('   LOC')
             self._emit('  ' if entry.structs.address_size == 4 else '          ')
-            self._emit('CFA      ')
+            self._emit(' CFA      ')
 
+            # Decode the table nad look at the registers it describes.
+            # We build reg_order here to match readelf's order. In particular,
+            # registers are sorted by their number, and the register matching
+            # ra_regnum is always listed last with a special heading.
             decoded_table = entry.get_decoded()
-            for regnum in decoded_table.reg_order:
+            reg_order = sorted(ifilter(
+                lambda r: r != ra_regnum, 
+                decoded_table.reg_order))
+
+            # Headings for the registers
+            for regnum in reg_order:
                 self._emit('%-6s' % describe_reg_name(regnum))
             self._emitline('ra      ')
-
-
-
+            
+            # Now include ra_regnum in reg_order to print its values similarly
+            # to the other registers.
+            reg_order.append(ra_regnum)
+            for line in decoded_table.table:
+                self._emit(self._format_hex(
+                    line['pc'], fullhex=True, lead0x=False))
+                self._emit(' %-9s' % describe_CFI_CFA_rule(line['cfa']))
+
+                for regnum in reg_order:
+                    if regnum in line:
+                        s = describe_CFI_register_rule(line[regnum])
+                    else:
+                        s = 'u'
+                    self._emit('%-6s' % s)
+                self._emitline()
+        self._emitline()
 
     def _emit(self, s=''):
         """ Emit an object to output
index 7df91d79950fb8992cf09095d6484fc4ed1efe3f..ca3b656be5121ec7b30bbb0bc403baef5dc8cbf8 100755 (executable)
@@ -53,7 +53,7 @@ def run_test_on_file(filename):
     for option in [
             '-e', '-s', '-r', '-x.text', '-p.shstrtab',
             '--debug-dump=info', '--debug-dump=decodedline',
-            '--debug-dump=frames']:
+            '--debug-dump=frames', '--debug-dump=frames-interp']:
         testlog.info("..option='%s'" % option)
         # stdouts will be a 2-element list: output of readelf and output 
         # of scripts/readelf.py
index fa0ac8005f5dee6780ed52f2856b78ff8ada7626..30e405b511d352b5de2e0290dd70a05562e2d062 100644 (file)
@@ -104,7 +104,6 @@ class TestCallFrame(unittest.TestCase):
 
         decoded_FDE = entries[1].get_decoded()
         self.assertEqual(decoded_FDE.reg_order, list(range(9)))
-        #self.assertEqual(len(decoded_FDE.table), 1)
         self.assertEqual(decoded_FDE.table[0]['cfa'].reg, 7)
         self.assertEqual(decoded_FDE.table[0]['cfa'].offset, 0)
         self.assertEqual(decoded_FDE.table[0]['pc'], 0x11223344)
@@ -120,8 +119,6 @@ class TestCallFrame(unittest.TestCase):
         self.assertEqual(decoded_FDE.table[5][4].arg, -12)
         self.assertEqual(decoded_FDE.table[6]['pc'], 0x11223344 + 64)
         self.assertEqual(decoded_FDE.table[9]['pc'], 0x11223344 + 76)
-        self.assertEqual(decoded_FDE.table[9][6].type, RegisterRule.SAME_VALUE)
-        self.assertEqual(decoded_FDE.table[10]['pc'], 0x11223344 + 80)
 
     def test_describe_CFI_instructions(self):
         # The data here represents a single CIE