DW_OP_opcode2name = dict((v, k) for k, v in iteritems(DW_OP_name2opcode))
-class GenericExprVisitor(object):
- """ A DWARF expression is a sequence of instructions encoded in a block
- of bytes. This class decodes the sequence into discrete instructions
- with their arguments and allows generic "visiting" to process them.
-
- Usage: subclass this class, and override the needed methods. The
- easiest way would be to just override _after_visit, which gets passed
- each decoded instruction (with its arguments) in order. Clients of
- the visitor then just execute process_expr. The subclass can keep
- its own internal information updated in _after_visit and provide
- methods to extract it. For a good example of this usage, see the
- ExprDumper class in the descriptions module.
-
- A more complex usage could be to override visiting methods for
- specific instructions, by placing them into the dispatch table.
- """
- def __init__(self, structs):
- self.structs = structs
- self._init_dispatch_table()
- self.stream = None
- self._cur_opcode = None
- self._cur_opcode_name = None
- self._cur_args = []
-
- def process_expr(self, expr):
- """ Process (visit) a DWARF expression. expr should be a list of
- (integer) byte values.
- """
- self.stream = BytesIO(bytelist2string(expr))
-
- while True:
- # Get the next opcode from the stream. If nothing is left in the
- # stream, we're done.
- byte = self.stream.read(1)
- if len(byte) == 0:
- break
-
- # Decode the opcode and its name
- self._cur_opcode = ord(byte)
- self._cur_opcode_name = DW_OP_opcode2name.get(
- self._cur_opcode, 'OP:0x%x' % self._cur_opcode)
- # Will be filled in by visitors
- self._cur_args = []
-
- # Dispatch to a visitor function
- visitor = self._dispatch_table.get(
- self._cur_opcode,
- self._default_visitor)
- visitor(self._cur_opcode, self._cur_opcode_name)
-
- # Finally call the post-visit function
- self._after_visit(
- self._cur_opcode, self._cur_opcode_name, self._cur_args)
-
- def _after_visit(self, opcode, opcode_name, args):
- pass
-
- def _default_visitor(self, opcode, opcode_name):
- pass
-
- def _visit_OP_with_no_args(self, opcode, opcode_name):
- self._cur_args = []
-
- def _visit_OP_addr(self, opcode, opcode_name):
- self._cur_args = [
- struct_parse(self.structs.Dwarf_target_addr(''), self.stream)]
-
- def _make_visitor_arg_struct(self, struct_arg):
- """ Create a visitor method for an opcode that that accepts a single
- argument, specified by a struct.
- """
- def visitor(opcode, opcode_name):
- self._cur_args = [struct_parse(struct_arg, self.stream)]
- return visitor
-
- def _make_visitor_arg_struct2(self, struct_arg1, struct_arg2):
- """ Create a visitor method for an opcode that that accepts two
- arguments, specified by structs.
- """
- def visitor(opcode, opcode_name):
- self._cur_args = [
- struct_parse(struct_arg1, self.stream),
- struct_parse(struct_arg2, self.stream)]
- return visitor
-
- def _init_dispatch_table(self):
- self._dispatch_table = {}
- def add(opcode_name, func):
- self._dispatch_table[DW_OP_name2opcode[opcode_name]] = func
-
- add('DW_OP_addr', self._visit_OP_addr)
- add('DW_OP_const1u',
- self._make_visitor_arg_struct(self.structs.Dwarf_uint8('')))
- add('DW_OP_const1s',
- self._make_visitor_arg_struct(self.structs.Dwarf_int8('')))
- add('DW_OP_const2u',
- self._make_visitor_arg_struct(self.structs.Dwarf_uint16('')))
- add('DW_OP_const2s',
- self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
- add('DW_OP_const4u',
- self._make_visitor_arg_struct(self.structs.Dwarf_uint32('')))
- add('DW_OP_const4s',
- self._make_visitor_arg_struct(self.structs.Dwarf_int32('')))
- add('DW_OP_const8u',
- self._make_visitor_arg_struct2(
- self.structs.Dwarf_uint32(''),
- self.structs.Dwarf_uint32('')))
- add('DW_OP_const8s',
- self._make_visitor_arg_struct2(
- self.structs.Dwarf_int32(''),
- self.structs.Dwarf_int32('')))
- add('DW_OP_constu',
- self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
- add('DW_OP_consts',
- self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
- add('DW_OP_pick',
- self._make_visitor_arg_struct(self.structs.Dwarf_uint8('')))
- add('DW_OP_plus_uconst',
- self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
- add('DW_OP_bra',
- self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
- add('DW_OP_skip',
- self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
-
- for opname in [ 'DW_OP_deref', 'DW_OP_dup', 'DW_OP_drop', 'DW_OP_over',
- 'DW_OP_swap', 'DW_OP_swap', 'DW_OP_rot', 'DW_OP_xderef',
- 'DW_OP_abs', 'DW_OP_and', 'DW_OP_div', 'DW_OP_minus',
- 'DW_OP_mod', 'DW_OP_mul', 'DW_OP_neg', 'DW_OP_not',
- 'DW_OP_plus', 'DW_OP_shl', 'DW_OP_shr', 'DW_OP_shra',
- 'DW_OP_xor', 'DW_OP_eq', 'DW_OP_ge', 'DW_OP_gt',
- 'DW_OP_le', 'DW_OP_lt', 'DW_OP_ne', 'DW_OP_nop',
- 'DW_OP_push_object_address', 'DW_OP_form_tls_address',
- 'DW_OP_call_frame_cfa']:
- add(opname, self._visit_OP_with_no_args)
-
- for n in range(0, 32):
- add('DW_OP_lit%s' % n, self._visit_OP_with_no_args)
- add('DW_OP_reg%s' % n, self._visit_OP_with_no_args)
- add('DW_OP_breg%s' % n,
- self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
-
- add('DW_OP_fbreg',
- self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
- add('DW_OP_regx',
- self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
- add('DW_OP_bregx',
- self._make_visitor_arg_struct2(
- self.structs.Dwarf_uleb128(''),
- self.structs.Dwarf_sleb128('')))
- add('DW_OP_piece',
- self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
- add('DW_OP_bit_piece',
- self._make_visitor_arg_struct2(
- self.structs.Dwarf_uleb128(''),
- self.structs.Dwarf_uleb128('')))
- add('DW_OP_deref_size',
- self._make_visitor_arg_struct(self.structs.Dwarf_int8('')))
- add('DW_OP_xderef_size',
- self._make_visitor_arg_struct(self.structs.Dwarf_int8('')))
- add('DW_OP_call2',
- self._make_visitor_arg_struct(self.structs.Dwarf_uint16('')))
- add('DW_OP_call4',
- self._make_visitor_arg_struct(self.structs.Dwarf_uint32('')))
- add('DW_OP_call_ref',
- self._make_visitor_arg_struct(self.structs.Dwarf_offset('')))
-
-
DwarfExprOp = namedtuple('DwarfExprOp', 'op op_name args')