xref: /freebsd-src/contrib/llvm-project/libunwind/src/DwarfInstructions.hpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric //  Processor specific interpretation of DWARF unwind info.
90b57cec5SDimitry Andric //
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #ifndef __DWARF_INSTRUCTIONS_HPP__
130b57cec5SDimitry Andric #define __DWARF_INSTRUCTIONS_HPP__
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include <stdint.h>
160b57cec5SDimitry Andric #include <stdio.h>
170b57cec5SDimitry Andric #include <stdlib.h>
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "DwarfParser.hpp"
20bdd1243dSDimitry Andric #include "Registers.hpp"
210b57cec5SDimitry Andric #include "config.h"
22bdd1243dSDimitry Andric #include "dwarf2.h"
23bdd1243dSDimitry Andric #include "libunwind_ext.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric namespace libunwind {
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric 
29bdd1243dSDimitry Andric /// DwarfInstructions maps abstract DWARF unwind instructions to a particular
300b57cec5SDimitry Andric /// architecture
310b57cec5SDimitry Andric template <typename A, typename R>
320b57cec5SDimitry Andric class DwarfInstructions {
330b57cec5SDimitry Andric public:
340b57cec5SDimitry Andric   typedef typename A::pint_t pint_t;
350b57cec5SDimitry Andric   typedef typename A::sint_t sint_t;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
38bdd1243dSDimitry Andric                            R &registers, bool &isSignalFrame, bool stage2);
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric private:
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   enum {
430b57cec5SDimitry Andric     DW_X86_64_RET_ADDR = 16
440b57cec5SDimitry Andric   };
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   enum {
470b57cec5SDimitry Andric     DW_X86_RET_ADDR = 8
480b57cec5SDimitry Andric   };
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   typedef typename CFI_Parser<A>::RegisterLocation  RegisterLocation;
510b57cec5SDimitry Andric   typedef typename CFI_Parser<A>::PrologInfo        PrologInfo;
520b57cec5SDimitry Andric   typedef typename CFI_Parser<A>::FDE_Info          FDE_Info;
530b57cec5SDimitry Andric   typedef typename CFI_Parser<A>::CIE_Info          CIE_Info;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   static pint_t evaluateExpression(pint_t expression, A &addressSpace,
560b57cec5SDimitry Andric                                    const R &registers,
570b57cec5SDimitry Andric                                    pint_t initialStackValue);
580b57cec5SDimitry Andric   static pint_t getSavedRegister(A &addressSpace, const R &registers,
590b57cec5SDimitry Andric                                  pint_t cfa, const RegisterLocation &savedReg);
600b57cec5SDimitry Andric   static double getSavedFloatRegister(A &addressSpace, const R &registers,
610b57cec5SDimitry Andric                                   pint_t cfa, const RegisterLocation &savedReg);
620b57cec5SDimitry Andric   static v128 getSavedVectorRegister(A &addressSpace, const R &registers,
630b57cec5SDimitry Andric                                   pint_t cfa, const RegisterLocation &savedReg);
640b57cec5SDimitry Andric 
getCFA(A & addressSpace,const PrologInfo & prolog,const R & registers)650b57cec5SDimitry Andric   static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
660b57cec5SDimitry Andric                        const R &registers) {
670b57cec5SDimitry Andric     if (prolog.cfaRegister != 0)
680b57cec5SDimitry Andric       return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
690b57cec5SDimitry Andric              prolog.cfaRegisterOffset);
700b57cec5SDimitry Andric     if (prolog.cfaExpression != 0)
710b57cec5SDimitry Andric       return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
720b57cec5SDimitry Andric                                 registers, 0);
730b57cec5SDimitry Andric     assert(0 && "getCFA(): unknown location");
740b57cec5SDimitry Andric     __builtin_unreachable();
750b57cec5SDimitry Andric   }
7681ad6265SDimitry Andric #if defined(_LIBUNWIND_TARGET_AARCH64)
7781ad6265SDimitry Andric   static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
7881ad6265SDimitry Andric                                PrologInfo &prolog);
7981ad6265SDimitry Andric #endif
800b57cec5SDimitry Andric };
810b57cec5SDimitry Andric 
82d56accc7SDimitry Andric template <typename R>
getSparcWCookie(const R & r,int)83d56accc7SDimitry Andric auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) {
84d56accc7SDimitry Andric   return r.getWCookie();
85d56accc7SDimitry Andric }
getSparcWCookie(const R &,long)86d56accc7SDimitry Andric template <typename R> uint64_t getSparcWCookie(const R &, long) {
87d56accc7SDimitry Andric   return 0;
88d56accc7SDimitry Andric }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric template <typename A, typename R>
getSavedRegister(A & addressSpace,const R & registers,pint_t cfa,const RegisterLocation & savedReg)910b57cec5SDimitry Andric typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
920b57cec5SDimitry Andric     A &addressSpace, const R &registers, pint_t cfa,
930b57cec5SDimitry Andric     const RegisterLocation &savedReg) {
940b57cec5SDimitry Andric   switch (savedReg.location) {
950b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterInCFA:
960b57cec5SDimitry Andric     return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
970b57cec5SDimitry Andric 
98d56accc7SDimitry Andric   case CFI_Parser<A>::kRegisterInCFADecrypt: // sparc64 specific
99d56accc7SDimitry Andric     return (pint_t)(addressSpace.getP(cfa + (pint_t)savedReg.value) ^
100d56accc7SDimitry Andric            getSparcWCookie(registers, 0));
101d56accc7SDimitry Andric 
1020b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterAtExpression:
1030b57cec5SDimitry Andric     return (pint_t)addressSpace.getRegister(evaluateExpression(
1040b57cec5SDimitry Andric         (pint_t)savedReg.value, addressSpace, registers, cfa));
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterIsExpression:
1070b57cec5SDimitry Andric     return evaluateExpression((pint_t)savedReg.value, addressSpace,
1080b57cec5SDimitry Andric                               registers, cfa);
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterInRegister:
1110b57cec5SDimitry Andric     return registers.getRegister((int)savedReg.value);
1125866c369SDimitry Andric 
1130b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterUnused:
1140b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterOffsetFromCFA:
1150b57cec5SDimitry Andric     // FIX ME
1160b57cec5SDimitry Andric     break;
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric   _LIBUNWIND_ABORT("unsupported restore location for register");
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric template <typename A, typename R>
getSavedFloatRegister(A & addressSpace,const R & registers,pint_t cfa,const RegisterLocation & savedReg)1220b57cec5SDimitry Andric double DwarfInstructions<A, R>::getSavedFloatRegister(
1230b57cec5SDimitry Andric     A &addressSpace, const R &registers, pint_t cfa,
1240b57cec5SDimitry Andric     const RegisterLocation &savedReg) {
1250b57cec5SDimitry Andric   switch (savedReg.location) {
1260b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterInCFA:
1270b57cec5SDimitry Andric     return addressSpace.getDouble(cfa + (pint_t)savedReg.value);
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterAtExpression:
1300b57cec5SDimitry Andric     return addressSpace.getDouble(
1310b57cec5SDimitry Andric         evaluateExpression((pint_t)savedReg.value, addressSpace,
1320b57cec5SDimitry Andric                             registers, cfa));
133349cc55cSDimitry Andric   case CFI_Parser<A>::kRegisterInRegister:
134349cc55cSDimitry Andric #ifndef _LIBUNWIND_TARGET_ARM
135349cc55cSDimitry Andric     return registers.getFloatRegister((int)savedReg.value);
136349cc55cSDimitry Andric #endif
1370b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterIsExpression:
1380b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterUnused:
1390b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterOffsetFromCFA:
140d56accc7SDimitry Andric   case CFI_Parser<A>::kRegisterInCFADecrypt:
1410b57cec5SDimitry Andric     // FIX ME
1420b57cec5SDimitry Andric     break;
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric   _LIBUNWIND_ABORT("unsupported restore location for float register");
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric template <typename A, typename R>
getSavedVectorRegister(A & addressSpace,const R & registers,pint_t cfa,const RegisterLocation & savedReg)1480b57cec5SDimitry Andric v128 DwarfInstructions<A, R>::getSavedVectorRegister(
1490b57cec5SDimitry Andric     A &addressSpace, const R &registers, pint_t cfa,
1500b57cec5SDimitry Andric     const RegisterLocation &savedReg) {
1510b57cec5SDimitry Andric   switch (savedReg.location) {
1520b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterInCFA:
1530b57cec5SDimitry Andric     return addressSpace.getVector(cfa + (pint_t)savedReg.value);
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterAtExpression:
1560b57cec5SDimitry Andric     return addressSpace.getVector(
1570b57cec5SDimitry Andric         evaluateExpression((pint_t)savedReg.value, addressSpace,
1580b57cec5SDimitry Andric                             registers, cfa));
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterIsExpression:
1610b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterUnused:
1620b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterOffsetFromCFA:
1630b57cec5SDimitry Andric   case CFI_Parser<A>::kRegisterInRegister:
164d56accc7SDimitry Andric   case CFI_Parser<A>::kRegisterInCFADecrypt:
1650b57cec5SDimitry Andric     // FIX ME
1660b57cec5SDimitry Andric     break;
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric   _LIBUNWIND_ABORT("unsupported restore location for vector register");
1690b57cec5SDimitry Andric }
17081ad6265SDimitry Andric #if defined(_LIBUNWIND_TARGET_AARCH64)
17181ad6265SDimitry Andric template <typename A, typename R>
getRA_SIGN_STATE(A & addressSpace,R registers,pint_t cfa,PrologInfo & prolog)17281ad6265SDimitry Andric bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
17381ad6265SDimitry Andric                                                pint_t cfa, PrologInfo &prolog) {
17481ad6265SDimitry Andric   pint_t raSignState;
17581ad6265SDimitry Andric   auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
17681ad6265SDimitry Andric   if (regloc.location == CFI_Parser<A>::kRegisterUnused)
17781ad6265SDimitry Andric     raSignState = static_cast<pint_t>(regloc.value);
17881ad6265SDimitry Andric   else
17981ad6265SDimitry Andric     raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
18081ad6265SDimitry Andric 
18181ad6265SDimitry Andric   // Only bit[0] is meaningful.
18281ad6265SDimitry Andric   return raSignState & 0x01;
18381ad6265SDimitry Andric }
18481ad6265SDimitry Andric #endif
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric template <typename A, typename R>
stepWithDwarf(A & addressSpace,pint_t pc,pint_t fdeStart,R & registers,bool & isSignalFrame,bool stage2)1870b57cec5SDimitry Andric int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
188480093f4SDimitry Andric                                            pint_t fdeStart, R &registers,
189bdd1243dSDimitry Andric                                            bool &isSignalFrame, bool stage2) {
1900b57cec5SDimitry Andric   FDE_Info fdeInfo;
1910b57cec5SDimitry Andric   CIE_Info cieInfo;
1920b57cec5SDimitry Andric   if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
1930b57cec5SDimitry Andric                                &cieInfo) == NULL) {
1940b57cec5SDimitry Andric     PrologInfo prolog;
1950b57cec5SDimitry Andric     if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
1960b57cec5SDimitry Andric                                             R::getArch(), &prolog)) {
1970b57cec5SDimitry Andric       // get pointer to cfa (architecture specific)
1980b57cec5SDimitry Andric       pint_t cfa = getCFA(addressSpace, prolog, registers);
1990b57cec5SDimitry Andric 
200bdd1243dSDimitry Andric       (void)stage2;
201bdd1243dSDimitry Andric       // __unw_step_stage2 is not used for cross unwinding, so we use
202bdd1243dSDimitry Andric       // __aarch64__ rather than LIBUNWIND_TARGET_AARCH64 to make sure we are
203bdd1243dSDimitry Andric       // building for AArch64 natively.
204bdd1243dSDimitry Andric #if defined(__aarch64__)
205bdd1243dSDimitry Andric       if (stage2 && cieInfo.mteTaggedFrame) {
206bdd1243dSDimitry Andric         pint_t sp = registers.getSP();
207bdd1243dSDimitry Andric         pint_t p = sp;
208bdd1243dSDimitry Andric         // AArch64 doesn't require the value of SP to be 16-byte aligned at
209bdd1243dSDimitry Andric         // all times, only at memory accesses and public interfaces [1]. Thus,
210bdd1243dSDimitry Andric         // a signal could arrive at a point where SP is not aligned properly.
211bdd1243dSDimitry Andric         // In that case, the kernel fixes up [2] the signal frame, but we
212bdd1243dSDimitry Andric         // still have a misaligned SP in the previous frame. If that signal
213bdd1243dSDimitry Andric         // handler caused stack unwinding, we would have an unaligned SP.
214bdd1243dSDimitry Andric         // We do not need to fix up the CFA, as that is the SP at a "public
215bdd1243dSDimitry Andric         // interface".
216bdd1243dSDimitry Andric         // [1]:
217bdd1243dSDimitry Andric         // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#622the-stack
218bdd1243dSDimitry Andric         // [2]:
219bdd1243dSDimitry Andric         // https://github.com/torvalds/linux/blob/1930a6e739c4b4a654a69164dbe39e554d228915/arch/arm64/kernel/signal.c#L718
220bdd1243dSDimitry Andric         p &= ~0xfULL;
221bdd1243dSDimitry Andric         // CFA is the bottom of the current stack frame.
222bdd1243dSDimitry Andric         for (; p < cfa; p += 16) {
223*1ac55f4cSDimitry Andric           __asm__ __volatile__(".arch armv8.5-a\n"
224*1ac55f4cSDimitry Andric                                ".arch_extension memtag\n"
225bdd1243dSDimitry Andric                                "stg %[Ptr], [%[Ptr]]\n"
226bdd1243dSDimitry Andric                                :
227bdd1243dSDimitry Andric                                : [Ptr] "r"(p)
228bdd1243dSDimitry Andric                                : "memory");
229bdd1243dSDimitry Andric         }
230bdd1243dSDimitry Andric       }
231bdd1243dSDimitry Andric #endif
2320b57cec5SDimitry Andric       // restore registers that DWARF says were saved
2330b57cec5SDimitry Andric       R newRegisters = registers;
234fe6060f1SDimitry Andric 
235fe6060f1SDimitry Andric       // Typically, the CFA is the stack pointer at the call site in
236fe6060f1SDimitry Andric       // the previous frame. However, there are scenarios in which this is not
237fe6060f1SDimitry Andric       // true. For example, if we switched to a new stack. In that case, the
238fe6060f1SDimitry Andric       // value of the previous SP might be indicated by a CFI directive.
239fe6060f1SDimitry Andric       //
240fe6060f1SDimitry Andric       // We set the SP here to the CFA, allowing for it to be overridden
241fe6060f1SDimitry Andric       // by a CFI directive later on.
242fe6060f1SDimitry Andric       newRegisters.setSP(cfa);
243fe6060f1SDimitry Andric 
2440b57cec5SDimitry Andric       pint_t returnAddress = 0;
24581ad6265SDimitry Andric       constexpr int lastReg = R::lastDwarfRegNum();
24681ad6265SDimitry Andric       static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
24781ad6265SDimitry Andric                         lastReg,
2480b57cec5SDimitry Andric                     "register range too large");
2490b57cec5SDimitry Andric       assert(lastReg >= (int)cieInfo.returnAddressRegister &&
2500b57cec5SDimitry Andric              "register range does not contain return address register");
2510b57cec5SDimitry Andric       for (int i = 0; i <= lastReg; ++i) {
2520b57cec5SDimitry Andric         if (prolog.savedRegisters[i].location !=
2530b57cec5SDimitry Andric             CFI_Parser<A>::kRegisterUnused) {
2540b57cec5SDimitry Andric           if (registers.validFloatRegister(i))
2550b57cec5SDimitry Andric             newRegisters.setFloatRegister(
2560b57cec5SDimitry Andric                 i, getSavedFloatRegister(addressSpace, registers, cfa,
2570b57cec5SDimitry Andric                                          prolog.savedRegisters[i]));
2580b57cec5SDimitry Andric           else if (registers.validVectorRegister(i))
2590b57cec5SDimitry Andric             newRegisters.setVectorRegister(
2600b57cec5SDimitry Andric                 i, getSavedVectorRegister(addressSpace, registers, cfa,
2610b57cec5SDimitry Andric                                           prolog.savedRegisters[i]));
2620b57cec5SDimitry Andric           else if (i == (int)cieInfo.returnAddressRegister)
2630b57cec5SDimitry Andric             returnAddress = getSavedRegister(addressSpace, registers, cfa,
2640b57cec5SDimitry Andric                                              prolog.savedRegisters[i]);
2650b57cec5SDimitry Andric           else if (registers.validRegister(i))
2660b57cec5SDimitry Andric             newRegisters.setRegister(
2670b57cec5SDimitry Andric                 i, getSavedRegister(addressSpace, registers, cfa,
2680b57cec5SDimitry Andric                                     prolog.savedRegisters[i]));
2690b57cec5SDimitry Andric           else
2700b57cec5SDimitry Andric             return UNW_EBADREG;
2710b57cec5SDimitry Andric         }
2720b57cec5SDimitry Andric       }
2730b57cec5SDimitry Andric 
274480093f4SDimitry Andric       isSignalFrame = cieInfo.isSignalFrame;
275480093f4SDimitry Andric 
2760b57cec5SDimitry Andric #if defined(_LIBUNWIND_TARGET_AARCH64)
2770b57cec5SDimitry Andric       // If the target is aarch64 then the return address may have been signed
2780b57cec5SDimitry Andric       // using the v8.3 pointer authentication extensions. The original
2790b57cec5SDimitry Andric       // return address needs to be authenticated before the return address is
2800b57cec5SDimitry Andric       // restored. autia1716 is used instead of autia as autia1716 assembles
2810b57cec5SDimitry Andric       // to a NOP on pre-v8.3a architectures.
2820b57cec5SDimitry Andric       if ((R::getArch() == REGISTERS_ARM64) &&
28381ad6265SDimitry Andric           getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
284fe6060f1SDimitry Andric           returnAddress != 0) {
2850b57cec5SDimitry Andric #if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
2860b57cec5SDimitry Andric         return UNW_ECROSSRASIGNING;
2870b57cec5SDimitry Andric #else
2880b57cec5SDimitry Andric         register unsigned long long x17 __asm("x17") = returnAddress;
2890b57cec5SDimitry Andric         register unsigned long long x16 __asm("x16") = cfa;
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric         // These are the autia1716/autib1716 instructions. The hint instructions
2920b57cec5SDimitry Andric         // are used here as gcc does not assemble autia1716/autib1716 for pre
2930b57cec5SDimitry Andric         // armv8.3a targets.
2940b57cec5SDimitry Andric         if (cieInfo.addressesSignedWithBKey)
2950b57cec5SDimitry Andric           asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
2960b57cec5SDimitry Andric         else
2970b57cec5SDimitry Andric           asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
2980b57cec5SDimitry Andric         returnAddress = x17;
2990b57cec5SDimitry Andric #endif
3000b57cec5SDimitry Andric       }
3010b57cec5SDimitry Andric #endif
3020b57cec5SDimitry Andric 
3030eae32dcSDimitry Andric #if defined(_LIBUNWIND_IS_NATIVE_ONLY) && defined(_LIBUNWIND_TARGET_ARM) &&    \
3040eae32dcSDimitry Andric     defined(__ARM_FEATURE_PAUTH)
3050eae32dcSDimitry Andric       if ((R::getArch() == REGISTERS_ARM) &&
3060eae32dcSDimitry Andric           prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE].value) {
3070eae32dcSDimitry Andric         pint_t pac =
3080eae32dcSDimitry Andric             getSavedRegister(addressSpace, registers, cfa,
3090eae32dcSDimitry Andric                              prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE]);
3100eae32dcSDimitry Andric         __asm__ __volatile__("autg %0, %1, %2"
3110eae32dcSDimitry Andric                              :
3120eae32dcSDimitry Andric                              : "r"(pac), "r"(returnAddress), "r"(cfa)
3130eae32dcSDimitry Andric                              :);
3140eae32dcSDimitry Andric       }
3150eae32dcSDimitry Andric #endif
3160eae32dcSDimitry Andric 
3170b57cec5SDimitry Andric #if defined(_LIBUNWIND_TARGET_SPARC)
3180b57cec5SDimitry Andric       if (R::getArch() == REGISTERS_SPARC) {
3190b57cec5SDimitry Andric         // Skip call site instruction and delay slot
3200b57cec5SDimitry Andric         returnAddress += 8;
3210b57cec5SDimitry Andric         // Skip unimp instruction if function returns a struct
3220b57cec5SDimitry Andric         if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
3230b57cec5SDimitry Andric           returnAddress += 4;
3240b57cec5SDimitry Andric       }
3250b57cec5SDimitry Andric #endif
3260b57cec5SDimitry Andric 
327d56accc7SDimitry Andric #if defined(_LIBUNWIND_TARGET_SPARC64)
328d56accc7SDimitry Andric       // Skip call site instruction and delay slot.
329d56accc7SDimitry Andric       if (R::getArch() == REGISTERS_SPARC64)
330d56accc7SDimitry Andric         returnAddress += 8;
331d56accc7SDimitry Andric #endif
332d56accc7SDimitry Andric 
3330b57cec5SDimitry Andric #if defined(_LIBUNWIND_TARGET_PPC64)
3340b57cec5SDimitry Andric #define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
3350b57cec5SDimitry Andric #define PPC64_ELFV1_R2_OFFSET 40
3360b57cec5SDimitry Andric #define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1)
3370b57cec5SDimitry Andric #define PPC64_ELFV2_R2_OFFSET 24
3380b57cec5SDimitry Andric       // If the instruction at return address is a TOC (r2) restore,
3390b57cec5SDimitry Andric       // then r2 was saved and needs to be restored.
3400b57cec5SDimitry Andric       // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24,
3410b57cec5SDimitry Andric       // while in ELFv1 ABI it is saved at SP + 40.
3420b57cec5SDimitry Andric       if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) {
3430b57cec5SDimitry Andric         pint_t sp = newRegisters.getRegister(UNW_REG_SP);
3440b57cec5SDimitry Andric         pint_t r2 = 0;
3450b57cec5SDimitry Andric         switch (addressSpace.get32(returnAddress)) {
3460b57cec5SDimitry Andric         case PPC64_ELFV1_R2_LOAD_INST_ENCODING:
3470b57cec5SDimitry Andric           r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET);
3480b57cec5SDimitry Andric           break;
3490b57cec5SDimitry Andric         case PPC64_ELFV2_R2_LOAD_INST_ENCODING:
3500b57cec5SDimitry Andric           r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET);
3510b57cec5SDimitry Andric           break;
3520b57cec5SDimitry Andric         }
3530b57cec5SDimitry Andric         if (r2)
3540b57cec5SDimitry Andric           newRegisters.setRegister(UNW_PPC64_R2, r2);
3550b57cec5SDimitry Andric       }
3560b57cec5SDimitry Andric #endif
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric       // Return address is address after call site instruction, so setting IP to
359bdd1243dSDimitry Andric       // that does simulates a return.
3600b57cec5SDimitry Andric       newRegisters.setIP(returnAddress);
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric       // Simulate the step by replacing the register set with the new ones.
3630b57cec5SDimitry Andric       registers = newRegisters;
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric       return UNW_STEP_SUCCESS;
3660b57cec5SDimitry Andric     }
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric   return UNW_EBADFRAME;
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric template <typename A, typename R>
3720b57cec5SDimitry Andric typename A::pint_t
evaluateExpression(pint_t expression,A & addressSpace,const R & registers,pint_t initialStackValue)3730b57cec5SDimitry Andric DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
3740b57cec5SDimitry Andric                                             const R &registers,
3750b57cec5SDimitry Andric                                             pint_t initialStackValue) {
3760b57cec5SDimitry Andric   const bool log = false;
3770b57cec5SDimitry Andric   pint_t p = expression;
3780b57cec5SDimitry Andric   pint_t expressionEnd = expression + 20; // temp, until len read
3790b57cec5SDimitry Andric   pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd);
3800b57cec5SDimitry Andric   expressionEnd = p + length;
3810b57cec5SDimitry Andric   if (log)
3820b57cec5SDimitry Andric     fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n",
3830b57cec5SDimitry Andric             (uint64_t)length);
3840b57cec5SDimitry Andric   pint_t stack[100];
3850b57cec5SDimitry Andric   pint_t *sp = stack;
3860b57cec5SDimitry Andric   *(++sp) = initialStackValue;
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric   while (p < expressionEnd) {
3890b57cec5SDimitry Andric     if (log) {
3900b57cec5SDimitry Andric       for (pint_t *t = sp; t > stack; --t) {
3910b57cec5SDimitry Andric         fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t));
3920b57cec5SDimitry Andric       }
3930b57cec5SDimitry Andric     }
3940b57cec5SDimitry Andric     uint8_t opcode = addressSpace.get8(p++);
3950b57cec5SDimitry Andric     sint_t svalue, svalue2;
3960b57cec5SDimitry Andric     pint_t value;
3970b57cec5SDimitry Andric     uint32_t reg;
3980b57cec5SDimitry Andric     switch (opcode) {
3990b57cec5SDimitry Andric     case DW_OP_addr:
4000b57cec5SDimitry Andric       // push immediate address sized value
4010b57cec5SDimitry Andric       value = addressSpace.getP(p);
4020b57cec5SDimitry Andric       p += sizeof(pint_t);
4030b57cec5SDimitry Andric       *(++sp) = value;
4040b57cec5SDimitry Andric       if (log)
4050b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
4060b57cec5SDimitry Andric       break;
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric     case DW_OP_deref:
4090b57cec5SDimitry Andric       // pop stack, dereference, push result
4100b57cec5SDimitry Andric       value = *sp--;
4110b57cec5SDimitry Andric       *(++sp) = addressSpace.getP(value);
4120b57cec5SDimitry Andric       if (log)
4130b57cec5SDimitry Andric         fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value);
4140b57cec5SDimitry Andric       break;
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric     case DW_OP_const1u:
4170b57cec5SDimitry Andric       // push immediate 1 byte value
4180b57cec5SDimitry Andric       value = addressSpace.get8(p);
4190b57cec5SDimitry Andric       p += 1;
4200b57cec5SDimitry Andric       *(++sp) = value;
4210b57cec5SDimitry Andric       if (log)
4220b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
4230b57cec5SDimitry Andric       break;
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric     case DW_OP_const1s:
4260b57cec5SDimitry Andric       // push immediate 1 byte signed value
4270b57cec5SDimitry Andric       svalue = (int8_t) addressSpace.get8(p);
4280b57cec5SDimitry Andric       p += 1;
4290b57cec5SDimitry Andric       *(++sp) = (pint_t)svalue;
4300b57cec5SDimitry Andric       if (log)
4310b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
4320b57cec5SDimitry Andric       break;
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric     case DW_OP_const2u:
4350b57cec5SDimitry Andric       // push immediate 2 byte value
4360b57cec5SDimitry Andric       value = addressSpace.get16(p);
4370b57cec5SDimitry Andric       p += 2;
4380b57cec5SDimitry Andric       *(++sp) = value;
4390b57cec5SDimitry Andric       if (log)
4400b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
4410b57cec5SDimitry Andric       break;
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric     case DW_OP_const2s:
4440b57cec5SDimitry Andric       // push immediate 2 byte signed value
4450b57cec5SDimitry Andric       svalue = (int16_t) addressSpace.get16(p);
4460b57cec5SDimitry Andric       p += 2;
4470b57cec5SDimitry Andric       *(++sp) = (pint_t)svalue;
4480b57cec5SDimitry Andric       if (log)
4490b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
4500b57cec5SDimitry Andric       break;
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric     case DW_OP_const4u:
4530b57cec5SDimitry Andric       // push immediate 4 byte value
4540b57cec5SDimitry Andric       value = addressSpace.get32(p);
4550b57cec5SDimitry Andric       p += 4;
4560b57cec5SDimitry Andric       *(++sp) = value;
4570b57cec5SDimitry Andric       if (log)
4580b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
4590b57cec5SDimitry Andric       break;
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric     case DW_OP_const4s:
4620b57cec5SDimitry Andric       // push immediate 4 byte signed value
4630b57cec5SDimitry Andric       svalue = (int32_t)addressSpace.get32(p);
4640b57cec5SDimitry Andric       p += 4;
4650b57cec5SDimitry Andric       *(++sp) = (pint_t)svalue;
4660b57cec5SDimitry Andric       if (log)
4670b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
4680b57cec5SDimitry Andric       break;
4690b57cec5SDimitry Andric 
4700b57cec5SDimitry Andric     case DW_OP_const8u:
4710b57cec5SDimitry Andric       // push immediate 8 byte value
4720b57cec5SDimitry Andric       value = (pint_t)addressSpace.get64(p);
4730b57cec5SDimitry Andric       p += 8;
4740b57cec5SDimitry Andric       *(++sp) = value;
4750b57cec5SDimitry Andric       if (log)
4760b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
4770b57cec5SDimitry Andric       break;
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric     case DW_OP_const8s:
4800b57cec5SDimitry Andric       // push immediate 8 byte signed value
4810b57cec5SDimitry Andric       value = (pint_t)addressSpace.get64(p);
4820b57cec5SDimitry Andric       p += 8;
4830b57cec5SDimitry Andric       *(++sp) = value;
4840b57cec5SDimitry Andric       if (log)
4850b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
4860b57cec5SDimitry Andric       break;
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric     case DW_OP_constu:
4890b57cec5SDimitry Andric       // push immediate ULEB128 value
4900b57cec5SDimitry Andric       value = (pint_t)addressSpace.getULEB128(p, expressionEnd);
4910b57cec5SDimitry Andric       *(++sp) = value;
4920b57cec5SDimitry Andric       if (log)
4930b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
4940b57cec5SDimitry Andric       break;
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric     case DW_OP_consts:
4970b57cec5SDimitry Andric       // push immediate SLEB128 value
4980b57cec5SDimitry Andric       svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
4990b57cec5SDimitry Andric       *(++sp) = (pint_t)svalue;
5000b57cec5SDimitry Andric       if (log)
5010b57cec5SDimitry Andric         fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
5020b57cec5SDimitry Andric       break;
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric     case DW_OP_dup:
5050b57cec5SDimitry Andric       // push top of stack
5060b57cec5SDimitry Andric       value = *sp;
5070b57cec5SDimitry Andric       *(++sp) = value;
5080b57cec5SDimitry Andric       if (log)
5090b57cec5SDimitry Andric         fprintf(stderr, "duplicate top of stack\n");
5100b57cec5SDimitry Andric       break;
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric     case DW_OP_drop:
5130b57cec5SDimitry Andric       // pop
5140b57cec5SDimitry Andric       --sp;
5150b57cec5SDimitry Andric       if (log)
5160b57cec5SDimitry Andric         fprintf(stderr, "pop top of stack\n");
5170b57cec5SDimitry Andric       break;
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric     case DW_OP_over:
5200b57cec5SDimitry Andric       // dup second
5210b57cec5SDimitry Andric       value = sp[-1];
5220b57cec5SDimitry Andric       *(++sp) = value;
5230b57cec5SDimitry Andric       if (log)
5240b57cec5SDimitry Andric         fprintf(stderr, "duplicate second in stack\n");
5250b57cec5SDimitry Andric       break;
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric     case DW_OP_pick:
5280b57cec5SDimitry Andric       // pick from
5290b57cec5SDimitry Andric       reg = addressSpace.get8(p);
5300b57cec5SDimitry Andric       p += 1;
531480093f4SDimitry Andric       value = sp[-(int)reg];
5320b57cec5SDimitry Andric       *(++sp) = value;
5330b57cec5SDimitry Andric       if (log)
5340b57cec5SDimitry Andric         fprintf(stderr, "duplicate %d in stack\n", reg);
5350b57cec5SDimitry Andric       break;
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric     case DW_OP_swap:
5380b57cec5SDimitry Andric       // swap top two
5390b57cec5SDimitry Andric       value = sp[0];
5400b57cec5SDimitry Andric       sp[0] = sp[-1];
5410b57cec5SDimitry Andric       sp[-1] = value;
5420b57cec5SDimitry Andric       if (log)
5430b57cec5SDimitry Andric         fprintf(stderr, "swap top of stack\n");
5440b57cec5SDimitry Andric       break;
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric     case DW_OP_rot:
5470b57cec5SDimitry Andric       // rotate top three
5480b57cec5SDimitry Andric       value = sp[0];
5490b57cec5SDimitry Andric       sp[0] = sp[-1];
5500b57cec5SDimitry Andric       sp[-1] = sp[-2];
5510b57cec5SDimitry Andric       sp[-2] = value;
5520b57cec5SDimitry Andric       if (log)
5530b57cec5SDimitry Andric         fprintf(stderr, "rotate top three of stack\n");
5540b57cec5SDimitry Andric       break;
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric     case DW_OP_xderef:
5570b57cec5SDimitry Andric       // pop stack, dereference, push result
5580b57cec5SDimitry Andric       value = *sp--;
5590b57cec5SDimitry Andric       *sp = *((pint_t*)value);
5600b57cec5SDimitry Andric       if (log)
5610b57cec5SDimitry Andric         fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value);
5620b57cec5SDimitry Andric       break;
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric     case DW_OP_abs:
5650b57cec5SDimitry Andric       svalue = (sint_t)*sp;
5660b57cec5SDimitry Andric       if (svalue < 0)
5670b57cec5SDimitry Andric         *sp = (pint_t)(-svalue);
5680b57cec5SDimitry Andric       if (log)
5690b57cec5SDimitry Andric         fprintf(stderr, "abs\n");
5700b57cec5SDimitry Andric       break;
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric     case DW_OP_and:
5730b57cec5SDimitry Andric       value = *sp--;
5740b57cec5SDimitry Andric       *sp &= value;
5750b57cec5SDimitry Andric       if (log)
5760b57cec5SDimitry Andric         fprintf(stderr, "and\n");
5770b57cec5SDimitry Andric       break;
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric     case DW_OP_div:
5800b57cec5SDimitry Andric       svalue = (sint_t)(*sp--);
5810b57cec5SDimitry Andric       svalue2 = (sint_t)*sp;
5820b57cec5SDimitry Andric       *sp = (pint_t)(svalue2 / svalue);
5830b57cec5SDimitry Andric       if (log)
5840b57cec5SDimitry Andric         fprintf(stderr, "div\n");
5850b57cec5SDimitry Andric       break;
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric     case DW_OP_minus:
5880b57cec5SDimitry Andric       value = *sp--;
5890b57cec5SDimitry Andric       *sp = *sp - value;
5900b57cec5SDimitry Andric       if (log)
5910b57cec5SDimitry Andric         fprintf(stderr, "minus\n");
5920b57cec5SDimitry Andric       break;
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric     case DW_OP_mod:
5950b57cec5SDimitry Andric       svalue = (sint_t)(*sp--);
5960b57cec5SDimitry Andric       svalue2 = (sint_t)*sp;
5970b57cec5SDimitry Andric       *sp = (pint_t)(svalue2 % svalue);
5980b57cec5SDimitry Andric       if (log)
5990b57cec5SDimitry Andric         fprintf(stderr, "module\n");
6000b57cec5SDimitry Andric       break;
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric     case DW_OP_mul:
6030b57cec5SDimitry Andric       svalue = (sint_t)(*sp--);
6040b57cec5SDimitry Andric       svalue2 = (sint_t)*sp;
6050b57cec5SDimitry Andric       *sp = (pint_t)(svalue2 * svalue);
6060b57cec5SDimitry Andric       if (log)
6070b57cec5SDimitry Andric         fprintf(stderr, "mul\n");
6080b57cec5SDimitry Andric       break;
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric     case DW_OP_neg:
6110b57cec5SDimitry Andric       *sp = 0 - *sp;
6120b57cec5SDimitry Andric       if (log)
6130b57cec5SDimitry Andric         fprintf(stderr, "neg\n");
6140b57cec5SDimitry Andric       break;
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric     case DW_OP_not:
6170b57cec5SDimitry Andric       svalue = (sint_t)(*sp);
6180b57cec5SDimitry Andric       *sp = (pint_t)(~svalue);
6190b57cec5SDimitry Andric       if (log)
6200b57cec5SDimitry Andric         fprintf(stderr, "not\n");
6210b57cec5SDimitry Andric       break;
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric     case DW_OP_or:
6240b57cec5SDimitry Andric       value = *sp--;
6250b57cec5SDimitry Andric       *sp |= value;
6260b57cec5SDimitry Andric       if (log)
6270b57cec5SDimitry Andric         fprintf(stderr, "or\n");
6280b57cec5SDimitry Andric       break;
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric     case DW_OP_plus:
6310b57cec5SDimitry Andric       value = *sp--;
6320b57cec5SDimitry Andric       *sp += value;
6330b57cec5SDimitry Andric       if (log)
6340b57cec5SDimitry Andric         fprintf(stderr, "plus\n");
6350b57cec5SDimitry Andric       break;
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric     case DW_OP_plus_uconst:
6380b57cec5SDimitry Andric       // pop stack, add uelb128 constant, push result
6390b57cec5SDimitry Andric       *sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
6400b57cec5SDimitry Andric       if (log)
6410b57cec5SDimitry Andric         fprintf(stderr, "add constant\n");
6420b57cec5SDimitry Andric       break;
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric     case DW_OP_shl:
6450b57cec5SDimitry Andric       value = *sp--;
6460b57cec5SDimitry Andric       *sp = *sp << value;
6470b57cec5SDimitry Andric       if (log)
6480b57cec5SDimitry Andric         fprintf(stderr, "shift left\n");
6490b57cec5SDimitry Andric       break;
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric     case DW_OP_shr:
6520b57cec5SDimitry Andric       value = *sp--;
6530b57cec5SDimitry Andric       *sp = *sp >> value;
6540b57cec5SDimitry Andric       if (log)
6550b57cec5SDimitry Andric         fprintf(stderr, "shift left\n");
6560b57cec5SDimitry Andric       break;
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric     case DW_OP_shra:
6590b57cec5SDimitry Andric       value = *sp--;
6600b57cec5SDimitry Andric       svalue = (sint_t)*sp;
6610b57cec5SDimitry Andric       *sp = (pint_t)(svalue >> value);
6620b57cec5SDimitry Andric       if (log)
663bdd1243dSDimitry Andric         fprintf(stderr, "shift left arithmetic\n");
6640b57cec5SDimitry Andric       break;
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric     case DW_OP_xor:
6670b57cec5SDimitry Andric       value = *sp--;
6680b57cec5SDimitry Andric       *sp ^= value;
6690b57cec5SDimitry Andric       if (log)
6700b57cec5SDimitry Andric         fprintf(stderr, "xor\n");
6710b57cec5SDimitry Andric       break;
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric     case DW_OP_skip:
6740b57cec5SDimitry Andric       svalue = (int16_t) addressSpace.get16(p);
6750b57cec5SDimitry Andric       p += 2;
6760b57cec5SDimitry Andric       p = (pint_t)((sint_t)p + svalue);
6770b57cec5SDimitry Andric       if (log)
6780b57cec5SDimitry Andric         fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue);
6790b57cec5SDimitry Andric       break;
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric     case DW_OP_bra:
6820b57cec5SDimitry Andric       svalue = (int16_t) addressSpace.get16(p);
6830b57cec5SDimitry Andric       p += 2;
6840b57cec5SDimitry Andric       if (*sp--)
6850b57cec5SDimitry Andric         p = (pint_t)((sint_t)p + svalue);
6860b57cec5SDimitry Andric       if (log)
6870b57cec5SDimitry Andric         fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue);
6880b57cec5SDimitry Andric       break;
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric     case DW_OP_eq:
6910b57cec5SDimitry Andric       value = *sp--;
6920b57cec5SDimitry Andric       *sp = (*sp == value);
6930b57cec5SDimitry Andric       if (log)
6940b57cec5SDimitry Andric         fprintf(stderr, "eq\n");
6950b57cec5SDimitry Andric       break;
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric     case DW_OP_ge:
6980b57cec5SDimitry Andric       value = *sp--;
6990b57cec5SDimitry Andric       *sp = (*sp >= value);
7000b57cec5SDimitry Andric       if (log)
7010b57cec5SDimitry Andric         fprintf(stderr, "ge\n");
7020b57cec5SDimitry Andric       break;
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric     case DW_OP_gt:
7050b57cec5SDimitry Andric       value = *sp--;
7060b57cec5SDimitry Andric       *sp = (*sp > value);
7070b57cec5SDimitry Andric       if (log)
7080b57cec5SDimitry Andric         fprintf(stderr, "gt\n");
7090b57cec5SDimitry Andric       break;
7100b57cec5SDimitry Andric 
7110b57cec5SDimitry Andric     case DW_OP_le:
7120b57cec5SDimitry Andric       value = *sp--;
7130b57cec5SDimitry Andric       *sp = (*sp <= value);
7140b57cec5SDimitry Andric       if (log)
7150b57cec5SDimitry Andric         fprintf(stderr, "le\n");
7160b57cec5SDimitry Andric       break;
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric     case DW_OP_lt:
7190b57cec5SDimitry Andric       value = *sp--;
7200b57cec5SDimitry Andric       *sp = (*sp < value);
7210b57cec5SDimitry Andric       if (log)
7220b57cec5SDimitry Andric         fprintf(stderr, "lt\n");
7230b57cec5SDimitry Andric       break;
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric     case DW_OP_ne:
7260b57cec5SDimitry Andric       value = *sp--;
7270b57cec5SDimitry Andric       *sp = (*sp != value);
7280b57cec5SDimitry Andric       if (log)
7290b57cec5SDimitry Andric         fprintf(stderr, "ne\n");
7300b57cec5SDimitry Andric       break;
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric     case DW_OP_lit0:
7330b57cec5SDimitry Andric     case DW_OP_lit1:
7340b57cec5SDimitry Andric     case DW_OP_lit2:
7350b57cec5SDimitry Andric     case DW_OP_lit3:
7360b57cec5SDimitry Andric     case DW_OP_lit4:
7370b57cec5SDimitry Andric     case DW_OP_lit5:
7380b57cec5SDimitry Andric     case DW_OP_lit6:
7390b57cec5SDimitry Andric     case DW_OP_lit7:
7400b57cec5SDimitry Andric     case DW_OP_lit8:
7410b57cec5SDimitry Andric     case DW_OP_lit9:
7420b57cec5SDimitry Andric     case DW_OP_lit10:
7430b57cec5SDimitry Andric     case DW_OP_lit11:
7440b57cec5SDimitry Andric     case DW_OP_lit12:
7450b57cec5SDimitry Andric     case DW_OP_lit13:
7460b57cec5SDimitry Andric     case DW_OP_lit14:
7470b57cec5SDimitry Andric     case DW_OP_lit15:
7480b57cec5SDimitry Andric     case DW_OP_lit16:
7490b57cec5SDimitry Andric     case DW_OP_lit17:
7500b57cec5SDimitry Andric     case DW_OP_lit18:
7510b57cec5SDimitry Andric     case DW_OP_lit19:
7520b57cec5SDimitry Andric     case DW_OP_lit20:
7530b57cec5SDimitry Andric     case DW_OP_lit21:
7540b57cec5SDimitry Andric     case DW_OP_lit22:
7550b57cec5SDimitry Andric     case DW_OP_lit23:
7560b57cec5SDimitry Andric     case DW_OP_lit24:
7570b57cec5SDimitry Andric     case DW_OP_lit25:
7580b57cec5SDimitry Andric     case DW_OP_lit26:
7590b57cec5SDimitry Andric     case DW_OP_lit27:
7600b57cec5SDimitry Andric     case DW_OP_lit28:
7610b57cec5SDimitry Andric     case DW_OP_lit29:
7620b57cec5SDimitry Andric     case DW_OP_lit30:
7630b57cec5SDimitry Andric     case DW_OP_lit31:
7640b57cec5SDimitry Andric       value = static_cast<pint_t>(opcode - DW_OP_lit0);
7650b57cec5SDimitry Andric       *(++sp) = value;
7660b57cec5SDimitry Andric       if (log)
7670b57cec5SDimitry Andric         fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value);
7680b57cec5SDimitry Andric       break;
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric     case DW_OP_reg0:
7710b57cec5SDimitry Andric     case DW_OP_reg1:
7720b57cec5SDimitry Andric     case DW_OP_reg2:
7730b57cec5SDimitry Andric     case DW_OP_reg3:
7740b57cec5SDimitry Andric     case DW_OP_reg4:
7750b57cec5SDimitry Andric     case DW_OP_reg5:
7760b57cec5SDimitry Andric     case DW_OP_reg6:
7770b57cec5SDimitry Andric     case DW_OP_reg7:
7780b57cec5SDimitry Andric     case DW_OP_reg8:
7790b57cec5SDimitry Andric     case DW_OP_reg9:
7800b57cec5SDimitry Andric     case DW_OP_reg10:
7810b57cec5SDimitry Andric     case DW_OP_reg11:
7820b57cec5SDimitry Andric     case DW_OP_reg12:
7830b57cec5SDimitry Andric     case DW_OP_reg13:
7840b57cec5SDimitry Andric     case DW_OP_reg14:
7850b57cec5SDimitry Andric     case DW_OP_reg15:
7860b57cec5SDimitry Andric     case DW_OP_reg16:
7870b57cec5SDimitry Andric     case DW_OP_reg17:
7880b57cec5SDimitry Andric     case DW_OP_reg18:
7890b57cec5SDimitry Andric     case DW_OP_reg19:
7900b57cec5SDimitry Andric     case DW_OP_reg20:
7910b57cec5SDimitry Andric     case DW_OP_reg21:
7920b57cec5SDimitry Andric     case DW_OP_reg22:
7930b57cec5SDimitry Andric     case DW_OP_reg23:
7940b57cec5SDimitry Andric     case DW_OP_reg24:
7950b57cec5SDimitry Andric     case DW_OP_reg25:
7960b57cec5SDimitry Andric     case DW_OP_reg26:
7970b57cec5SDimitry Andric     case DW_OP_reg27:
7980b57cec5SDimitry Andric     case DW_OP_reg28:
7990b57cec5SDimitry Andric     case DW_OP_reg29:
8000b57cec5SDimitry Andric     case DW_OP_reg30:
8010b57cec5SDimitry Andric     case DW_OP_reg31:
8020b57cec5SDimitry Andric       reg = static_cast<uint32_t>(opcode - DW_OP_reg0);
8030b57cec5SDimitry Andric       *(++sp) = registers.getRegister((int)reg);
8040b57cec5SDimitry Andric       if (log)
8050b57cec5SDimitry Andric         fprintf(stderr, "push reg %d\n", reg);
8060b57cec5SDimitry Andric       break;
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric     case DW_OP_regx:
8090b57cec5SDimitry Andric       reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
8100b57cec5SDimitry Andric       *(++sp) = registers.getRegister((int)reg);
8110b57cec5SDimitry Andric       if (log)
8120b57cec5SDimitry Andric         fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
8130b57cec5SDimitry Andric       break;
8140b57cec5SDimitry Andric 
8150b57cec5SDimitry Andric     case DW_OP_breg0:
8160b57cec5SDimitry Andric     case DW_OP_breg1:
8170b57cec5SDimitry Andric     case DW_OP_breg2:
8180b57cec5SDimitry Andric     case DW_OP_breg3:
8190b57cec5SDimitry Andric     case DW_OP_breg4:
8200b57cec5SDimitry Andric     case DW_OP_breg5:
8210b57cec5SDimitry Andric     case DW_OP_breg6:
8220b57cec5SDimitry Andric     case DW_OP_breg7:
8230b57cec5SDimitry Andric     case DW_OP_breg8:
8240b57cec5SDimitry Andric     case DW_OP_breg9:
8250b57cec5SDimitry Andric     case DW_OP_breg10:
8260b57cec5SDimitry Andric     case DW_OP_breg11:
8270b57cec5SDimitry Andric     case DW_OP_breg12:
8280b57cec5SDimitry Andric     case DW_OP_breg13:
8290b57cec5SDimitry Andric     case DW_OP_breg14:
8300b57cec5SDimitry Andric     case DW_OP_breg15:
8310b57cec5SDimitry Andric     case DW_OP_breg16:
8320b57cec5SDimitry Andric     case DW_OP_breg17:
8330b57cec5SDimitry Andric     case DW_OP_breg18:
8340b57cec5SDimitry Andric     case DW_OP_breg19:
8350b57cec5SDimitry Andric     case DW_OP_breg20:
8360b57cec5SDimitry Andric     case DW_OP_breg21:
8370b57cec5SDimitry Andric     case DW_OP_breg22:
8380b57cec5SDimitry Andric     case DW_OP_breg23:
8390b57cec5SDimitry Andric     case DW_OP_breg24:
8400b57cec5SDimitry Andric     case DW_OP_breg25:
8410b57cec5SDimitry Andric     case DW_OP_breg26:
8420b57cec5SDimitry Andric     case DW_OP_breg27:
8430b57cec5SDimitry Andric     case DW_OP_breg28:
8440b57cec5SDimitry Andric     case DW_OP_breg29:
8450b57cec5SDimitry Andric     case DW_OP_breg30:
8460b57cec5SDimitry Andric     case DW_OP_breg31:
8470b57cec5SDimitry Andric       reg = static_cast<uint32_t>(opcode - DW_OP_breg0);
8480b57cec5SDimitry Andric       svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
8490b57cec5SDimitry Andric       svalue += static_cast<sint_t>(registers.getRegister((int)reg));
8500b57cec5SDimitry Andric       *(++sp) = (pint_t)(svalue);
8510b57cec5SDimitry Andric       if (log)
8520b57cec5SDimitry Andric         fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
8530b57cec5SDimitry Andric       break;
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric     case DW_OP_bregx:
8560b57cec5SDimitry Andric       reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
8570b57cec5SDimitry Andric       svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
8580b57cec5SDimitry Andric       svalue += static_cast<sint_t>(registers.getRegister((int)reg));
8590b57cec5SDimitry Andric       *(++sp) = (pint_t)(svalue);
8600b57cec5SDimitry Andric       if (log)
8610b57cec5SDimitry Andric         fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
8620b57cec5SDimitry Andric       break;
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric     case DW_OP_fbreg:
8650b57cec5SDimitry Andric       _LIBUNWIND_ABORT("DW_OP_fbreg not implemented");
8660b57cec5SDimitry Andric       break;
8670b57cec5SDimitry Andric 
8680b57cec5SDimitry Andric     case DW_OP_piece:
8690b57cec5SDimitry Andric       _LIBUNWIND_ABORT("DW_OP_piece not implemented");
8700b57cec5SDimitry Andric       break;
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric     case DW_OP_deref_size:
8730b57cec5SDimitry Andric       // pop stack, dereference, push result
8740b57cec5SDimitry Andric       value = *sp--;
8750b57cec5SDimitry Andric       switch (addressSpace.get8(p++)) {
8760b57cec5SDimitry Andric       case 1:
8770b57cec5SDimitry Andric         value = addressSpace.get8(value);
8780b57cec5SDimitry Andric         break;
8790b57cec5SDimitry Andric       case 2:
8800b57cec5SDimitry Andric         value = addressSpace.get16(value);
8810b57cec5SDimitry Andric         break;
8820b57cec5SDimitry Andric       case 4:
8830b57cec5SDimitry Andric         value = addressSpace.get32(value);
8840b57cec5SDimitry Andric         break;
8850b57cec5SDimitry Andric       case 8:
8860b57cec5SDimitry Andric         value = (pint_t)addressSpace.get64(value);
8870b57cec5SDimitry Andric         break;
8880b57cec5SDimitry Andric       default:
8890b57cec5SDimitry Andric         _LIBUNWIND_ABORT("DW_OP_deref_size with bad size");
8900b57cec5SDimitry Andric       }
8910b57cec5SDimitry Andric       *(++sp) = value;
8920b57cec5SDimitry Andric       if (log)
8930b57cec5SDimitry Andric         fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value);
8940b57cec5SDimitry Andric       break;
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric     case DW_OP_xderef_size:
8970b57cec5SDimitry Andric     case DW_OP_nop:
8980b57cec5SDimitry Andric     case DW_OP_push_object_addres:
8990b57cec5SDimitry Andric     case DW_OP_call2:
9000b57cec5SDimitry Andric     case DW_OP_call4:
9010b57cec5SDimitry Andric     case DW_OP_call_ref:
9020b57cec5SDimitry Andric     default:
9030b57cec5SDimitry Andric       _LIBUNWIND_ABORT("DWARF opcode not implemented");
9040b57cec5SDimitry Andric     }
9050b57cec5SDimitry Andric 
9060b57cec5SDimitry Andric   }
9070b57cec5SDimitry Andric   if (log)
9080b57cec5SDimitry Andric     fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp);
9090b57cec5SDimitry Andric   return *sp;
9100b57cec5SDimitry Andric }
9110b57cec5SDimitry Andric 
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric } // namespace libunwind
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric #endif // __DWARF_INSTRUCTIONS_HPP__
917