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
_struct
2(
196 self
.structs
.Dwarf_uint32(''),
197 self
.structs
.Dwarf_uint32('')))
199 self
._make
_visitor
_arg
_struct
2(
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
_struct
2(
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
_struct
2(
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('')))