From 9377b5513b6dbf8421a07ea3aa222a63326a8919 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Sat, 14 Mar 2020 05:52:03 -0700 Subject: [PATCH] Simplify ExprDumper now that the expression parser is simpler. We no longer need the part-by-part dumping and separate process/get_str. Also simplify tests. Fixes #298 --- elftools/dwarf/descriptions.py | 30 ++++++++++++------------------ test/test_dwarf_expr.py | 34 +++++++++------------------------- 2 files changed, 21 insertions(+), 43 deletions(-) diff --git a/elftools/dwarf/descriptions.py b/elftools/dwarf/descriptions.py index fdf5768..9c20996 100644 --- a/elftools/dwarf/descriptions.py +++ b/elftools/dwarf/descriptions.py @@ -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([ diff --git a/test/test_dwarf_expr.py b/test/test_dwarf_expr.py index 0cc7f61..1d925f6 100644 --- a/test/test_dwarf_expr.py +++ b/test/test_dwarf_expr.py @@ -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') -- 2.30.2