changed line program entries to contain commands and arguments, AND state. this allow...
[pyelftools.git] / elftools / dwarf / location_expr.py
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/location_expr.py
3 #
4 # Decoding DWARF location expressions
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from cStringIO import StringIO
10
11 from ..common.utils import struct_parse, bytelist2string
12
13
14 # Location expression opcodes. name -> opcode mapping
15 DW_OP_name2opcode = dict(
16 DW_OP_addr=0x03,
17 DW_OP_deref=0x06,
18 DW_OP_const1u=0x08,
19 DW_OP_const1s=0x09,
20 DW_OP_const2u=0x0a,
21 DW_OP_const2s=0x0b,
22 DW_OP_const4u=0x0c,
23 DW_OP_const4s=0x0d,
24 DW_OP_const8u=0x0e,
25 DW_OP_const8s=0x0f,
26 DW_OP_constu=0x10,
27 DW_OP_consts=0x11,
28 DW_OP_dup=0x12,
29 DW_OP_drop=0x13,
30 DW_OP_over=0x14,
31 DW_OP_pick=0x15,
32 DW_OP_swap=0x16,
33 DW_OP_rot=0x17,
34 DW_OP_xderef=0x18,
35 DW_OP_abs=0x19,
36 DW_OP_and=0x1a,
37 DW_OP_div=0x1b,
38 DW_OP_minus=0x1c,
39 DW_OP_mod=0x1d,
40 DW_OP_mul=0x1e,
41 DW_OP_neg=0x1f,
42 DW_OP_not=0x20,
43 DW_OP_or=0x21,
44 DW_OP_plus=0x22,
45 DW_OP_plus_uconst=0x23,
46 DW_OP_shl=0x24,
47 DW_OP_shr=0x25,
48 DW_OP_shra=0x26,
49 DW_OP_xor=0x27,
50 DW_OP_bra=0x28,
51 DW_OP_eq=0x29,
52 DW_OP_ge=0x2a,
53 DW_OP_gt=0x2b,
54 DW_OP_le=0x2c,
55 DW_OP_lt=0x2d,
56 DW_OP_ne=0x2e,
57 DW_OP_skip=0x2f,
58 DW_OP_regx=0x90,
59 DW_OP_fbreg=0x91,
60 DW_OP_bregx=0x92,
61 DW_OP_piece=0x93,
62 DW_OP_deref_size=0x94,
63 DW_OP_xderef_size=0x95,
64 DW_OP_nop=0x96,
65 DW_OP_push_object_address=0x97,
66 DW_OP_call2=0x98,
67 DW_OP_call4=0x99,
68 DW_OP_call_ref=0x9a,
69 DW_OP_form_tls_address=0x9b,
70 DW_OP_call_frame_cfa=0x9c,
71 DW_OP_bit_piece=0x9d,
72 )
73
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.
78 """
79 for index in range(index_start, index_end + 1):
80 name = '%s%s' % (prefix, index)
81 value = value_start + index - index_start
82 map[name] = value
83
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)
87
88 # opcode -> name mapping
89 DW_OP_opcode2name = dict((v, k) for k, v in DW_OP_name2opcode.iteritems())
90
91
92 class GenericLocationExprVisitor(object):
93 def __init__(self, structs):
94 self.structs = structs
95 self._init_dispatch_table()
96 self.stream = None
97 self._cur_opcode = None
98 self._cur_opcode_name = None
99 self._cur_args = []
100
101 def process_expr(self, loc_expr):
102 """ Process (visit) a location expression. Currently two possible
103 types are supported for expr:
104
105 1. File-like stream object
106 2. List of byte values (the result of parsed DW_FORM_block*
107 attributes).
108 """
109 if hasattr(loc_expr, 'read') and hasattr(loc_expr, 'seek'):
110 # looks like a stream
111 self.stream = loc_expr
112 else:
113 self.stream = StringIO(bytelist2string(loc_expr))
114
115 while True:
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)
119 if len(byte) == 0:
120 break
121
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
127 self._cur_args = []
128
129 # Dispatch to a visitor function
130 visitor = self._dispatch_table.get(
131 self._cur_opcode,
132 self._default_visitor)
133 visitor(self._cur_opcode, self._cur_opcode_name)
134
135 # Finally call the post-visit function
136 self._after_visit(
137 self._cur_opcode, self._cur_opcode_name, self._cur_args)
138
139 def _after_visit(self, opcode, opcode_name, args):
140 pass
141
142 def _default_visitor(self, opcode, opcode_name):
143 pass
144
145 def _visit_OP_with_no_args(self, opcode, opcode_name):
146 self._cur_args = []
147
148 def _visit_OP_addr(self, opcode, opcode_name):
149 self._cur_args = [
150 struct_parse(self.structs.Dwarf_target_addr(''), self.stream)]
151
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.
155 """
156 def visitor(opcode, opcode_name):
157 self._cur_args = [struct_parse(struct_arg, self.stream)]
158 return visitor
159
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.
163 """
164 def visitor(opcode, opcode_name):
165 self._cur_args = [
166 struct_parse(struct_arg1, self.stream),
167 struct_parse(struct_arg2, self.stream)]
168 return visitor
169
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
174
175 add('DW_OP_addr', self._visit_OP_addr)
176 add('DW_OP_const1u',
177 self._make_visitor_arg_struct(self.structs.Dwarf_uint8('')))
178 add('DW_OP_const1s',
179 self._make_visitor_arg_struct(self.structs.Dwarf_int8('')))
180 add('DW_OP_const2u',
181 self._make_visitor_arg_struct(self.structs.Dwarf_uint16('')))
182 add('DW_OP_const2s',
183 self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
184 add('DW_OP_const4u',
185 self._make_visitor_arg_struct(self.structs.Dwarf_uint32('')))
186 add('DW_OP_const4s',
187 self._make_visitor_arg_struct(self.structs.Dwarf_int32('')))
188 add('DW_OP_const8u',
189 self._make_visitor_arg_struct2(
190 self.structs.Dwarf_uint32(''),
191 self.structs.Dwarf_uint32('')))
192 add('DW_OP_const8s',
193 self._make_visitor_arg_struct2(
194 self.structs.Dwarf_int32(''),
195 self.structs.Dwarf_int32('')))
196 add('DW_OP_constu',
197 self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
198 add('DW_OP_consts',
199 self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
200 add('DW_OP_pick',
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('')))
204 add('DW_OP_bra',
205 self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
206 add('DW_OP_skip',
207 self._make_visitor_arg_struct(self.structs.Dwarf_int16('')))
208
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)
219
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('')))
225
226 add('DW_OP_fbreg',
227 self._make_visitor_arg_struct(self.structs.Dwarf_sleb128('')))
228 add('DW_OP_regx',
229 self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
230 add('DW_OP_bregx',
231 self._make_visitor_arg_struct2(
232 self.structs.Dwarf_uleb128(''),
233 self.structs.Dwarf_sleb128('')))
234 add('DW_OP_piece',
235 self._make_visitor_arg_struct(self.structs.Dwarf_uleb128('')))
236 add('DW_OP_bit_piece',
237 self._make_visitor_arg_struct2(
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('')))
244 add('DW_OP_call2',
245 self._make_visitor_arg_struct(self.structs.Dwarf_uint16('')))
246 add('DW_OP_call4',
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('')))
250
251
252 class LocationExpressionDumper(GenericLocationExprVisitor):
253 def __init__(self, structs):
254 super(LocationExpressionDumper, self).__init__(structs)
255 self._init_lookups()
256 self._str_parts = []
257
258 def clear(self):
259 self._str_parts = []
260
261 def get_str(self):
262 return '; '.join(self._str_parts)
263
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',])
271
272 for n in range(0, 32):
273 self._ops_with_decimal_arg.add('DW_OP_breg%s' % n)
274
275 self._ops_with_two_decimal_args = set([
276 'DW_OP_const8u', 'DW_OP_const8s', 'DW_OP_bregx', 'DW_OP_bit_piece'])
277
278 self._ops_with_hex_arg = set(
279 ['DW_OP_addr', 'DW_OP_call2', 'DW_OP_call4', 'DW_OP_call_ref'])
280
281 def _after_visit(self, opcode, opcode_name, args):
282 self._str_parts.append(self._dump_to_string(opcode, opcode_name, args))
283
284 def _dump_to_string(self, opcode, opcode_name, args):
285 if len(args) == 0:
286 return opcode_name
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])
293 else:
294 return '<unknown %s>' % opcode_name
295
296
297