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