From d84ec01f64c0a38832c5399a801ad0fb12106eb4 Mon Sep 17 00:00:00 2001 From: Seva Alekseyev Date: Mon, 16 May 2022 09:58:24 -0400 Subject: [PATCH] Storing the offset of DWARF operations within the expression block (#404) * Storing the offset of every DWARF operations within the expression block * Trivial auto test --- elftools/dwarf/dwarf_expr.py | 5 +++-- test/test_dwarf_expr.py | 31 +++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/elftools/dwarf/dwarf_expr.py b/elftools/dwarf/dwarf_expr.py index 07c6fa1..39ceee7 100644 --- a/elftools/dwarf/dwarf_expr.py +++ b/elftools/dwarf/dwarf_expr.py @@ -114,7 +114,7 @@ DW_OP_opcode2name = dict((v, k) for k, v in iteritems(DW_OP_name2opcode)) # Each parsed DWARF expression is returned as this type with its numeric opcode, # op name (as a string) and a list of arguments. -DWARFExprOp = namedtuple('DWARFExprOp', 'op op_name args') +DWARFExprOp = namedtuple('DWARFExprOp', 'op op_name args offset') class DWARFExprParser(object): @@ -138,6 +138,7 @@ class DWARFExprParser(object): while True: # Get the next opcode from the stream. If nothing is left in the # stream, we're done. + offset = stream.tell() byte = stream.read(1) if len(byte) == 0: break @@ -150,7 +151,7 @@ class DWARFExprParser(object): arg_parser = self._dispatch_table[op] args = arg_parser(stream) - parsed.append(DWARFExprOp(op=op, op_name=op_name, args=args)) + parsed.append(DWARFExprOp(op=op, op_name=op_name, args=args, offset=offset)) return parsed diff --git a/test/test_dwarf_expr.py b/test/test_dwarf_expr.py index 308d872..4e5dfc4 100644 --- a/test/test_dwarf_expr.py +++ b/test/test_dwarf_expr.py @@ -72,18 +72,41 @@ class TestParseExpr(unittest.TestCase): def test_single(self): p = DWARFExprParser(self.structs32) lst = p.parse_expr([0x1b]) - self.assertEqual(lst, [DWARFExprOp(op=0x1B, op_name='DW_OP_div', args=[])]) + self.assertEqual(lst, [DWARFExprOp(op=0x1B, op_name='DW_OP_div', args=[], offset=0)]) lst = p.parse_expr([0x90, 16]) - self.assertEqual(lst, [DWARFExprOp(op=0x90, op_name='DW_OP_regx', args=[16])]) + self.assertEqual(lst, [DWARFExprOp(op=0x90, op_name='DW_OP_regx', args=[16], offset=0)]) lst = p.parse_expr([0xe0]) self.assertEqual(len(lst), 1) # 0xe0 maps to both DW_OP_GNU_push_tls_address and DW_OP_lo_user, so # check for both to prevent non-determinism. self.assertIn(lst[0], [ - DWARFExprOp(op=0xe0, op_name='DW_OP_GNU_push_tls_address', args=[]), - DWARFExprOp(op=0xe0, op_name='DW_OP_lo_user', args=[])]) + DWARFExprOp(op=0xe0, op_name='DW_OP_GNU_push_tls_address', args=[], offset=0), + DWARFExprOp(op=0xe0, op_name='DW_OP_lo_user', args=[], offset=0)]) + + # Real life example: + # push_object_address + # deref + # dup + # bra 4 + # lit0 + # skip 3 + # lit4 + # minus + # deref + lst = p.parse_expr([0x97,0x6,0x12,0x28,0x4,0x0,0x30,0x2F,0x3,0x0,0x34,0x1C,0x6]) + self.assertEqual(len(lst), 9) + self.assertEqual(lst, [ + DWARFExprOp(op=0x97, op_name='DW_OP_push_object_address', args=[], offset=0), + DWARFExprOp(op=0x6, op_name='DW_OP_deref', args=[], offset=1), + DWARFExprOp(op=0x12, op_name='DW_OP_dup', args=[], offset=2), + DWARFExprOp(op=0x28, op_name='DW_OP_bra', args=[4], offset=3), + DWARFExprOp(op=0x30, op_name='DW_OP_lit0', args=[], offset=6), + DWARFExprOp(op=0x2f, op_name='DW_OP_skip', args=[3], offset=7), + DWARFExprOp(op=0x34, op_name='DW_OP_lit4', args=[], offset=10), + DWARFExprOp(op=0x1c, op_name='DW_OP_minus', args=[], offset=11), + DWARFExprOp(op=0x6, op_name='DW_OP_deref', args=[], offset=12)]) if __name__ == '__main__': -- 2.30.2