Simplify ExprDumper now that the expression parser is simpler.
authorEli Bendersky <eliben@gmail.com>
Sat, 14 Mar 2020 12:52:03 +0000 (05:52 -0700)
committerEli Bendersky <eliben@gmail.com>
Sat, 14 Mar 2020 12:52:03 +0000 (05:52 -0700)
We no longer need the part-by-part dumping and separate process/get_str.

Also simplify tests.

Fixes #298

elftools/dwarf/descriptions.py
test/test_dwarf_expr.py

index fdf5768e71e95c8a33eed7f27997e0dff88d2e00..9c20996e62ebf70dab3ffd65255457b8123e1853 100644 (file)
@@ -103,14 +103,13 @@ def describe_CFI_instructions(entry):
             s += '  %s: %s\n' % (name, instr.args[0])
         elif name == 'DW_CFA_def_cfa_expression':
             expr_dumper = ExprDumper(entry.structs)
-            expr_dumper.process_expr(instr.args[0])
             # readelf output is missing a colon for DW_CFA_def_cfa_expression
-            s += '  %s (%s)\n' % (name, expr_dumper.get_str())
+            s += '  %s (%s)\n' % (name, expr_dumper.dump_expr(instr.args[0]))
         elif name == 'DW_CFA_expression':
             expr_dumper = ExprDumper(entry.structs)
-            expr_dumper.process_expr(instr.args[1])
             s += '  %s: %s (%s)\n' % (
-                name, _full_reg_name(instr.args[0]), expr_dumper.get_str())
+                name, _full_reg_name(instr.args[0]),
+                                     expr_dumper.dump_expr(instr.args[1]))
         else:
             s += '  %s: <??>\n' % name
 
@@ -146,9 +145,7 @@ def describe_DWARF_expr(expr, structs):
         _DWARF_EXPR_DUMPER_CACHE[cache_key] = \
             ExprDumper(structs)
     dwarf_expr_dumper = _DWARF_EXPR_DUMPER_CACHE[cache_key]
-    dwarf_expr_dumper.clear()
-    dwarf_expr_dumper.process_expr(expr)
-    return '(' + dwarf_expr_dumper.get_str() + ')'
+    return '(' + dwarf_expr_dumper.dump_expr(expr) + ')'
 
 
 def describe_reg_name(regnum, machine_arch=None, default=True):
@@ -535,8 +532,7 @@ class ExprDumper(object):
     """ A dumper for DWARF expressions that dumps a textual
         representation of the complete expression.
 
-        Usage: after creation, call process_expr, and then get_str for a
-        semicolon-delimited string representation of the decoded expression.
+        Usage: after creation, call dump_expr repeatedly - it's stateless.
     """
     def __init__(self, structs):
         self.structs = structs
@@ -544,19 +540,17 @@ class ExprDumper(object):
         self._init_lookups()
         self._str_parts = []
 
-    def process_expr(self, expr):
-        """ Parse and process a DWARF expression. expr should be a list of
+    def dump_expr(self, expr):
+        """ Parse and dump a DWARF expression. expr should be a list of
             (integer) byte values.
+
+            Returns a string representing the expression.
         """
         parsed = self.expr_parser.parse_expr(expr)
+        s = []
         for deo in parsed:
-            self._str_parts.append(self._dump_to_string(deo.op, deo.op_name, deo.args))
-
-    def clear(self):
-        self._str_parts = []
-
-    def get_str(self):
-        return '; '.join(self._str_parts)
+            s.append(self._dump_to_string(deo.op, deo.op_name, deo.args))
+        return '; '.join(s)
 
     def _init_lookups(self):
         self._ops_with_decimal_arg = set([
index 0cc7f61467fe5436ebfa935d0494a277cb5bfba8..1d925f600a32e8c7873a978f9275a8579da38f1f 100644 (file)
@@ -22,48 +22,32 @@ class TestExprDumper(unittest.TestCase):
         set_global_machine_arch('x64')
 
     def test_basic_single(self):
-        self.visitor.process_expr([0x1b])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x1b]),
             'DW_OP_div')
 
-        self.setUp()
-        self.visitor.process_expr([0x74, 0x82, 0x01])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x74, 0x82, 0x01]),
             'DW_OP_breg4 (rsi): 130')
 
-        self.setUp()
-        self.visitor.process_expr([0x91, 0x82, 0x01])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x91, 0x82, 0x01]),
             'DW_OP_fbreg: 130')
 
-        self.setUp()
-        self.visitor.process_expr([0x51])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x51]),
             'DW_OP_reg1 (rdx)')
 
-        self.setUp()
-        self.visitor.process_expr([0x90, 16])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x90, 16]),
             'DW_OP_regx: 16 (rip)')
 
-        self.setUp()
-        self.visitor.process_expr([0x9d, 0x8f, 0x0A, 0x90, 0x01])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x9d, 0x8f, 0x0A, 0x90, 0x01]),
             'DW_OP_bit_piece: 1295 144')
 
     def test_basic_sequence(self):
-        self.visitor.process_expr([0x03, 0x01, 0x02, 0, 0, 0x06, 0x06])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x03, 0x01, 0x02, 0, 0, 0x06, 0x06]),
             'DW_OP_addr: 201; DW_OP_deref; DW_OP_deref')
 
-        self.setUp()
-        self.visitor.process_expr([0x15, 0xFF, 0x0b, 0xf1, 0xff])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x15, 0xFF, 0x0b, 0xf1, 0xff]),
             'DW_OP_pick: 255; DW_OP_const2s: -15')
 
-        self.setUp()
-        self.visitor.process_expr([0x1d, 0x1e, 0x1d, 0x1e, 0x1d, 0x1e])
-        self.assertEqual(self.visitor.get_str(),
+        self.assertEqual(self.visitor.dump_expr([0x1d, 0x1e, 0x1d, 0x1e, 0x1d, 0x1e]),
             'DW_OP_mod; DW_OP_mul; DW_OP_mod; DW_OP_mul; DW_OP_mod; DW_OP_mul')