from collections import defaultdict
from .constants import *
-from .dwarf_expr import parse_expr
+from .dwarf_expr import DWARFExprParser
from .die import DIE
from ..common.utils import preserve_stream_pos, dwarf_assert
from ..common.py3compat import bytes2str
"""
def __init__(self, structs):
self.structs = structs
+ self.expr_parser = DWARFExprParser(self.structs)
self._init_lookups()
self._str_parts = []
""" Parse and process a DWARF expression. expr should be a list of
(integer) byte values.
"""
- parsed = parse_expr(expr, self.structs)
+ parsed = self.expr_parser.parse_expr(expr)
for deo in parsed:
self._str_parts.append(self._dump_to_string(deo.op, deo.op_name, deo.args))
# 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')
-def parse_expr(expr, structs):
- """ Parses expr (a list of integers) into a list of DwarfExprOp.
+class DWARFExprParser(object):
+ """DWARF expression parser.
- The list can potentially be nested.
+ When initialized, requires structs to cache a dispatch table. After that,
+ parse_expr can be called repeatedly - it's stateless.
"""
- dispatch_table = _init_dispatch_table(structs)
- stream = BytesIO(bytelist2string(expr))
- parsed = []
+ def __init__(self, structs):
+ self._dispatch_table = _init_dispatch_table(structs)
- while True:
- # Get the next opcode from the stream. If nothing is left in the
- # stream, we're done.
- byte = stream.read(1)
- if len(byte) == 0:
- break
+ def parse_expr(self, expr):
+ """ Parses expr (a list of integers) into a list of DWARFExprOp.
- # Decode the opcode and its name.
- op = ord(byte)
- op_name = DW_OP_opcode2name.get(op, 'OP:0x%x' % op)
+ The list can potentially be nested.
+ """
+ stream = BytesIO(bytelist2string(expr))
+ parsed = []
- # Use dispatch table to parse args.
- arg_parser = dispatch_table[op]
- args = arg_parser(stream)
+ while True:
+ # Get the next opcode from the stream. If nothing is left in the
+ # stream, we're done.
+ byte = stream.read(1)
+ if len(byte) == 0:
+ break
- parsed.append(DwarfExprOp(op=op, op_name=op_name, args=args))
+ # Decode the opcode and its name.
+ op = ord(byte)
+ op_name = DW_OP_opcode2name.get(op, 'OP:0x%x' % op)
- return parsed
+ # Use dispatch table to parse args.
+ arg_parser = self._dispatch_table[op]
+ args = arg_parser(stream)
+
+ parsed.append(DWARFExprOp(op=op, op_name=op_name, args=args))
+
+ return parsed
def _init_dispatch_table(structs):
import unittest
from elftools.dwarf.descriptions import ExprDumper, set_global_machine_arch
-from elftools.dwarf.dwarf_expr import parse_expr, DwarfExprOp
+from elftools.dwarf.dwarf_expr import DWARFExprParser, DWARFExprOp
from elftools.dwarf.structs import DWARFStructs
set_global_machine_arch('x64')
def test_single(self):
- lst = parse_expr([0x1b], self.structs32)
- self.assertEqual(lst, [DwarfExprOp(op=0x1B, op_name='DW_OP_div', args=[])])
+ p = DWARFExprParser(self.structs32)
+ lst = p.parse_expr([0x1b])
+ self.assertEqual(lst, [DWARFExprOp(op=0x1B, op_name='DW_OP_div', args=[])])
- lst = parse_expr([0x90, 16], self.structs32)
- self.assertEqual(lst, [DwarfExprOp(op=0x90, op_name='DW_OP_regx', args=[16])])
+ lst = p.parse_expr([0x90, 16])
+ self.assertEqual(lst, [DWARFExprOp(op=0x90, op_name='DW_OP_regx', args=[16])])
if __name__ == '__main__':