1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | // |
8 | // Processor specific interpretation of DWARF unwind info. |
9 | // |
10 | //===----------------------------------------------------------------------===// |
11 | |
12 | #ifndef __DWARF_INSTRUCTIONS_HPP__ |
13 | #define __DWARF_INSTRUCTIONS_HPP__ |
14 | |
15 | #include <stdint.h> |
16 | #include <stdio.h> |
17 | #include <stdlib.h> |
18 | |
19 | #include "DwarfParser.hpp" |
20 | #include "Registers.hpp" |
21 | #include "config.h" |
22 | #include "dwarf2.h" |
23 | #include "libunwind_ext.h" |
24 | |
25 | |
26 | namespace libunwind { |
27 | |
28 | |
29 | /// DwarfInstructions maps abstract DWARF unwind instructions to a particular |
30 | /// architecture |
31 | template <typename A, typename R> |
32 | class DwarfInstructions { |
33 | public: |
34 | typedef typename A::pint_t pint_t; |
35 | typedef typename A::sint_t sint_t; |
36 | |
37 | static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, |
38 | R ®isters, bool &isSignalFrame, bool stage2); |
39 | |
40 | private: |
41 | |
42 | enum { |
43 | DW_X86_64_RET_ADDR = 16 |
44 | }; |
45 | |
46 | enum { |
47 | DW_X86_RET_ADDR = 8 |
48 | }; |
49 | |
50 | typedef typename CFI_Parser<A>::RegisterLocation RegisterLocation; |
51 | typedef typename CFI_Parser<A>::PrologInfo PrologInfo; |
52 | typedef typename CFI_Parser<A>::FDE_Info FDE_Info; |
53 | typedef typename CFI_Parser<A>::CIE_Info CIE_Info; |
54 | |
55 | static pint_t evaluateExpression(pint_t expression, A &addressSpace, |
56 | const R ®isters, |
57 | pint_t initialStackValue); |
58 | static pint_t getSavedRegister(A &addressSpace, const R ®isters, |
59 | pint_t cfa, const RegisterLocation &savedReg); |
60 | static double getSavedFloatRegister(A &addressSpace, const R ®isters, |
61 | pint_t cfa, const RegisterLocation &savedReg); |
62 | static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, |
63 | pint_t cfa, const RegisterLocation &savedReg); |
64 | |
65 | static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, |
66 | const R ®isters) { |
67 | if (prolog.cfaRegister != 0) |
68 | return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + |
69 | prolog.cfaRegisterOffset); |
70 | if (prolog.cfaExpression != 0) |
71 | return evaluateExpression(expression: (pint_t)prolog.cfaExpression, addressSpace, |
72 | registers, initialStackValue: 0); |
73 | assert(0 && "getCFA(): unknown location" ); |
74 | __builtin_unreachable(); |
75 | } |
76 | #if defined(_LIBUNWIND_TARGET_AARCH64) |
77 | static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa, |
78 | PrologInfo &prolog); |
79 | #endif |
80 | }; |
81 | |
82 | template <typename R> |
83 | auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) { |
84 | return r.getWCookie(); |
85 | } |
86 | template <typename R> uint64_t getSparcWCookie(const R &, long) { |
87 | return 0; |
88 | } |
89 | |
90 | template <typename A, typename R> |
91 | typename A::pint_t DwarfInstructions<A, R>::getSavedRegister( |
92 | A &addressSpace, const R ®isters, pint_t cfa, |
93 | const RegisterLocation &savedReg) { |
94 | switch (savedReg.location) { |
95 | case CFI_Parser<A>::kRegisterInCFA: |
96 | return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value); |
97 | |
98 | case CFI_Parser<A>::kRegisterInCFADecrypt: // sparc64 specific |
99 | return (pint_t)(addressSpace.getP(cfa + (pint_t)savedReg.value) ^ |
100 | getSparcWCookie(registers, 0)); |
101 | |
102 | case CFI_Parser<A>::kRegisterAtExpression: |
103 | return (pint_t)addressSpace.getRegister(evaluateExpression( |
104 | expression: (pint_t)savedReg.value, addressSpace, registers, initialStackValue: cfa)); |
105 | |
106 | case CFI_Parser<A>::kRegisterIsExpression: |
107 | return evaluateExpression(expression: (pint_t)savedReg.value, addressSpace, |
108 | registers, initialStackValue: cfa); |
109 | |
110 | case CFI_Parser<A>::kRegisterInRegister: |
111 | return registers.getRegister((int)savedReg.value); |
112 | case CFI_Parser<A>::kRegisterUndefined: |
113 | return 0; |
114 | case CFI_Parser<A>::kRegisterUnused: |
115 | case CFI_Parser<A>::kRegisterOffsetFromCFA: |
116 | // FIX ME |
117 | break; |
118 | } |
119 | _LIBUNWIND_ABORT("unsupported restore location for register" ); |
120 | } |
121 | |
122 | template <typename A, typename R> |
123 | double DwarfInstructions<A, R>::getSavedFloatRegister( |
124 | A &addressSpace, const R ®isters, pint_t cfa, |
125 | const RegisterLocation &savedReg) { |
126 | switch (savedReg.location) { |
127 | case CFI_Parser<A>::kRegisterInCFA: |
128 | return addressSpace.getDouble(cfa + (pint_t)savedReg.value); |
129 | |
130 | case CFI_Parser<A>::kRegisterAtExpression: |
131 | return addressSpace.getDouble( |
132 | evaluateExpression(expression: (pint_t)savedReg.value, addressSpace, |
133 | registers, initialStackValue: cfa)); |
134 | case CFI_Parser<A>::kRegisterUndefined: |
135 | return 0.0; |
136 | case CFI_Parser<A>::kRegisterInRegister: |
137 | #ifndef _LIBUNWIND_TARGET_ARM |
138 | return registers.getFloatRegister((int)savedReg.value); |
139 | #endif |
140 | case CFI_Parser<A>::kRegisterIsExpression: |
141 | case CFI_Parser<A>::kRegisterUnused: |
142 | case CFI_Parser<A>::kRegisterOffsetFromCFA: |
143 | case CFI_Parser<A>::kRegisterInCFADecrypt: |
144 | // FIX ME |
145 | break; |
146 | } |
147 | _LIBUNWIND_ABORT("unsupported restore location for float register" ); |
148 | } |
149 | |
150 | template <typename A, typename R> |
151 | v128 DwarfInstructions<A, R>::getSavedVectorRegister( |
152 | A &addressSpace, const R ®isters, pint_t cfa, |
153 | const RegisterLocation &savedReg) { |
154 | switch (savedReg.location) { |
155 | case CFI_Parser<A>::kRegisterInCFA: |
156 | return addressSpace.getVector(cfa + (pint_t)savedReg.value); |
157 | |
158 | case CFI_Parser<A>::kRegisterAtExpression: |
159 | return addressSpace.getVector( |
160 | evaluateExpression(expression: (pint_t)savedReg.value, addressSpace, |
161 | registers, initialStackValue: cfa)); |
162 | |
163 | case CFI_Parser<A>::kRegisterIsExpression: |
164 | case CFI_Parser<A>::kRegisterUnused: |
165 | case CFI_Parser<A>::kRegisterUndefined: |
166 | case CFI_Parser<A>::kRegisterOffsetFromCFA: |
167 | case CFI_Parser<A>::kRegisterInRegister: |
168 | case CFI_Parser<A>::kRegisterInCFADecrypt: |
169 | // FIX ME |
170 | break; |
171 | } |
172 | _LIBUNWIND_ABORT("unsupported restore location for vector register" ); |
173 | } |
174 | #if defined(_LIBUNWIND_TARGET_AARCH64) |
175 | template <typename A, typename R> |
176 | bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers, |
177 | pint_t cfa, PrologInfo &prolog) { |
178 | pint_t raSignState; |
179 | auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE]; |
180 | if (regloc.location == CFI_Parser<A>::kRegisterUnused) |
181 | raSignState = static_cast<pint_t>(regloc.value); |
182 | else |
183 | raSignState = getSavedRegister(addressSpace, registers, cfa, regloc); |
184 | |
185 | // Only bit[0] is meaningful. |
186 | return raSignState & 0x01; |
187 | } |
188 | #endif |
189 | |
190 | template <typename A, typename R> |
191 | int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, |
192 | pint_t fdeStart, R ®isters, |
193 | bool &isSignalFrame, bool stage2) { |
194 | FDE_Info fdeInfo; |
195 | CIE_Info cieInfo; |
196 | if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, |
197 | &cieInfo) == NULL) { |
198 | PrologInfo prolog; |
199 | if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, |
200 | R::getArch(), &prolog)) { |
201 | // get pointer to cfa (architecture specific) |
202 | pint_t cfa = getCFA(addressSpace, prolog, registers); |
203 | |
204 | (void)stage2; |
205 | // __unw_step_stage2 is not used for cross unwinding, so we use |
206 | // __aarch64__ rather than LIBUNWIND_TARGET_AARCH64 to make sure we are |
207 | // building for AArch64 natively. |
208 | #if defined(__aarch64__) |
209 | if (stage2 && cieInfo.mteTaggedFrame) { |
210 | pint_t sp = registers.getSP(); |
211 | pint_t p = sp; |
212 | // AArch64 doesn't require the value of SP to be 16-byte aligned at |
213 | // all times, only at memory accesses and public interfaces [1]. Thus, |
214 | // a signal could arrive at a point where SP is not aligned properly. |
215 | // In that case, the kernel fixes up [2] the signal frame, but we |
216 | // still have a misaligned SP in the previous frame. If that signal |
217 | // handler caused stack unwinding, we would have an unaligned SP. |
218 | // We do not need to fix up the CFA, as that is the SP at a "public |
219 | // interface". |
220 | // [1]: |
221 | // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#622the-stack |
222 | // [2]: |
223 | // https://github.com/torvalds/linux/blob/1930a6e739c4b4a654a69164dbe39e554d228915/arch/arm64/kernel/signal.c#L718 |
224 | p &= ~0xfULL; |
225 | // CFA is the bottom of the current stack frame. |
226 | for (; p < cfa; p += 16) { |
227 | __asm__ __volatile__(".arch armv8.5-a\n" |
228 | ".arch_extension memtag\n" |
229 | "stg %[Ptr], [%[Ptr]]\n" |
230 | : |
231 | : [Ptr] "r" (p) |
232 | : "memory" ); |
233 | } |
234 | } |
235 | #endif |
236 | // restore registers that DWARF says were saved |
237 | R newRegisters = registers; |
238 | |
239 | // Typically, the CFA is the stack pointer at the call site in |
240 | // the previous frame. However, there are scenarios in which this is not |
241 | // true. For example, if we switched to a new stack. In that case, the |
242 | // value of the previous SP might be indicated by a CFI directive. |
243 | // |
244 | // We set the SP here to the CFA, allowing for it to be overridden |
245 | // by a CFI directive later on. |
246 | newRegisters.setSP(cfa); |
247 | |
248 | pint_t returnAddress = 0; |
249 | constexpr int lastReg = R::lastDwarfRegNum(); |
250 | static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= |
251 | lastReg, |
252 | "register range too large" ); |
253 | assert(lastReg >= (int)cieInfo.returnAddressRegister && |
254 | "register range does not contain return address register" ); |
255 | for (int i = 0; i <= lastReg; ++i) { |
256 | if (prolog.savedRegisters[i].location != |
257 | CFI_Parser<A>::kRegisterUnused) { |
258 | if (registers.validFloatRegister(i)) |
259 | newRegisters.setFloatRegister( |
260 | i, getSavedFloatRegister(addressSpace, registers, cfa, |
261 | savedReg: prolog.savedRegisters[i])); |
262 | else if (registers.validVectorRegister(i)) |
263 | newRegisters.setVectorRegister( |
264 | i, getSavedVectorRegister(addressSpace, registers, cfa, |
265 | savedReg: prolog.savedRegisters[i])); |
266 | else if (i == (int)cieInfo.returnAddressRegister) |
267 | returnAddress = getSavedRegister(addressSpace, registers, cfa, |
268 | savedReg: prolog.savedRegisters[i]); |
269 | else if (registers.validRegister(i)) |
270 | newRegisters.setRegister( |
271 | i, getSavedRegister(addressSpace, registers, cfa, |
272 | savedReg: prolog.savedRegisters[i])); |
273 | else |
274 | return UNW_EBADREG; |
275 | } else if (i == (int)cieInfo.returnAddressRegister) { |
276 | // Leaf function keeps the return address in register and there is no |
277 | // explicit instructions how to restore it. |
278 | returnAddress = registers.getRegister(cieInfo.returnAddressRegister); |
279 | } |
280 | } |
281 | |
282 | isSignalFrame = cieInfo.isSignalFrame; |
283 | |
284 | #if defined(_LIBUNWIND_TARGET_AARCH64) |
285 | // If the target is aarch64 then the return address may have been signed |
286 | // using the v8.3 pointer authentication extensions. The original |
287 | // return address needs to be authenticated before the return address is |
288 | // restored. autia1716 is used instead of autia as autia1716 assembles |
289 | // to a NOP on pre-v8.3a architectures. |
290 | if ((R::getArch() == REGISTERS_ARM64) && |
291 | getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) && |
292 | returnAddress != 0) { |
293 | #if !defined(_LIBUNWIND_IS_NATIVE_ONLY) |
294 | return UNW_ECROSSRASIGNING; |
295 | #else |
296 | register unsigned long long x17 __asm("x17" ) = returnAddress; |
297 | register unsigned long long x16 __asm("x16" ) = cfa; |
298 | |
299 | // These are the autia1716/autib1716 instructions. The hint instructions |
300 | // are used here as gcc does not assemble autia1716/autib1716 for pre |
301 | // armv8.3a targets. |
302 | if (cieInfo.addressesSignedWithBKey) |
303 | asm("hint 0xe" : "+r" (x17) : "r" (x16)); // autib1716 |
304 | else |
305 | asm("hint 0xc" : "+r" (x17) : "r" (x16)); // autia1716 |
306 | returnAddress = x17; |
307 | #endif |
308 | } |
309 | #endif |
310 | |
311 | #if defined(_LIBUNWIND_IS_NATIVE_ONLY) && defined(_LIBUNWIND_TARGET_ARM) && \ |
312 | defined(__ARM_FEATURE_PAUTH) |
313 | if ((R::getArch() == REGISTERS_ARM) && |
314 | prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE].value) { |
315 | pint_t pac = |
316 | getSavedRegister(addressSpace, registers, cfa, |
317 | prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE]); |
318 | __asm__ __volatile__("autg %0, %1, %2" |
319 | : |
320 | : "r" (pac), "r" (returnAddress), "r" (cfa) |
321 | :); |
322 | } |
323 | #endif |
324 | |
325 | #if defined(_LIBUNWIND_TARGET_SPARC) |
326 | if (R::getArch() == REGISTERS_SPARC) { |
327 | // Skip call site instruction and delay slot |
328 | returnAddress += 8; |
329 | // Skip unimp instruction if function returns a struct |
330 | if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0) |
331 | returnAddress += 4; |
332 | } |
333 | #endif |
334 | |
335 | #if defined(_LIBUNWIND_TARGET_SPARC64) |
336 | // Skip call site instruction and delay slot. |
337 | if (R::getArch() == REGISTERS_SPARC64) |
338 | returnAddress += 8; |
339 | #endif |
340 | |
341 | #if defined(_LIBUNWIND_TARGET_PPC64) |
342 | #define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1) |
343 | #define PPC64_ELFV1_R2_OFFSET 40 |
344 | #define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1) |
345 | #define PPC64_ELFV2_R2_OFFSET 24 |
346 | // If the instruction at return address is a TOC (r2) restore, |
347 | // then r2 was saved and needs to be restored. |
348 | // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24, |
349 | // while in ELFv1 ABI it is saved at SP + 40. |
350 | if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) { |
351 | pint_t sp = newRegisters.getRegister(UNW_REG_SP); |
352 | pint_t r2 = 0; |
353 | switch (addressSpace.get32(returnAddress)) { |
354 | case PPC64_ELFV1_R2_LOAD_INST_ENCODING: |
355 | r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET); |
356 | break; |
357 | case PPC64_ELFV2_R2_LOAD_INST_ENCODING: |
358 | r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET); |
359 | break; |
360 | } |
361 | if (r2) |
362 | newRegisters.setRegister(UNW_PPC64_R2, r2); |
363 | } |
364 | #endif |
365 | |
366 | // Return address is address after call site instruction, so setting IP to |
367 | // that does simulates a return. |
368 | newRegisters.setIP(returnAddress); |
369 | |
370 | // Simulate the step by replacing the register set with the new ones. |
371 | registers = newRegisters; |
372 | |
373 | return UNW_STEP_SUCCESS; |
374 | } |
375 | } |
376 | return UNW_EBADFRAME; |
377 | } |
378 | |
379 | template <typename A, typename R> |
380 | typename A::pint_t |
381 | DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace, |
382 | const R ®isters, |
383 | pint_t initialStackValue) { |
384 | const bool log = false; |
385 | pint_t p = expression; |
386 | pint_t expressionEnd = expression + 20; // temp, until len read |
387 | pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd); |
388 | expressionEnd = p + length; |
389 | if (log) |
390 | fprintf(stderr, format: "evaluateExpression(): length=%" PRIu64 "\n" , |
391 | (uint64_t)length); |
392 | pint_t stack[100]; |
393 | pint_t *sp = stack; |
394 | *(++sp) = initialStackValue; |
395 | |
396 | while (p < expressionEnd) { |
397 | if (log) { |
398 | for (pint_t *t = sp; t > stack; --t) { |
399 | fprintf(stderr, format: "sp[] = 0x%" PRIx64 "\n" , (uint64_t)(*t)); |
400 | } |
401 | } |
402 | uint8_t opcode = addressSpace.get8(p++); |
403 | sint_t svalue, svalue2; |
404 | pint_t value; |
405 | uint32_t reg; |
406 | switch (opcode) { |
407 | case DW_OP_addr: |
408 | // push immediate address sized value |
409 | value = addressSpace.getP(p); |
410 | p += sizeof(pint_t); |
411 | *(++sp) = value; |
412 | if (log) |
413 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)value); |
414 | break; |
415 | |
416 | case DW_OP_deref: |
417 | // pop stack, dereference, push result |
418 | value = *sp--; |
419 | *(++sp) = addressSpace.getP(value); |
420 | if (log) |
421 | fprintf(stderr, format: "dereference 0x%" PRIx64 "\n" , (uint64_t)value); |
422 | break; |
423 | |
424 | case DW_OP_const1u: |
425 | // push immediate 1 byte value |
426 | value = addressSpace.get8(p); |
427 | p += 1; |
428 | *(++sp) = value; |
429 | if (log) |
430 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)value); |
431 | break; |
432 | |
433 | case DW_OP_const1s: |
434 | // push immediate 1 byte signed value |
435 | svalue = (int8_t) addressSpace.get8(p); |
436 | p += 1; |
437 | *(++sp) = (pint_t)svalue; |
438 | if (log) |
439 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)svalue); |
440 | break; |
441 | |
442 | case DW_OP_const2u: |
443 | // push immediate 2 byte value |
444 | value = addressSpace.get16(p); |
445 | p += 2; |
446 | *(++sp) = value; |
447 | if (log) |
448 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)value); |
449 | break; |
450 | |
451 | case DW_OP_const2s: |
452 | // push immediate 2 byte signed value |
453 | svalue = (int16_t) addressSpace.get16(p); |
454 | p += 2; |
455 | *(++sp) = (pint_t)svalue; |
456 | if (log) |
457 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)svalue); |
458 | break; |
459 | |
460 | case DW_OP_const4u: |
461 | // push immediate 4 byte value |
462 | value = addressSpace.get32(p); |
463 | p += 4; |
464 | *(++sp) = value; |
465 | if (log) |
466 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)value); |
467 | break; |
468 | |
469 | case DW_OP_const4s: |
470 | // push immediate 4 byte signed value |
471 | svalue = (int32_t)addressSpace.get32(p); |
472 | p += 4; |
473 | *(++sp) = (pint_t)svalue; |
474 | if (log) |
475 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)svalue); |
476 | break; |
477 | |
478 | case DW_OP_const8u: |
479 | // push immediate 8 byte value |
480 | value = (pint_t)addressSpace.get64(p); |
481 | p += 8; |
482 | *(++sp) = value; |
483 | if (log) |
484 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)value); |
485 | break; |
486 | |
487 | case DW_OP_const8s: |
488 | // push immediate 8 byte signed value |
489 | value = (pint_t)addressSpace.get64(p); |
490 | p += 8; |
491 | *(++sp) = value; |
492 | if (log) |
493 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)value); |
494 | break; |
495 | |
496 | case DW_OP_constu: |
497 | // push immediate ULEB128 value |
498 | value = (pint_t)addressSpace.getULEB128(p, expressionEnd); |
499 | *(++sp) = value; |
500 | if (log) |
501 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)value); |
502 | break; |
503 | |
504 | case DW_OP_consts: |
505 | // push immediate SLEB128 value |
506 | svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); |
507 | *(++sp) = (pint_t)svalue; |
508 | if (log) |
509 | fprintf(stderr, format: "push 0x%" PRIx64 "\n" , (uint64_t)svalue); |
510 | break; |
511 | |
512 | case DW_OP_dup: |
513 | // push top of stack |
514 | value = *sp; |
515 | *(++sp) = value; |
516 | if (log) |
517 | fprintf(stderr, format: "duplicate top of stack\n" ); |
518 | break; |
519 | |
520 | case DW_OP_drop: |
521 | // pop |
522 | --sp; |
523 | if (log) |
524 | fprintf(stderr, format: "pop top of stack\n" ); |
525 | break; |
526 | |
527 | case DW_OP_over: |
528 | // dup second |
529 | value = sp[-1]; |
530 | *(++sp) = value; |
531 | if (log) |
532 | fprintf(stderr, format: "duplicate second in stack\n" ); |
533 | break; |
534 | |
535 | case DW_OP_pick: |
536 | // pick from |
537 | reg = addressSpace.get8(p); |
538 | p += 1; |
539 | value = sp[-(int)reg]; |
540 | *(++sp) = value; |
541 | if (log) |
542 | fprintf(stderr, format: "duplicate %d in stack\n" , reg); |
543 | break; |
544 | |
545 | case DW_OP_swap: |
546 | // swap top two |
547 | value = sp[0]; |
548 | sp[0] = sp[-1]; |
549 | sp[-1] = value; |
550 | if (log) |
551 | fprintf(stderr, format: "swap top of stack\n" ); |
552 | break; |
553 | |
554 | case DW_OP_rot: |
555 | // rotate top three |
556 | value = sp[0]; |
557 | sp[0] = sp[-1]; |
558 | sp[-1] = sp[-2]; |
559 | sp[-2] = value; |
560 | if (log) |
561 | fprintf(stderr, format: "rotate top three of stack\n" ); |
562 | break; |
563 | |
564 | case DW_OP_xderef: |
565 | // pop stack, dereference, push result |
566 | value = *sp--; |
567 | *sp = *((pint_t*)value); |
568 | if (log) |
569 | fprintf(stderr, format: "x-dereference 0x%" PRIx64 "\n" , (uint64_t)value); |
570 | break; |
571 | |
572 | case DW_OP_abs: |
573 | svalue = (sint_t)*sp; |
574 | if (svalue < 0) |
575 | *sp = (pint_t)(-svalue); |
576 | if (log) |
577 | fprintf(stderr, format: "abs\n" ); |
578 | break; |
579 | |
580 | case DW_OP_and: |
581 | value = *sp--; |
582 | *sp &= value; |
583 | if (log) |
584 | fprintf(stderr, format: "and\n" ); |
585 | break; |
586 | |
587 | case DW_OP_div: |
588 | svalue = (sint_t)(*sp--); |
589 | svalue2 = (sint_t)*sp; |
590 | *sp = (pint_t)(svalue2 / svalue); |
591 | if (log) |
592 | fprintf(stderr, format: "div\n" ); |
593 | break; |
594 | |
595 | case DW_OP_minus: |
596 | value = *sp--; |
597 | *sp = *sp - value; |
598 | if (log) |
599 | fprintf(stderr, format: "minus\n" ); |
600 | break; |
601 | |
602 | case DW_OP_mod: |
603 | svalue = (sint_t)(*sp--); |
604 | svalue2 = (sint_t)*sp; |
605 | *sp = (pint_t)(svalue2 % svalue); |
606 | if (log) |
607 | fprintf(stderr, format: "module\n" ); |
608 | break; |
609 | |
610 | case DW_OP_mul: |
611 | svalue = (sint_t)(*sp--); |
612 | svalue2 = (sint_t)*sp; |
613 | *sp = (pint_t)(svalue2 * svalue); |
614 | if (log) |
615 | fprintf(stderr, format: "mul\n" ); |
616 | break; |
617 | |
618 | case DW_OP_neg: |
619 | *sp = 0 - *sp; |
620 | if (log) |
621 | fprintf(stderr, format: "neg\n" ); |
622 | break; |
623 | |
624 | case DW_OP_not: |
625 | svalue = (sint_t)(*sp); |
626 | *sp = (pint_t)(~svalue); |
627 | if (log) |
628 | fprintf(stderr, format: "not\n" ); |
629 | break; |
630 | |
631 | case DW_OP_or: |
632 | value = *sp--; |
633 | *sp |= value; |
634 | if (log) |
635 | fprintf(stderr, format: "or\n" ); |
636 | break; |
637 | |
638 | case DW_OP_plus: |
639 | value = *sp--; |
640 | *sp += value; |
641 | if (log) |
642 | fprintf(stderr, format: "plus\n" ); |
643 | break; |
644 | |
645 | case DW_OP_plus_uconst: |
646 | // pop stack, add uelb128 constant, push result |
647 | *sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd)); |
648 | if (log) |
649 | fprintf(stderr, format: "add constant\n" ); |
650 | break; |
651 | |
652 | case DW_OP_shl: |
653 | value = *sp--; |
654 | *sp = *sp << value; |
655 | if (log) |
656 | fprintf(stderr, format: "shift left\n" ); |
657 | break; |
658 | |
659 | case DW_OP_shr: |
660 | value = *sp--; |
661 | *sp = *sp >> value; |
662 | if (log) |
663 | fprintf(stderr, format: "shift left\n" ); |
664 | break; |
665 | |
666 | case DW_OP_shra: |
667 | value = *sp--; |
668 | svalue = (sint_t)*sp; |
669 | *sp = (pint_t)(svalue >> value); |
670 | if (log) |
671 | fprintf(stderr, format: "shift left arithmetic\n" ); |
672 | break; |
673 | |
674 | case DW_OP_xor: |
675 | value = *sp--; |
676 | *sp ^= value; |
677 | if (log) |
678 | fprintf(stderr, format: "xor\n" ); |
679 | break; |
680 | |
681 | case DW_OP_skip: |
682 | svalue = (int16_t) addressSpace.get16(p); |
683 | p += 2; |
684 | p = (pint_t)((sint_t)p + svalue); |
685 | if (log) |
686 | fprintf(stderr, format: "skip %" PRIu64 "\n" , (uint64_t)svalue); |
687 | break; |
688 | |
689 | case DW_OP_bra: |
690 | svalue = (int16_t) addressSpace.get16(p); |
691 | p += 2; |
692 | if (*sp--) |
693 | p = (pint_t)((sint_t)p + svalue); |
694 | if (log) |
695 | fprintf(stderr, format: "bra %" PRIu64 "\n" , (uint64_t)svalue); |
696 | break; |
697 | |
698 | case DW_OP_eq: |
699 | value = *sp--; |
700 | *sp = (*sp == value); |
701 | if (log) |
702 | fprintf(stderr, format: "eq\n" ); |
703 | break; |
704 | |
705 | case DW_OP_ge: |
706 | value = *sp--; |
707 | *sp = (*sp >= value); |
708 | if (log) |
709 | fprintf(stderr, format: "ge\n" ); |
710 | break; |
711 | |
712 | case DW_OP_gt: |
713 | value = *sp--; |
714 | *sp = (*sp > value); |
715 | if (log) |
716 | fprintf(stderr, format: "gt\n" ); |
717 | break; |
718 | |
719 | case DW_OP_le: |
720 | value = *sp--; |
721 | *sp = (*sp <= value); |
722 | if (log) |
723 | fprintf(stderr, format: "le\n" ); |
724 | break; |
725 | |
726 | case DW_OP_lt: |
727 | value = *sp--; |
728 | *sp = (*sp < value); |
729 | if (log) |
730 | fprintf(stderr, format: "lt\n" ); |
731 | break; |
732 | |
733 | case DW_OP_ne: |
734 | value = *sp--; |
735 | *sp = (*sp != value); |
736 | if (log) |
737 | fprintf(stderr, format: "ne\n" ); |
738 | break; |
739 | |
740 | case DW_OP_lit0: |
741 | case DW_OP_lit1: |
742 | case DW_OP_lit2: |
743 | case DW_OP_lit3: |
744 | case DW_OP_lit4: |
745 | case DW_OP_lit5: |
746 | case DW_OP_lit6: |
747 | case DW_OP_lit7: |
748 | case DW_OP_lit8: |
749 | case DW_OP_lit9: |
750 | case DW_OP_lit10: |
751 | case DW_OP_lit11: |
752 | case DW_OP_lit12: |
753 | case DW_OP_lit13: |
754 | case DW_OP_lit14: |
755 | case DW_OP_lit15: |
756 | case DW_OP_lit16: |
757 | case DW_OP_lit17: |
758 | case DW_OP_lit18: |
759 | case DW_OP_lit19: |
760 | case DW_OP_lit20: |
761 | case DW_OP_lit21: |
762 | case DW_OP_lit22: |
763 | case DW_OP_lit23: |
764 | case DW_OP_lit24: |
765 | case DW_OP_lit25: |
766 | case DW_OP_lit26: |
767 | case DW_OP_lit27: |
768 | case DW_OP_lit28: |
769 | case DW_OP_lit29: |
770 | case DW_OP_lit30: |
771 | case DW_OP_lit31: |
772 | value = static_cast<pint_t>(opcode - DW_OP_lit0); |
773 | *(++sp) = value; |
774 | if (log) |
775 | fprintf(stderr, format: "push literal 0x%" PRIx64 "\n" , (uint64_t)value); |
776 | break; |
777 | |
778 | case DW_OP_reg0: |
779 | case DW_OP_reg1: |
780 | case DW_OP_reg2: |
781 | case DW_OP_reg3: |
782 | case DW_OP_reg4: |
783 | case DW_OP_reg5: |
784 | case DW_OP_reg6: |
785 | case DW_OP_reg7: |
786 | case DW_OP_reg8: |
787 | case DW_OP_reg9: |
788 | case DW_OP_reg10: |
789 | case DW_OP_reg11: |
790 | case DW_OP_reg12: |
791 | case DW_OP_reg13: |
792 | case DW_OP_reg14: |
793 | case DW_OP_reg15: |
794 | case DW_OP_reg16: |
795 | case DW_OP_reg17: |
796 | case DW_OP_reg18: |
797 | case DW_OP_reg19: |
798 | case DW_OP_reg20: |
799 | case DW_OP_reg21: |
800 | case DW_OP_reg22: |
801 | case DW_OP_reg23: |
802 | case DW_OP_reg24: |
803 | case DW_OP_reg25: |
804 | case DW_OP_reg26: |
805 | case DW_OP_reg27: |
806 | case DW_OP_reg28: |
807 | case DW_OP_reg29: |
808 | case DW_OP_reg30: |
809 | case DW_OP_reg31: |
810 | reg = static_cast<uint32_t>(opcode - DW_OP_reg0); |
811 | *(++sp) = registers.getRegister((int)reg); |
812 | if (log) |
813 | fprintf(stderr, format: "push reg %d\n" , reg); |
814 | break; |
815 | |
816 | case DW_OP_regx: |
817 | reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd)); |
818 | *(++sp) = registers.getRegister((int)reg); |
819 | if (log) |
820 | fprintf(stderr, format: "push reg %d + 0x%" PRIx64 "\n" , reg, (uint64_t)svalue); |
821 | break; |
822 | |
823 | case DW_OP_breg0: |
824 | case DW_OP_breg1: |
825 | case DW_OP_breg2: |
826 | case DW_OP_breg3: |
827 | case DW_OP_breg4: |
828 | case DW_OP_breg5: |
829 | case DW_OP_breg6: |
830 | case DW_OP_breg7: |
831 | case DW_OP_breg8: |
832 | case DW_OP_breg9: |
833 | case DW_OP_breg10: |
834 | case DW_OP_breg11: |
835 | case DW_OP_breg12: |
836 | case DW_OP_breg13: |
837 | case DW_OP_breg14: |
838 | case DW_OP_breg15: |
839 | case DW_OP_breg16: |
840 | case DW_OP_breg17: |
841 | case DW_OP_breg18: |
842 | case DW_OP_breg19: |
843 | case DW_OP_breg20: |
844 | case DW_OP_breg21: |
845 | case DW_OP_breg22: |
846 | case DW_OP_breg23: |
847 | case DW_OP_breg24: |
848 | case DW_OP_breg25: |
849 | case DW_OP_breg26: |
850 | case DW_OP_breg27: |
851 | case DW_OP_breg28: |
852 | case DW_OP_breg29: |
853 | case DW_OP_breg30: |
854 | case DW_OP_breg31: |
855 | reg = static_cast<uint32_t>(opcode - DW_OP_breg0); |
856 | svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); |
857 | svalue += static_cast<sint_t>(registers.getRegister((int)reg)); |
858 | *(++sp) = (pint_t)(svalue); |
859 | if (log) |
860 | fprintf(stderr, format: "push reg %d + 0x%" PRIx64 "\n" , reg, (uint64_t)svalue); |
861 | break; |
862 | |
863 | case DW_OP_bregx: |
864 | reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd)); |
865 | svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); |
866 | svalue += static_cast<sint_t>(registers.getRegister((int)reg)); |
867 | *(++sp) = (pint_t)(svalue); |
868 | if (log) |
869 | fprintf(stderr, format: "push reg %d + 0x%" PRIx64 "\n" , reg, (uint64_t)svalue); |
870 | break; |
871 | |
872 | case DW_OP_fbreg: |
873 | _LIBUNWIND_ABORT("DW_OP_fbreg not implemented" ); |
874 | break; |
875 | |
876 | case DW_OP_piece: |
877 | _LIBUNWIND_ABORT("DW_OP_piece not implemented" ); |
878 | break; |
879 | |
880 | case DW_OP_deref_size: |
881 | // pop stack, dereference, push result |
882 | value = *sp--; |
883 | switch (addressSpace.get8(p++)) { |
884 | case 1: |
885 | value = addressSpace.get8(value); |
886 | break; |
887 | case 2: |
888 | value = addressSpace.get16(value); |
889 | break; |
890 | case 4: |
891 | value = addressSpace.get32(value); |
892 | break; |
893 | case 8: |
894 | value = (pint_t)addressSpace.get64(value); |
895 | break; |
896 | default: |
897 | _LIBUNWIND_ABORT("DW_OP_deref_size with bad size" ); |
898 | } |
899 | *(++sp) = value; |
900 | if (log) |
901 | fprintf(stderr, format: "sized dereference 0x%" PRIx64 "\n" , (uint64_t)value); |
902 | break; |
903 | |
904 | case DW_OP_xderef_size: |
905 | case DW_OP_nop: |
906 | case DW_OP_push_object_addres: |
907 | case DW_OP_call2: |
908 | case DW_OP_call4: |
909 | case DW_OP_call_ref: |
910 | default: |
911 | _LIBUNWIND_ABORT("DWARF opcode not implemented" ); |
912 | } |
913 | |
914 | } |
915 | if (log) |
916 | fprintf(stderr, format: "expression evaluates to 0x%" PRIx64 "\n" , (uint64_t)*sp); |
917 | return *sp; |
918 | } |
919 | |
920 | |
921 | |
922 | } // namespace libunwind |
923 | |
924 | #endif // __DWARF_INSTRUCTIONS_HPP__ |
925 | |