/src/libunwind/src/dwarf/Gexpr.c
Line | Count | Source |
1 | | /* libunwind - a platform-independent unwind library |
2 | | Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. |
3 | | Contributed by David Mosberger-Tang <davidm@hpl.hp.com> |
4 | | |
5 | | This file is part of libunwind. |
6 | | |
7 | | Permission is hereby granted, free of charge, to any person obtaining |
8 | | a copy of this software and associated documentation files (the |
9 | | "Software"), to deal in the Software without restriction, including |
10 | | without limitation the rights to use, copy, modify, merge, publish, |
11 | | distribute, sublicense, and/or sell copies of the Software, and to |
12 | | permit persons to whom the Software is furnished to do so, subject to |
13 | | the following conditions: |
14 | | |
15 | | The above copyright notice and this permission notice shall be |
16 | | included in all copies or substantial portions of the Software. |
17 | | |
18 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
19 | | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
20 | | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
21 | | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
22 | | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
23 | | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
24 | | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
25 | | |
26 | | #include "dwarf_i.h" |
27 | | #include "libunwind_i.h" |
28 | | |
29 | | /* The "pick" operator provides an index range of 0..255 indicating |
30 | | that the stack could at least have a depth of up to 256 elements, |
31 | | but the GCC unwinder restricts the depth to 64, which seems |
32 | | reasonable so we use the same value here. */ |
33 | 0 | #define MAX_EXPR_STACK_SIZE 64 |
34 | | |
35 | 0 | #define NUM_OPERANDS(signature) (((signature) >> 6) & 0x3) |
36 | 0 | #define OPND1_TYPE(signature) (((signature) >> 3) & 0x7) |
37 | 0 | #define OPND2_TYPE(signature) (((signature) >> 0) & 0x7) |
38 | | |
39 | | #define OPND_SIGNATURE(n, t1, t2) (((n) << 6) | ((t1) << 3) | ((t2) << 0)) |
40 | | #define OPND1(t1) OPND_SIGNATURE(1, t1, 0) |
41 | | #define OPND2(t1, t2) OPND_SIGNATURE(2, t1, t2) |
42 | | |
43 | 0 | #define VAL8 0x0 |
44 | 0 | #define VAL16 0x1 |
45 | 0 | #define VAL32 0x2 |
46 | 0 | #define VAL64 0x3 |
47 | 0 | #define ULEB128 0x4 |
48 | 0 | #define SLEB128 0x5 |
49 | 0 | #define OFFSET 0x6 /* 32-bit offset for 32-bit DWARF, 64-bit otherwise */ |
50 | 0 | #define ADDR 0x7 /* Machine address. */ |
51 | | |
52 | | static const uint8_t operands[256] = |
53 | | { |
54 | | [DW_OP_addr] = OPND1 (ADDR), |
55 | | [DW_OP_const1u] = OPND1 (VAL8), |
56 | | [DW_OP_const1s] = OPND1 (VAL8), |
57 | | [DW_OP_const2u] = OPND1 (VAL16), |
58 | | [DW_OP_const2s] = OPND1 (VAL16), |
59 | | [DW_OP_const4u] = OPND1 (VAL32), |
60 | | [DW_OP_const4s] = OPND1 (VAL32), |
61 | | [DW_OP_const8u] = OPND1 (VAL64), |
62 | | [DW_OP_const8s] = OPND1 (VAL64), |
63 | | [DW_OP_constu] = OPND1 (ULEB128), |
64 | | [DW_OP_consts] = OPND1 (SLEB128), |
65 | | [DW_OP_pick] = OPND1 (VAL8), |
66 | | [DW_OP_plus_uconst] = OPND1 (ULEB128), |
67 | | [DW_OP_skip] = OPND1 (VAL16), |
68 | | [DW_OP_bra] = OPND1 (VAL16), |
69 | | [DW_OP_breg0 + 0] = OPND1 (SLEB128), |
70 | | [DW_OP_breg0 + 1] = OPND1 (SLEB128), |
71 | | [DW_OP_breg0 + 2] = OPND1 (SLEB128), |
72 | | [DW_OP_breg0 + 3] = OPND1 (SLEB128), |
73 | | [DW_OP_breg0 + 4] = OPND1 (SLEB128), |
74 | | [DW_OP_breg0 + 5] = OPND1 (SLEB128), |
75 | | [DW_OP_breg0 + 6] = OPND1 (SLEB128), |
76 | | [DW_OP_breg0 + 7] = OPND1 (SLEB128), |
77 | | [DW_OP_breg0 + 8] = OPND1 (SLEB128), |
78 | | [DW_OP_breg0 + 9] = OPND1 (SLEB128), |
79 | | [DW_OP_breg0 + 10] = OPND1 (SLEB128), |
80 | | [DW_OP_breg0 + 11] = OPND1 (SLEB128), |
81 | | [DW_OP_breg0 + 12] = OPND1 (SLEB128), |
82 | | [DW_OP_breg0 + 13] = OPND1 (SLEB128), |
83 | | [DW_OP_breg0 + 14] = OPND1 (SLEB128), |
84 | | [DW_OP_breg0 + 15] = OPND1 (SLEB128), |
85 | | [DW_OP_breg0 + 16] = OPND1 (SLEB128), |
86 | | [DW_OP_breg0 + 17] = OPND1 (SLEB128), |
87 | | [DW_OP_breg0 + 18] = OPND1 (SLEB128), |
88 | | [DW_OP_breg0 + 19] = OPND1 (SLEB128), |
89 | | [DW_OP_breg0 + 20] = OPND1 (SLEB128), |
90 | | [DW_OP_breg0 + 21] = OPND1 (SLEB128), |
91 | | [DW_OP_breg0 + 22] = OPND1 (SLEB128), |
92 | | [DW_OP_breg0 + 23] = OPND1 (SLEB128), |
93 | | [DW_OP_breg0 + 24] = OPND1 (SLEB128), |
94 | | [DW_OP_breg0 + 25] = OPND1 (SLEB128), |
95 | | [DW_OP_breg0 + 26] = OPND1 (SLEB128), |
96 | | [DW_OP_breg0 + 27] = OPND1 (SLEB128), |
97 | | [DW_OP_breg0 + 28] = OPND1 (SLEB128), |
98 | | [DW_OP_breg0 + 29] = OPND1 (SLEB128), |
99 | | [DW_OP_breg0 + 30] = OPND1 (SLEB128), |
100 | | [DW_OP_breg0 + 31] = OPND1 (SLEB128), |
101 | | [DW_OP_regx] = OPND1 (ULEB128), |
102 | | [DW_OP_fbreg] = OPND1 (SLEB128), |
103 | | [DW_OP_bregx] = OPND2 (ULEB128, SLEB128), |
104 | | [DW_OP_piece] = OPND1 (ULEB128), |
105 | | [DW_OP_deref_size] = OPND1 (VAL8), |
106 | | [DW_OP_xderef_size] = OPND1 (VAL8), |
107 | | [DW_OP_call2] = OPND1 (VAL16), |
108 | | [DW_OP_call4] = OPND1 (VAL32), |
109 | | [DW_OP_call_ref] = OPND1 (OFFSET) |
110 | | }; |
111 | | |
112 | | static inline unw_sword_t |
113 | | sword (unw_addr_space_t as UNUSED, unw_word_t val) |
114 | 0 | { |
115 | 0 | switch (dwarf_addr_size (as)) |
116 | 0 | { |
117 | 0 | case 1: return (int8_t) val; |
118 | 0 | case 2: return (int16_t) val; |
119 | 0 | case 4: return (int32_t) val; |
120 | 0 | case 8: return (int64_t) val; |
121 | 0 | default: abort (); |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | static inline int |
126 | | read_operand (unw_addr_space_t as, unw_accessors_t *a, |
127 | | unw_word_t *addr, int operand_type, unw_word_t *val, void *arg) |
128 | 0 | { |
129 | 0 | uint8_t u8; |
130 | 0 | uint16_t u16; |
131 | 0 | uint32_t u32; |
132 | 0 | uint64_t u64; |
133 | 0 | int ret; |
134 | |
|
135 | 0 | if (operand_type == ADDR) |
136 | 0 | switch (dwarf_addr_size (as)) |
137 | 0 | { |
138 | 0 | case 1: operand_type = VAL8; break; |
139 | 0 | case 2: operand_type = VAL16; break; |
140 | 0 | case 4: operand_type = VAL32; break; |
141 | 0 | case 8: operand_type = VAL64; break; |
142 | 0 | default: abort (); |
143 | 0 | } |
144 | | |
145 | 0 | switch (operand_type) |
146 | 0 | { |
147 | 0 | case VAL8: |
148 | 0 | ret = dwarf_readu8 (as, a, addr, &u8, arg); |
149 | 0 | if (ret < 0) |
150 | 0 | return ret; |
151 | 0 | *val = u8; |
152 | 0 | break; |
153 | | |
154 | 0 | case VAL16: |
155 | 0 | ret = dwarf_readu16 (as, a, addr, &u16, arg); |
156 | 0 | if (ret < 0) |
157 | 0 | return ret; |
158 | 0 | *val = u16; |
159 | 0 | break; |
160 | | |
161 | 0 | case VAL32: |
162 | 0 | ret = dwarf_readu32 (as, a, addr, &u32, arg); |
163 | 0 | if (ret < 0) |
164 | 0 | return ret; |
165 | 0 | *val = u32; |
166 | 0 | break; |
167 | | |
168 | 0 | case VAL64: |
169 | 0 | ret = dwarf_readu64 (as, a, addr, &u64, arg); |
170 | 0 | if (ret < 0) |
171 | 0 | return ret; |
172 | 0 | *val = (unw_word_t) u64; |
173 | 0 | break; |
174 | | |
175 | 0 | case ULEB128: |
176 | 0 | ret = dwarf_read_uleb128 (as, a, addr, val, arg); |
177 | 0 | break; |
178 | | |
179 | 0 | case SLEB128: |
180 | 0 | ret = dwarf_read_sleb128 (as, a, addr, val, arg); |
181 | 0 | break; |
182 | | |
183 | 0 | case OFFSET: /* only used by DW_OP_call_ref, which we don't implement */ |
184 | 0 | default: |
185 | 0 | Debug (1, "Unexpected operand type %d\n", operand_type); |
186 | 0 | ret = -UNW_EINVAL; |
187 | 0 | } |
188 | 0 | return ret; |
189 | 0 | } |
190 | | |
191 | | HIDDEN int |
192 | | dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr, |
193 | 0 | unw_word_t rbp_addr, unw_word_t *cfa_offset) { |
194 | 0 | unw_accessors_t *a; |
195 | 0 | int ret; |
196 | 0 | void *arg; |
197 | 0 | unw_word_t len; |
198 | 0 | uint8_t opcode; |
199 | 0 | unw_word_t operand1; |
200 | |
|
201 | 0 | a = unw_get_accessors_int (c->as); |
202 | 0 | arg = c->as_arg; |
203 | |
|
204 | 0 | ret = dwarf_read_uleb128(c->as, a, &rbp_addr, &len, arg); |
205 | 0 | if (len != 2 || ret < 0) |
206 | 0 | return 0; |
207 | | |
208 | 0 | ret = dwarf_readu8(c->as, a, &rbp_addr, &opcode, arg); |
209 | 0 | if (ret < 0 || opcode != DW_OP_breg6) |
210 | 0 | return 0; |
211 | | |
212 | 0 | ret = read_operand(c->as, a, &rbp_addr, |
213 | 0 | OPND1_TYPE(operands[opcode]), &operand1, arg); |
214 | |
|
215 | 0 | if (ret < 0 || operand1 != 0) |
216 | 0 | return 0; |
217 | | |
218 | 0 | ret = dwarf_read_uleb128(c->as, a, &cfa_addr, &len, arg); |
219 | 0 | if (ret < 0 || len != 3) |
220 | 0 | return 0; |
221 | | |
222 | 0 | ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg); |
223 | 0 | if (ret < 0 || opcode != DW_OP_breg6) |
224 | 0 | return 0; |
225 | | |
226 | 0 | ret = read_operand(c->as, a, &cfa_addr, |
227 | 0 | OPND1_TYPE(operands[opcode]), &operand1, arg); |
228 | 0 | if (ret < 0) |
229 | 0 | return 0; |
230 | | |
231 | 0 | ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg); |
232 | 0 | if (ret < 0 || opcode != DW_OP_deref) |
233 | 0 | return 0; |
234 | | |
235 | 0 | *cfa_offset = operand1; |
236 | 0 | return 1; |
237 | 0 | } |
238 | | |
239 | | HIDDEN int |
240 | | dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t stack_val, unw_word_t *addr, |
241 | | unw_word_t len, unw_word_t *valp, int *is_register) |
242 | 0 | { |
243 | 0 | unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2 = 0, tmp3, end_addr; |
244 | 0 | uint8_t opcode, operands_signature, u8; |
245 | 0 | unw_addr_space_t as; |
246 | 0 | unw_accessors_t *a; |
247 | 0 | void *arg; |
248 | 0 | unw_word_t stack[MAX_EXPR_STACK_SIZE]; |
249 | 0 | unsigned int tos = 0; |
250 | 0 | uint16_t u16; |
251 | 0 | uint32_t u32; |
252 | 0 | uint64_t u64; |
253 | 0 | int ret; |
254 | 0 | unw_word_t stackerror = 0; |
255 | | |
256 | | // pop() is either followed by a semicolon or |
257 | | // used in a push() macro |
258 | | // In either case we can sneak in an extra statement |
259 | 0 | # define pop() \ |
260 | 0 | (((tos - 1) >= MAX_EXPR_STACK_SIZE) ? \ |
261 | 0 | stackerror++ : stack[--tos]); \ |
262 | 0 | if (stackerror) \ |
263 | 0 | { \ |
264 | 0 | Debug (1, "Stack underflow\n"); \ |
265 | 0 | return -UNW_EINVAL; \ |
266 | 0 | } |
267 | | |
268 | | // Removed the parentheses on the assignment |
269 | | // to allow the extra stack error check |
270 | | // when x is evaluated |
271 | 0 | # define push(x) \ |
272 | 0 | do { \ |
273 | 0 | unw_word_t _x = x; \ |
274 | 0 | if (tos >= MAX_EXPR_STACK_SIZE) \ |
275 | 0 | { \ |
276 | 0 | Debug (1, "Stack overflow\n"); \ |
277 | 0 | return -UNW_EINVAL; \ |
278 | 0 | } \ |
279 | 0 | stack[tos++] = _x; \ |
280 | 0 | } while (0) |
281 | | |
282 | | // Pick is always used in a push() macro |
283 | | // In either case we can sneak in an extra statement |
284 | 0 | # define pick(n) \ |
285 | 0 | (((tos - 1 - (n)) >= MAX_EXPR_STACK_SIZE) ? \ |
286 | 0 | stackerror++ : stack[tos - 1 - (n)]); \ |
287 | 0 | if (stackerror) \ |
288 | 0 | { \ |
289 | 0 | Debug (1, "Out-of-stack pick\n"); \ |
290 | 0 | return -UNW_EINVAL; \ |
291 | 0 | } |
292 | |
|
293 | 0 | as = c->as; |
294 | 0 | arg = c->as_arg; |
295 | 0 | a = unw_get_accessors_int (as); |
296 | 0 | end_addr = *addr + len; |
297 | 0 | *is_register = 0; |
298 | |
|
299 | 0 | Debug (14, "len=%lu, pushing initial value=0x%lx\n", |
300 | 0 | (unsigned long) len, (unsigned long) stack_val); |
301 | | |
302 | | /* The DWARF standard requires the current CFA to be pushed onto the stack */ |
303 | | /* before evaluating DW_CFA_expression and DW_CFA_val_expression programs. */ |
304 | | /* DW_CFA_def_cfa_expressions do not take an initial value, but we push on */ |
305 | | /* a dummy value to keep this logic consistent. */ |
306 | 0 | push (stack_val); |
307 | | |
308 | 0 | while (*addr < end_addr) |
309 | 0 | { |
310 | 0 | if ((ret = dwarf_readu8 (as, a, addr, &opcode, arg)) < 0) |
311 | 0 | return ret; |
312 | | |
313 | 0 | operands_signature = operands[opcode]; |
314 | |
|
315 | 0 | if (unlikely (NUM_OPERANDS (operands_signature) > 0)) |
316 | 0 | { |
317 | 0 | if ((ret = read_operand (as, a, addr, |
318 | 0 | OPND1_TYPE (operands_signature), |
319 | 0 | &operand1, arg)) < 0) |
320 | 0 | return ret; |
321 | 0 | if (NUM_OPERANDS (operands_signature) > 1) |
322 | 0 | if ((ret = read_operand (as, a, addr, |
323 | 0 | OPND2_TYPE (operands_signature), |
324 | 0 | &operand2, arg)) < 0) |
325 | 0 | return ret; |
326 | 0 | } |
327 | | |
328 | 0 | switch ((dwarf_expr_op_t) opcode) |
329 | 0 | { |
330 | 0 | case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: |
331 | 0 | case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: |
332 | 0 | case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: |
333 | 0 | case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: |
334 | 0 | case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: |
335 | 0 | case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: |
336 | 0 | case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: |
337 | 0 | case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: |
338 | 0 | case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: |
339 | 0 | case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: |
340 | 0 | case DW_OP_lit30: case DW_OP_lit31: |
341 | 0 | Debug (15, "OP_lit(%d)\n", (int) opcode - DW_OP_lit0); |
342 | 0 | push (opcode - DW_OP_lit0); |
343 | 0 | break; |
344 | | |
345 | 0 | case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: |
346 | 0 | case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5: |
347 | 0 | case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8: |
348 | 0 | case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: |
349 | 0 | case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: |
350 | 0 | case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17: |
351 | 0 | case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20: |
352 | 0 | case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: |
353 | 0 | case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: |
354 | 0 | case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: |
355 | 0 | case DW_OP_breg30: case DW_OP_breg31: |
356 | 0 | Debug (15, "OP_breg(r%d,0x%lx)\n", |
357 | 0 | (int) opcode - DW_OP_breg0, (unsigned long) operand1); |
358 | 0 | if ((ret = unw_get_reg (dwarf_to_cursor (c), |
359 | 0 | dwarf_to_unw_regnum (opcode - DW_OP_breg0), |
360 | 0 | &tmp1)) < 0) |
361 | 0 | return ret; |
362 | 0 | push (tmp1 + operand1); |
363 | 0 | break; |
364 | | |
365 | 0 | case DW_OP_bregx: |
366 | 0 | Debug (15, "OP_bregx(r%d,0x%lx)\n", |
367 | 0 | (int) operand1, (unsigned long) operand2); |
368 | 0 | if ((ret = unw_get_reg (dwarf_to_cursor (c), |
369 | 0 | dwarf_to_unw_regnum ((int) operand1), &tmp1)) < 0) |
370 | 0 | return ret; |
371 | 0 | push (tmp1 + operand2); |
372 | 0 | break; |
373 | | |
374 | 0 | case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: |
375 | 0 | case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: |
376 | 0 | case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: |
377 | 0 | case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: |
378 | 0 | case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: |
379 | 0 | case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: |
380 | 0 | case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: |
381 | 0 | case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: |
382 | 0 | case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: |
383 | 0 | case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: |
384 | 0 | case DW_OP_reg30: case DW_OP_reg31: |
385 | 0 | Debug (15, "OP_reg(r%d)\n", (int) opcode - DW_OP_reg0); |
386 | 0 | *valp = dwarf_to_unw_regnum (opcode - DW_OP_reg0); |
387 | 0 | *is_register = 1; |
388 | 0 | return 0; |
389 | | |
390 | 0 | case DW_OP_regx: |
391 | 0 | Debug (15, "OP_regx(r%d)\n", (int) operand1); |
392 | 0 | *valp = dwarf_to_unw_regnum (operand1); |
393 | 0 | *is_register = 1; |
394 | 0 | return 0; |
395 | | |
396 | 0 | case DW_OP_addr: |
397 | 0 | case DW_OP_const1u: |
398 | 0 | case DW_OP_const2u: |
399 | 0 | case DW_OP_const4u: |
400 | 0 | case DW_OP_const8u: |
401 | 0 | case DW_OP_constu: |
402 | 0 | case DW_OP_const8s: |
403 | 0 | case DW_OP_consts: |
404 | 0 | Debug (15, "OP_const(0x%lx)\n", (unsigned long) operand1); |
405 | 0 | push (operand1); |
406 | 0 | break; |
407 | | |
408 | 0 | case DW_OP_const1s: |
409 | 0 | if (operand1 & 0x80) |
410 | 0 | operand1 |= ((unw_word_t) -1) << 8; |
411 | 0 | Debug (15, "OP_const1s(%ld)\n", (long) operand1); |
412 | 0 | push (operand1); |
413 | 0 | break; |
414 | | |
415 | 0 | case DW_OP_const2s: |
416 | 0 | if (operand1 & 0x8000) |
417 | 0 | operand1 |= ((unw_word_t) -1) << 16; |
418 | 0 | Debug (15, "OP_const2s(%ld)\n", (long) operand1); |
419 | 0 | push (operand1); |
420 | 0 | break; |
421 | | |
422 | 0 | case DW_OP_const4s: |
423 | 0 | if (operand1 & 0x80000000) |
424 | 0 | operand1 |= (((unw_word_t) -1) << 16) << 16; |
425 | 0 | Debug (15, "OP_const4s(%ld)\n", (long) operand1); |
426 | 0 | push (operand1); |
427 | 0 | break; |
428 | | |
429 | 0 | case DW_OP_deref: |
430 | 0 | Debug (15, "OP_deref\n"); |
431 | 0 | tmp1 = pop (); |
432 | 0 | if ((ret = dwarf_readw (as, a, &tmp1, &tmp2, arg)) < 0) |
433 | 0 | return ret; |
434 | 0 | push (tmp2); |
435 | 0 | break; |
436 | | |
437 | 0 | case DW_OP_deref_size: |
438 | 0 | Debug (15, "OP_deref_size(%d)\n", (int) operand1); |
439 | 0 | tmp1 = pop (); |
440 | 0 | switch (operand1) |
441 | 0 | { |
442 | 0 | default: |
443 | 0 | Debug (1, "Unexpected DW_OP_deref_size size %d\n", |
444 | 0 | (int) operand1); |
445 | 0 | return -UNW_EINVAL; |
446 | | |
447 | 0 | case 1: |
448 | 0 | if ((ret = dwarf_readu8 (as, a, &tmp1, &u8, arg)) < 0) |
449 | 0 | return ret; |
450 | 0 | tmp2 = u8; |
451 | 0 | break; |
452 | | |
453 | 0 | case 2: |
454 | 0 | if ((ret = dwarf_readu16 (as, a, &tmp1, &u16, arg)) < 0) |
455 | 0 | return ret; |
456 | 0 | tmp2 = u16; |
457 | 0 | break; |
458 | | |
459 | 0 | case 3: |
460 | 0 | case 4: |
461 | 0 | if ((ret = dwarf_readu32 (as, a, &tmp1, &u32, arg)) < 0) |
462 | 0 | return ret; |
463 | 0 | tmp2 = u32; |
464 | 0 | if (operand1 == 3) |
465 | 0 | { |
466 | 0 | if (dwarf_is_big_endian (as)) |
467 | 0 | tmp2 >>= 8; |
468 | 0 | else |
469 | 0 | tmp2 &= 0xffffff; |
470 | 0 | } |
471 | 0 | break; |
472 | 0 | case 5: |
473 | 0 | case 6: |
474 | 0 | case 7: |
475 | 0 | case 8: |
476 | 0 | if ((ret = dwarf_readu64 (as, a, &tmp1, &u64, arg)) < 0) |
477 | 0 | return ret; |
478 | 0 | tmp2 = (unw_word_t) u64; |
479 | 0 | if (operand1 != 8) |
480 | 0 | { |
481 | 0 | if (dwarf_is_big_endian (as)) |
482 | 0 | tmp2 >>= 64 - 8 * operand1; |
483 | 0 | else |
484 | 0 | tmp2 &= (~ (unw_word_t) 0) << (8 * operand1); |
485 | 0 | } |
486 | 0 | break; |
487 | 0 | } |
488 | 0 | push (tmp2); |
489 | 0 | break; |
490 | | |
491 | 0 | case DW_OP_dup: |
492 | 0 | Debug (15, "OP_dup\n"); |
493 | 0 | push (pick (0)); |
494 | 0 | break; |
495 | | |
496 | 0 | case DW_OP_drop: |
497 | 0 | Debug (15, "OP_drop\n"); |
498 | 0 | (void) pop (); |
499 | 0 | break; |
500 | | |
501 | 0 | case DW_OP_pick: |
502 | 0 | Debug (15, "OP_pick(%d)\n", (int) operand1); |
503 | 0 | push (pick (operand1)); |
504 | 0 | break; |
505 | | |
506 | 0 | case DW_OP_over: |
507 | 0 | Debug (15, "OP_over\n"); |
508 | 0 | push (pick (1)); |
509 | 0 | break; |
510 | | |
511 | 0 | case DW_OP_swap: |
512 | 0 | Debug (15, "OP_swap\n"); |
513 | 0 | tmp1 = pop (); |
514 | 0 | tmp2 = pop (); |
515 | 0 | push (tmp1); |
516 | 0 | push (tmp2); |
517 | 0 | break; |
518 | | |
519 | 0 | case DW_OP_rot: |
520 | 0 | Debug (15, "OP_rot\n"); |
521 | 0 | tmp1 = pop (); |
522 | 0 | tmp2 = pop (); |
523 | 0 | tmp3 = pop (); |
524 | 0 | push (tmp1); |
525 | 0 | push (tmp3); |
526 | 0 | push (tmp2); |
527 | 0 | break; |
528 | | |
529 | 0 | case DW_OP_abs: |
530 | 0 | Debug (15, "OP_abs\n"); |
531 | 0 | tmp1 = pop (); |
532 | 0 | if (tmp1 & ((unw_word_t) 1 << (8 * dwarf_addr_size (as) - 1))) |
533 | 0 | tmp1 = (~tmp1 + 1); |
534 | 0 | push (tmp1); |
535 | 0 | break; |
536 | | |
537 | 0 | case DW_OP_and: |
538 | 0 | Debug (15, "OP_and\n"); |
539 | 0 | tmp1 = pop (); |
540 | 0 | tmp2 = pop (); |
541 | 0 | push (tmp1 & tmp2); |
542 | 0 | break; |
543 | | |
544 | 0 | case DW_OP_div: |
545 | 0 | Debug (15, "OP_div\n"); |
546 | 0 | tmp1 = pop (); |
547 | 0 | tmp2 = pop (); |
548 | 0 | if (tmp1) |
549 | 0 | tmp1 = sword (as, tmp2) / sword (as, tmp1); |
550 | 0 | push (tmp1); |
551 | 0 | break; |
552 | | |
553 | 0 | case DW_OP_minus: |
554 | 0 | Debug (15, "OP_minus\n"); |
555 | 0 | tmp1 = pop (); |
556 | 0 | tmp2 = pop (); |
557 | 0 | tmp1 = tmp2 - tmp1; |
558 | 0 | push (tmp1); |
559 | 0 | break; |
560 | | |
561 | 0 | case DW_OP_mod: |
562 | 0 | Debug (15, "OP_mod\n"); |
563 | 0 | tmp1 = pop (); |
564 | 0 | tmp2 = pop (); |
565 | 0 | if (tmp1) |
566 | 0 | tmp1 = tmp2 % tmp1; |
567 | 0 | push (tmp1); |
568 | 0 | break; |
569 | | |
570 | 0 | case DW_OP_mul: |
571 | 0 | Debug (15, "OP_mul\n"); |
572 | 0 | tmp1 = pop (); |
573 | 0 | tmp2 = pop (); |
574 | 0 | if (tmp1) |
575 | 0 | tmp1 = tmp2 * tmp1; |
576 | 0 | push (tmp1); |
577 | 0 | break; |
578 | | |
579 | 0 | case DW_OP_neg: |
580 | 0 | Debug (15, "OP_neg\n"); |
581 | 0 | tmp1 = pop (); |
582 | 0 | push (~tmp1 + 1); |
583 | 0 | break; |
584 | | |
585 | 0 | case DW_OP_not: |
586 | 0 | Debug (15, "OP_not\n"); |
587 | 0 | push (~pop ()); |
588 | 0 | break; |
589 | | |
590 | 0 | case DW_OP_or: |
591 | 0 | Debug (15, "OP_or\n"); |
592 | 0 | tmp1 = pop (); |
593 | 0 | tmp2 = pop (); |
594 | 0 | push (tmp1 | tmp2); |
595 | 0 | break; |
596 | | |
597 | 0 | case DW_OP_plus: |
598 | 0 | Debug (15, "OP_plus\n"); |
599 | 0 | tmp1 = pop (); |
600 | 0 | tmp2 = pop (); |
601 | 0 | push (tmp1 + tmp2); |
602 | 0 | break; |
603 | | |
604 | 0 | case DW_OP_plus_uconst: |
605 | 0 | Debug (15, "OP_plus_uconst(%lu)\n", (unsigned long) operand1); |
606 | 0 | tmp1 = pop (); |
607 | 0 | push (tmp1 + operand1); |
608 | 0 | break; |
609 | | |
610 | 0 | case DW_OP_shl: |
611 | 0 | Debug (15, "OP_shl\n"); |
612 | 0 | tmp1 = pop (); |
613 | 0 | tmp2 = pop (); |
614 | 0 | push (tmp2 << tmp1); |
615 | 0 | break; |
616 | | |
617 | 0 | case DW_OP_shr: |
618 | 0 | Debug (15, "OP_shr\n"); |
619 | 0 | tmp1 = pop (); |
620 | 0 | tmp2 = pop (); |
621 | 0 | push (tmp2 >> tmp1); |
622 | 0 | break; |
623 | | |
624 | 0 | case DW_OP_shra: |
625 | 0 | Debug (15, "OP_shra\n"); |
626 | 0 | tmp1 = pop (); |
627 | 0 | tmp2 = pop (); |
628 | 0 | push (sword (as, tmp2) >> tmp1); |
629 | 0 | break; |
630 | | |
631 | 0 | case DW_OP_xor: |
632 | 0 | Debug (15, "OP_xor\n"); |
633 | 0 | tmp1 = pop (); |
634 | 0 | tmp2 = pop (); |
635 | 0 | push (tmp1 ^ tmp2); |
636 | 0 | break; |
637 | | |
638 | 0 | case DW_OP_le: |
639 | 0 | Debug (15, "OP_le\n"); |
640 | 0 | tmp1 = pop (); |
641 | 0 | tmp2 = pop (); |
642 | 0 | push (sword (as, tmp2) <= sword (as, tmp1)); |
643 | 0 | break; |
644 | | |
645 | 0 | case DW_OP_ge: |
646 | 0 | Debug (15, "OP_ge\n"); |
647 | 0 | tmp1 = pop (); |
648 | 0 | tmp2 = pop (); |
649 | 0 | push (sword (as, tmp2) >= sword (as, tmp1)); |
650 | 0 | break; |
651 | | |
652 | 0 | case DW_OP_eq: |
653 | 0 | Debug (15, "OP_eq\n"); |
654 | 0 | tmp1 = pop (); |
655 | 0 | tmp2 = pop (); |
656 | 0 | push (sword (as, tmp2) == sword (as, tmp1)); |
657 | 0 | break; |
658 | | |
659 | 0 | case DW_OP_lt: |
660 | 0 | Debug (15, "OP_lt\n"); |
661 | 0 | tmp1 = pop (); |
662 | 0 | tmp2 = pop (); |
663 | 0 | push (sword (as, tmp2) < sword (as, tmp1)); |
664 | 0 | break; |
665 | | |
666 | 0 | case DW_OP_gt: |
667 | 0 | Debug (15, "OP_gt\n"); |
668 | 0 | tmp1 = pop (); |
669 | 0 | tmp2 = pop (); |
670 | 0 | push (sword (as, tmp2) > sword (as, tmp1)); |
671 | 0 | break; |
672 | | |
673 | 0 | case DW_OP_ne: |
674 | 0 | Debug (15, "OP_ne\n"); |
675 | 0 | tmp1 = pop (); |
676 | 0 | tmp2 = pop (); |
677 | 0 | push (sword (as, tmp2) != sword (as, tmp1)); |
678 | 0 | break; |
679 | | |
680 | 0 | case DW_OP_skip: |
681 | 0 | Debug (15, "OP_skip(%d)\n", (int16_t) operand1); |
682 | 0 | *addr += (int16_t) operand1; |
683 | 0 | break; |
684 | | |
685 | 0 | case DW_OP_bra: |
686 | 0 | Debug (15, "OP_skip(%d)\n", (int16_t) operand1); |
687 | 0 | tmp1 = pop (); |
688 | 0 | if (tmp1) |
689 | 0 | *addr += (int16_t) operand1; |
690 | 0 | break; |
691 | | |
692 | 0 | case DW_OP_nop: |
693 | 0 | Debug (15, "OP_nop\n"); |
694 | 0 | break; |
695 | | |
696 | 0 | case DW_OP_call2: |
697 | 0 | case DW_OP_call4: |
698 | 0 | case DW_OP_call_ref: |
699 | 0 | case DW_OP_fbreg: |
700 | 0 | case DW_OP_piece: |
701 | 0 | case DW_OP_push_object_address: |
702 | 0 | case DW_OP_xderef: |
703 | 0 | case DW_OP_xderef_size: |
704 | 0 | default: |
705 | 0 | Debug (1, "Unexpected opcode 0x%x\n", opcode); |
706 | 0 | return -UNW_EINVAL; |
707 | 0 | } |
708 | 0 | } |
709 | 0 | *valp = pop (); |
710 | 0 | Debug (14, "final value = 0x%lx\n", (unsigned long) *valp); |
711 | 0 | return 0; |
712 | 0 | } |