1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/location_expr.py
4 # Decoding DWARF location expressions
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from cStringIO
import StringIO
11 from ..common
.utils
import struct_parse
, bytelist2string
14 # Location expression opcodes. name -> opcode mapping
15 DW_OP_name2opcode
= dict(
45 DW_OP_plus_uconst
=0x23,
62 DW_OP_deref_size
=0x94,
63 DW_OP_xderef_size
=0x95,
65 DW_OP_push_object_address
=0x97,
69 DW_OP_form_tls_address
=0x9b,
70 DW_OP_call_frame_cfa
=0x9c,
74 def _generate_dynamic_values(map, prefix
, index_start
, index_end
, value_start
):
75 """ Generate values in a map (dict) dynamically. Each key starts with
76 a (string) prefix, followed by an index in the inclusive range
77 [index_start, index_end]. The values start at value_start.
79 for index
in range(index_start
, index_end
+ 1):
80 name
= '%s%s' % (prefix
, index
)
81 value
= value_start
+ index
- index_start
84 _generate_dynamic_values(DW_OP_name2opcode
, 'DW_OP_lit', 0, 31, 0x30)
85 _generate_dynamic_values(DW_OP_name2opcode
, 'DW_OP_reg', 0, 31, 0x50)
86 _generate_dynamic_values(DW_OP_name2opcode
, 'DW_OP_breg', 0, 31, 0x70)
88 # opcode -> name mapping
89 DW_OP_opcode2name
= dict((v
, k
) for k
, v
in DW_OP_name2opcode
.iteritems())
92 class GenericLocationExprVisitor(object):
93 def __init__(self
, structs
):
94 self
.structs
= structs
95 self
._init
_dispatch
_table
()
97 self
._cur
_opcode
= None
98 self
._cur
_opcode
_name
= None
101 def process_expr(self
, loc_expr
):
102 """ Process (visit) a location expression. Currently two possible
103 types are supported for expr:
105 1. File-like stream object
106 2. List of byte values (the result of parsed DW_FORM_block*
109 if hasattr(loc_expr
, 'read') and hasattr(loc_expr
, 'seek'):
110 # looks like a stream
111 self
.stream
= loc_expr
113 self
.stream
= StringIO(bytelist2string(loc_expr
))
116 # Get the next opcode from the stream. If nothing is left in the
117 # stream, we're done.
118 byte
= self
.stream
.read(1)
122 # Decode the opcode and its name
123 self
._cur
_opcode
= ord(byte
)
124 self
._cur
_opcode
_name
= DW_OP_opcode2name
.get(
125 self
._cur
_opcode
, 'OP:0x%x' % self
._cur
_opcode
)
126 # Will be filled in by visitors
129 # Dispatch to a visitor function
130 visitor
= self
._dispatch
_table
.get(
132 self
._default
_visitor
)
133 visitor(self
._cur
_opcode
, self
._cur
_opcode
_name
)
135 # Finally call the post-visit function
137 self
._cur
_opcode
, self
._cur
_opcode
_name
, self
._cur
_args
)
139 def _after_visit(self
, opcode
, opcode_name
, args
):
142 def _default_visitor(self
, opcode
, opcode_name
):
145 def _visit_OP_with_no_args(self
, opcode
, opcode_name
):
148 def _visit_OP_addr(self
, opcode
, opcode_name
):
150 struct_parse(self
.structs
.Dwarf_target_addr(''), self
.stream
)]
152 def _make_visitor_arg_struct(self
, struct_arg
):
153 """ Create a visitor method for an opcode that that accepts a single
154 argument, specified by a struct.
156 def visitor(opcode
, opcode_name
):
157 self
._cur
_args
= [struct_parse(struct_arg
, self
.stream
)]
160 def _make_visitor_arg_struct2(self
, struct_arg1
, struct_arg2
):
161 """ Create a visitor method for an opcode that that accepts two
162 arguments, specified by structs.
164 def visitor(opcode
, opcode_name
):
166 struct_parse(struct_arg1
, self
.stream
),
167 struct_parse(struct_arg2
, self
.stream
)]
170 def _init_dispatch_table(self
):
171 self
._dispatch
_table
= {}
172 def add(opcode_name
, func
):
173 self
._dispatch
_table
[DW_OP_name2opcode
[opcode_name
]] = func
175 add('DW_OP_addr', self
._visit
_OP
_addr
)
177 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uint8('')))
179 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_int8('')))
181 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uint16('')))
183 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_int16('')))
185 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uint32('')))
187 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_int32('')))
189 self
._make
_visitor
_arg
_struct
2(
190 self
.structs
.Dwarf_uint32(''),
191 self
.structs
.Dwarf_uint32('')))
193 self
._make
_visitor
_arg
_struct
2(
194 self
.structs
.Dwarf_int32(''),
195 self
.structs
.Dwarf_int32('')))
197 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uleb128('')))
199 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_sleb128('')))
201 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uint8('')))
202 add('DW_OP_plus_uconst',
203 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uleb128('')))
205 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_int16('')))
207 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_int16('')))
209 for opname
in [ 'DW_OP_deref', 'DW_OP_dup', 'DW_OP_drop', 'DW_OP_over',
210 'DW_OP_swap', 'DW_OP_swap', 'DW_OP_rot', 'DW_OP_xderef',
211 'DW_OP_abs', 'DW_OP_and', 'DW_OP_div', 'DW_OP_minus',
212 'DW_OP_mod', 'DW_OP_mul', 'DW_OP_neg', 'DW_OP_not',
213 'DW_OP_plus', 'DW_OP_shl', 'DW_OP_shr', 'DW_OP_shra',
214 'DW_OP_xor', 'DW_OP_eq', 'DW_OP_ge', 'DW_OP_gt',
215 'DW_OP_le', 'DW_OP_lt', 'DW_OP_ne', 'DW_OP_nop',
216 'DW_OP_push_object_address', 'DW_OP_form_tls_address',
217 'DW_OP_call_frame_cfa']:
218 add(opname
, self
._visit
_OP
_with
_no
_args
)
220 for n
in range(0, 32):
221 add('DW_OP_lit%s' % n
, self
._visit
_OP
_with
_no
_args
)
222 add('DW_OP_reg%s' % n
, self
._visit
_OP
_with
_no
_args
)
223 add('DW_OP_breg%s' % n
,
224 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_sleb128('')))
227 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_sleb128('')))
229 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uleb128('')))
231 self
._make
_visitor
_arg
_struct
2(
232 self
.structs
.Dwarf_uleb128(''),
233 self
.structs
.Dwarf_sleb128('')))
235 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uleb128('')))
236 add('DW_OP_bit_piece',
237 self
._make
_visitor
_arg
_struct
2(
238 self
.structs
.Dwarf_uleb128(''),
239 self
.structs
.Dwarf_uleb128('')))
240 add('DW_OP_deref_size',
241 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_int8('')))
242 add('DW_OP_xderef_size',
243 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_int8('')))
245 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uint16('')))
247 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_uint32('')))
248 add('DW_OP_call_ref',
249 self
._make
_visitor
_arg
_struct
(self
.structs
.Dwarf_offset('')))
252 class LocationExpressionDumper(GenericLocationExprVisitor
):
253 def __init__(self
, structs
):
254 super(LocationExpressionDumper
, self
).__init
__(structs
)
262 return '; '.join(self
._str
_parts
)
264 def _init_lookups(self
):
265 self
._ops
_with
_decimal
_arg
= set([
266 'DW_OP_const1u', 'DW_OP_const1s', 'DW_OP_const2u', 'DW_OP_const2s',
267 'DW_OP_const4u', 'DW_OP_const4s', 'DW_OP_constu', 'DW_OP_consts',
268 'DW_OP_pick', 'DW_OP_plus_uconst', 'DW_OP_bra', 'DW_OP_skip',
269 'DW_OP_fbreg', 'DW_OP_piece', 'DW_OP_deref_size',
270 'DW_OP_xderef_size', 'DW_OP_regx',])
272 for n
in range(0, 32):
273 self
._ops
_with
_decimal
_arg
.add('DW_OP_breg%s' % n
)
275 self
._ops
_with
_two
_decimal
_args
= set([
276 'DW_OP_const8u', 'DW_OP_const8s', 'DW_OP_bregx', 'DW_OP_bit_piece'])
278 self
._ops
_with
_hex
_arg
= set(
279 ['DW_OP_addr', 'DW_OP_call2', 'DW_OP_call4', 'DW_OP_call_ref'])
281 def _after_visit(self
, opcode
, opcode_name
, args
):
282 self
._str
_parts
.append(self
._dump
_to
_string
(opcode
, opcode_name
, args
))
284 def _dump_to_string(self
, opcode
, opcode_name
, args
):
287 elif opcode_name
in self
._ops
_with
_decimal
_arg
:
288 return '%s: %s' % (opcode_name
, args
[0])
289 elif opcode_name
in self
._ops
_with
_hex
_arg
:
290 return '%s: %x' % (opcode_name
, args
[0])
291 elif opcode_name
in self
._ops
_with
_two
_decimal
_args
:
292 return '%s: %s %s' % (opcode_name
, args
[0], args
[1])
294 return '<unknown %s>' % opcode_name