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 collections
import namedtuple
11 from ..common
.py3compat
import BytesIO
, iteritems
12 from ..common
.utils
import struct_parse
, bytelist2string
, read_blob
15 # DWARF expression opcodes. name -> opcode mapping
16 DW_OP_name2opcode
= dict(
46 DW_OP_plus_uconst
=0x23,
63 DW_OP_deref_size
=0x94,
64 DW_OP_xderef_size
=0x95,
66 DW_OP_push_object_address
=0x97,
70 DW_OP_form_tls_address
=0x9b,
71 DW_OP_call_frame_cfa
=0x9c,
73 DW_OP_implicit_value
=0x9e,
74 DW_OP_stack_value
=0x9f,
75 DW_OP_implicit_pointer
=0xa0,
78 DW_OP_entry_value
=0xa3,
79 DW_OP_const_type
=0xa4,
80 DW_OP_regval_type
=0xa5,
81 DW_OP_deref_type
=0xa6,
82 DW_OP_xderef_type
=0xa7,
84 DW_OP_reinterpret
=0xa9,
86 DW_OP_GNU_push_tls_address
=0xe0,
87 DW_OP_GNU_implicit_pointer
=0xf2,
88 DW_OP_GNU_entry_value
=0xf3,
89 DW_OP_GNU_const_type
=0xf4,
90 DW_OP_GNU_regval_type
=0xf5,
91 DW_OP_GNU_deref_type
=0xf6,
92 DW_OP_GNU_convert
=0xf7,
93 DW_OP_GNU_parameter_ref
=0xfa,
97 def _generate_dynamic_values(map, prefix
, index_start
, index_end
, value_start
):
98 """ Generate values in a map (dict) dynamically. Each key starts with
99 a (string) prefix, followed by an index in the inclusive range
100 [index_start, index_end]. The values start at value_start.
102 for index
in range(index_start
, index_end
+ 1):
103 name
= '%s%s' % (prefix
, index
)
104 value
= value_start
+ index
- index_start
107 _generate_dynamic_values(DW_OP_name2opcode
, 'DW_OP_lit', 0, 31, 0x30)
108 _generate_dynamic_values(DW_OP_name2opcode
, 'DW_OP_reg', 0, 31, 0x50)
109 _generate_dynamic_values(DW_OP_name2opcode
, 'DW_OP_breg', 0, 31, 0x70)
111 # opcode -> name mapping
112 DW_OP_opcode2name
= dict((v
, k
) for k
, v
in iteritems(DW_OP_name2opcode
))
115 # Each parsed DWARF expression is returned as this type with its numeric opcode,
116 # op name (as a string) and a list of arguments.
117 DWARFExprOp
= namedtuple('DWARFExprOp', 'op op_name args')
120 class DWARFExprParser(object):
121 """DWARF expression parser.
123 When initialized, requires structs to cache a dispatch table. After that,
124 parse_expr can be called repeatedly - it's stateless.
127 def __init__(self
, structs
):
128 self
._dispatch
_table
= _init_dispatch_table(structs
)
130 def parse_expr(self
, expr
):
131 """ Parses expr (a list of integers) into a list of DWARFExprOp.
133 The list can potentially be nested.
135 stream
= BytesIO(bytelist2string(expr
))
139 # Get the next opcode from the stream. If nothing is left in the
140 # stream, we're done.
141 byte
= stream
.read(1)
145 # Decode the opcode and its name.
147 op_name
= DW_OP_opcode2name
.get(op
, 'OP:0x%x' % op
)
149 # Use dispatch table to parse args.
150 arg_parser
= self
._dispatch
_table
[op
]
151 args
= arg_parser(stream
)
153 parsed
.append(DWARFExprOp(op
=op
, op_name
=op_name
, args
=args
))
158 def _init_dispatch_table(structs
):
159 """Creates a dispatch table for parsing args of an op.
161 Returns a dict mapping opcode to a function. The function accepts a stream
162 and return a list of parsed arguments for the opcode from the stream;
163 the stream is advanced by the function as needed.
166 def add(opcode_name
, func
):
167 table
[DW_OP_name2opcode
[opcode_name
]] = func
170 return lambda stream
: []
173 return lambda stream
: [struct_parse(structs
.Dwarf_target_addr(''),
176 def parse_arg_struct(arg_struct
):
177 return lambda stream
: [struct_parse(arg_struct
, stream
)]
179 def parse_arg_struct2(arg1_struct
, arg2_struct
):
180 return lambda stream
: [struct_parse(arg1_struct
, stream
),
181 struct_parse(arg2_struct
, stream
)]
183 # ULEB128, then an expression of that length
184 def parse_nestedexpr():
186 size
= struct_parse(structs
.Dwarf_uleb128(''), stream
)
187 nested_expr_blob
= read_blob(stream
, size
)
188 return [DWARFExprParser(structs
).parse_expr(nested_expr_blob
)]
191 # ULEB128, then a blob of that size
193 return lambda stream
: [read_blob(stream
, struct_parse(structs
.Dwarf_uleb128(''), stream
))]
195 # ULEB128 with datatype DIE offset, then byte, then a blob of that size
196 def parse_typedblob():
197 return lambda stream
: [struct_parse(structs
.Dwarf_uleb128(''), stream
), read_blob(stream
, struct_parse(structs
.Dwarf_uint8(''), stream
))]
199 add('DW_OP_addr', parse_op_addr())
200 add('DW_OP_addrx', parse_arg_struct(structs
.Dwarf_uleb128('')))
201 add('DW_OP_const1u', parse_arg_struct(structs
.Dwarf_uint8('')))
202 add('DW_OP_const1s', parse_arg_struct(structs
.Dwarf_int8('')))
203 add('DW_OP_const2u', parse_arg_struct(structs
.Dwarf_uint16('')))
204 add('DW_OP_const2s', parse_arg_struct(structs
.Dwarf_int16('')))
205 add('DW_OP_const4u', parse_arg_struct(structs
.Dwarf_uint32('')))
206 add('DW_OP_const4s', parse_arg_struct(structs
.Dwarf_int32('')))
207 add('DW_OP_const8u', parse_arg_struct(structs
.Dwarf_uint64('')))
208 add('DW_OP_const8s', parse_arg_struct(structs
.Dwarf_int64('')))
209 add('DW_OP_constu', parse_arg_struct(structs
.Dwarf_uleb128('')))
210 add('DW_OP_consts', parse_arg_struct(structs
.Dwarf_sleb128('')))
211 add('DW_OP_pick', parse_arg_struct(structs
.Dwarf_uint8('')))
212 add('DW_OP_plus_uconst', parse_arg_struct(structs
.Dwarf_uleb128('')))
213 add('DW_OP_bra', parse_arg_struct(structs
.Dwarf_int16('')))
214 add('DW_OP_skip', parse_arg_struct(structs
.Dwarf_int16('')))
216 for opname
in [ 'DW_OP_deref', 'DW_OP_dup', 'DW_OP_drop', 'DW_OP_over',
217 'DW_OP_swap', 'DW_OP_swap', 'DW_OP_rot', 'DW_OP_xderef',
218 'DW_OP_abs', 'DW_OP_and', 'DW_OP_div', 'DW_OP_minus',
219 'DW_OP_mod', 'DW_OP_mul', 'DW_OP_neg', 'DW_OP_not',
220 'DW_OP_or', 'DW_OP_plus', 'DW_OP_shl', 'DW_OP_shr',
221 'DW_OP_shra', 'DW_OP_xor', 'DW_OP_eq', 'DW_OP_ge',
222 'DW_OP_gt', 'DW_OP_le', 'DW_OP_lt', 'DW_OP_ne', 'DW_OP_nop',
223 'DW_OP_push_object_address', 'DW_OP_form_tls_address',
224 'DW_OP_call_frame_cfa', 'DW_OP_stack_value',
225 'DW_OP_GNU_push_tls_address']:
226 add(opname
, parse_noargs())
228 for n
in range(0, 32):
229 add('DW_OP_lit%s' % n
, parse_noargs())
230 add('DW_OP_reg%s' % n
, parse_noargs())
231 add('DW_OP_breg%s' % n
, parse_arg_struct(structs
.Dwarf_sleb128('')))
233 add('DW_OP_fbreg', parse_arg_struct(structs
.Dwarf_sleb128('')))
234 add('DW_OP_regx', parse_arg_struct(structs
.Dwarf_uleb128('')))
235 add('DW_OP_bregx', parse_arg_struct2(structs
.Dwarf_uleb128(''),
236 structs
.Dwarf_sleb128('')))
237 add('DW_OP_piece', parse_arg_struct(structs
.Dwarf_uleb128('')))
238 add('DW_OP_bit_piece', parse_arg_struct2(structs
.Dwarf_uleb128(''),
239 structs
.Dwarf_uleb128('')))
240 add('DW_OP_deref_size', parse_arg_struct(structs
.Dwarf_int8('')))
241 add('DW_OP_xderef_size', parse_arg_struct(structs
.Dwarf_int8('')))
242 add('DW_OP_call2', parse_arg_struct(structs
.Dwarf_uint16('')))
243 add('DW_OP_call4', parse_arg_struct(structs
.Dwarf_uint32('')))
244 add('DW_OP_call_ref', parse_arg_struct(structs
.Dwarf_offset('')))
245 add('DW_OP_implicit_value', parse_blob())
246 add('DW_OP_GNU_entry_value', parse_nestedexpr())
247 add('DW_OP_GNU_const_type', parse_typedblob())
248 add('DW_OP_GNU_regval_type', parse_arg_struct2(structs
.Dwarf_uleb128(''),
249 structs
.Dwarf_uleb128('')))
250 add('DW_OP_GNU_deref_type', parse_arg_struct2(structs
.Dwarf_uint8(''),
251 structs
.Dwarf_uleb128('')))
252 add('DW_OP_GNU_implicit_pointer', parse_arg_struct2(structs
.Dwarf_offset(''),
253 structs
.Dwarf_sleb128('')))
254 add('DW_OP_GNU_parameter_ref', parse_arg_struct(structs
.Dwarf_offset('')))
255 add('DW_OP_GNU_convert', parse_arg_struct(structs
.Dwarf_uleb128('')))