1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/dwarf_expr.py
4 # Decoding DWARF expressions
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from ..common.py3compat import BytesIO, iteritems
10 from ..common.utils import struct_parse, bytelist2string
13 # DWARF expression opcodes. name -> opcode mapping
14 DW_OP_name2opcode = dict(
44 DW_OP_plus_uconst=0x23,
61 DW_OP_deref_size=0x94,
62 DW_OP_xderef_size=0x95,
64 DW_OP_push_object_address=0x97,
68 DW_OP_form_tls_address=0x9b,
69 DW_OP_call_frame_cfa=0x9c,
73 def _generate_dynamic_values(map, prefix, index_start, index_end, value_start):
74 """ Generate values in a map (dict) dynamically. Each key starts with
75 a (string) prefix, followed by an index in the inclusive range
76 [index_start, index_end]. The values start at value_start.
78 for index in range(index_start, index_end + 1):
79 name = '%s%s' % (prefix, index)
80 value = value_start + index - index_start
83 _generate_dynamic_values(DW_OP_name2opcode, 'DW_OP_lit', 0, 31, 0x30)
84 _generate_dynamic_values(DW_OP_name2opcode, 'DW_OP_reg', 0, 31, 0x50)
85 _generate_dynamic_values(DW_OP_name2opcode, 'DW_OP_breg', 0, 31, 0x70)
87 # opcode -> name mapping
88 DW_OP_opcode2name = dict((v, k) for k, v in iteritems(DW_OP_name2opcode))
91 class GenericExprVisitor(object):
92 """ A DWARF expression is a sequence of instructions encoded in a block
93 of bytes. This class decodes the sequence into discrete instructions
94 with their arguments and allows generic "visiting" to process them.
96 Usage: subclass this class, and override the needed methods. The
97 easiest way would be to just override _after_visit, which gets passed
98 each decoded instruction (with its arguments) in order. Clients of
99 the visitor then just execute process_expr. The subclass can keep
100 its own internal information updated in _after_visit and provide
101 methods to extract it. For a good example of this usage, see the
102 ExprDumper class in the descriptions module.
104 A more complex usage could be to override visiting methods for
105 specific instructions, by placing them into the dispatch table.
107 def __init__(self, structs):
108 self.structs = structs
109 self._init_dispatch_table()
111 self._cur_opcode = None
112 self._cur_opcode_name = None
115 def process_expr(self, expr):
116 """ Process (visit) a DWARF expression. expr should be a list of
117 (integer) byte values.
119 self.stream = BytesIO(bytelist2string(expr))
122 # Get the next opcode from the stream. If nothing is left in the
123 # stream, we're done.
124 byte = self.stream.read(1)
128 # Decode the opcode and its name
129 self._cur_opcode = ord(byte)
130 self._cur_opcode_name = DW_OP_opcode2name.get(
131 self._cur_opcode, 'OP:0x%x' % self._cur_opcode)
132 # Will be filled in by visitors
135 # Dispatch to a visitor function
136 visitor = self._dispatch_table.get(
138 self._default_visitor)
139 visitor(self._cur_opcode, self._cur_opcode_name)
141 # Finally call the post-visit function
143 self._cur_opcode, self._cur_opcode_name, self._cur_args)
145 def _after_visit(self, opcode, opcode_name, args):
148 def _default_visitor(self, opcode, opcode_name):
151 def _visit_OP_with_no_args(self, opcode, opcode_name):
154 def _visit_OP_addr(self, opcode, opcode_name):
156 struct_parse(self.structs.Dwarf_target_addr(''), self.stream)]
158 def _make_visitor_arg_struct(self, struct_arg):
159 """ Create a visitor method for an opcode that that accepts a single
160 argument, specified by a struct.
162 def visitor(opcode, opcode_name):
163 self._cur_args = [struct_parse(struct_arg, self.stream)]
166 def _make_visitor_arg_struct2(self, struct_arg1, struct_arg2):
167 """ Create a visitor method for an opcode that that accepts two
168 arguments, specified by structs.
170 def visitor(opcode, opcode_name):
172 struct_parse(struct_arg1, self.stream),
173 struct_parse(struct_arg2, self.stream)]
176 def _init_dispatch_table(self):
177 self._dispatch_table = {}
178 def add(opcode_name, func):
179 self._dispatch_table[DW_OP_name2opcode[opcode_name]] = func
181 add('DW_OP_addr', self._visit_OP_addr)
183 self._make_visitor_arg_struct(self.structs.Dwarf_uint8('')))
185 self._make_visitor_arg_struct(self.structs.Dwarf_int8('')))
187 self._make_visitor_arg_struct(self.structs.Dwarf_uint16('')))
189 self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
191 self._make_visitor_arg_struct(self.structs.Dwarf_uint32('')))
193 self._make_visitor_arg_struct(self.structs.Dwarf_int32('')))
195 self._make_visitor_arg_struct2(
196 self.structs.Dwarf_uint32(''),
197 self.structs.Dwarf_uint32('')))
199 self._make_visitor_arg_struct2(
200 self.structs.Dwarf_int32(''),
201 self.structs.Dwarf_int32('')))
203 self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
205 self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
207 self._make_visitor_arg_struct(self.structs.Dwarf_uint8('')))
208 add('DW_OP_plus_uconst',
209 self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
211 self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
213 self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
215 for opname in [ 'DW_OP_deref', 'DW_OP_dup', 'DW_OP_drop', 'DW_OP_over',
216 'DW_OP_swap', 'DW_OP_swap', 'DW_OP_rot', 'DW_OP_xderef',
217 'DW_OP_abs', 'DW_OP_and', 'DW_OP_div', 'DW_OP_minus',
218 'DW_OP_mod', 'DW_OP_mul', 'DW_OP_neg', 'DW_OP_not',
219 'DW_OP_plus', 'DW_OP_shl', 'DW_OP_shr', 'DW_OP_shra',
220 'DW_OP_xor', 'DW_OP_eq', 'DW_OP_ge', 'DW_OP_gt',
221 'DW_OP_le', 'DW_OP_lt', 'DW_OP_ne', 'DW_OP_nop',
222 'DW_OP_push_object_address', 'DW_OP_form_tls_address',
223 'DW_OP_call_frame_cfa']:
224 add(opname, self._visit_OP_with_no_args)
226 for n in range(0, 32):
227 add('DW_OP_lit%s' % n, self._visit_OP_with_no_args)
228 add('DW_OP_reg%s' % n, self._visit_OP_with_no_args)
229 add('DW_OP_breg%s' % n,
230 self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
233 self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
235 self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
237 self._make_visitor_arg_struct2(
238 self.structs.Dwarf_uleb128(''),
239 self.structs.Dwarf_sleb128('')))
241 self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
242 add('DW_OP_bit_piece',
243 self._make_visitor_arg_struct2(
244 self.structs.Dwarf_uleb128(''),
245 self.structs.Dwarf_uleb128('')))
246 add('DW_OP_deref_size',
247 self._make_visitor_arg_struct(self.structs.Dwarf_int8('')))
248 add('DW_OP_xderef_size',
249 self._make_visitor_arg_struct(self.structs.Dwarf_int8('')))
251 self._make_visitor_arg_struct(self.structs.Dwarf_uint16('')))
253 self._make_visitor_arg_struct(self.structs.Dwarf_uint32('')))
254 add('DW_OP_call_ref',
255 self._make_visitor_arg_struct(self.structs.Dwarf_offset('')))