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 ®isters, 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 ®isters, 570b57cec5SDimitry Andric pint_t initialStackValue); 580b57cec5SDimitry Andric static pint_t getSavedRegister(A &addressSpace, const R ®isters, 590b57cec5SDimitry Andric pint_t cfa, const RegisterLocation &savedReg); 600b57cec5SDimitry Andric static double getSavedFloatRegister(A &addressSpace, const R ®isters, 610b57cec5SDimitry Andric pint_t cfa, const RegisterLocation &savedReg); 620b57cec5SDimitry Andric static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, 630b57cec5SDimitry Andric pint_t cfa, const RegisterLocation &savedReg); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, 660b57cec5SDimitry Andric const R ®isters) { 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> 83d56accc7SDimitry Andric auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) { 84d56accc7SDimitry Andric return r.getWCookie(); 85d56accc7SDimitry Andric } 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> 910b57cec5SDimitry Andric typename A::pint_t DwarfInstructions<A, R>::getSavedRegister( 920b57cec5SDimitry Andric A &addressSpace, const R ®isters, 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> 1220b57cec5SDimitry Andric double DwarfInstructions<A, R>::getSavedFloatRegister( 1230b57cec5SDimitry Andric A &addressSpace, const R ®isters, 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> 1480b57cec5SDimitry Andric v128 DwarfInstructions<A, R>::getSavedVectorRegister( 1490b57cec5SDimitry Andric A &addressSpace, const R ®isters, 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> 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> 1870b57cec5SDimitry Andric int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, 188480093f4SDimitry Andric pint_t fdeStart, R ®isters, 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 3730b57cec5SDimitry Andric DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace, 3740b57cec5SDimitry Andric const R ®isters, 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