diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h --- a/libunwind/include/__libunwind_config.h +++ b/libunwind/include/__libunwind_config.h @@ -58,7 +58,11 @@ # elif defined(__ppc__) # define _LIBUNWIND_TARGET_PPC 1 # define _LIBUNWIND_CONTEXT_SIZE 117 +#if defined(_AIX) && defined(__GNUC__) && !defined(__clang__) +#define _LIBUNWIND_CURSOR_SIZE 125 +#else # define _LIBUNWIND_CURSOR_SIZE 124 +#endif # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC # elif defined(__aarch64__) # define _LIBUNWIND_TARGET_AARCH64 1 diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -120,6 +120,9 @@ extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL; #endif +#ifdef _AIX +extern uintptr_t unw_get_data_rel_base(unw_cursor_t *) LIBUNWIND_AVAIL; +#endif extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -24,11 +24,11 @@ #include "Registers.hpp" #ifndef _LIBUNWIND_USE_DLADDR - #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) - #define _LIBUNWIND_USE_DLADDR 1 - #else - #define _LIBUNWIND_USE_DLADDR 0 - #endif +#if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX)) +#define _LIBUNWIND_USE_DLADDR 1 +#else +#define _LIBUNWIND_USE_DLADDR 0 +#endif #endif #if _LIBUNWIND_USE_DLADDR @@ -45,6 +45,12 @@ }; #endif +#if defined(_AIX) +namespace libunwind { +char *getFuncName(uintptr_t pc, uint16_t &NameLen, unw_word_t *offset); +} +#endif + #ifdef __APPLE__ struct dyld_unwind_sections @@ -580,6 +586,11 @@ (void)targetAddr; (void)info; return true; +#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + // The traceback table is used for unwinding. + (void)targetAddr; + (void)info; + return true; #elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) int length = 0; info.arm_section = @@ -596,7 +607,6 @@ return false; } - inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { // TO DO: if OS has way to dynamically register FDEs, check that. (void)targetAddr; @@ -616,6 +626,13 @@ return true; } } +#elif defined(_AIX) + uint16_t nameLen; + char *funcName = getFuncName(addr, nameLen, offset); + if (funcName != NULL) { + snprintf(buf, bufLen, "%.*s", nameLen, funcName); + return true; + } #else (void)addr; (void)buf; diff --git a/libunwind/src/CMakeLists.txt b/libunwind/src/CMakeLists.txt --- a/libunwind/src/CMakeLists.txt +++ b/libunwind/src/CMakeLists.txt @@ -11,6 +11,12 @@ ) endif() +if(${CMAKE_SYSTEM_NAME} MATCHES "AIX") + list(APPEND LIBUNWIND_CXX_SOURCES + Unwind_AIXExtras.cpp + ) +endif() + set(LIBUNWIND_C_SOURCES UnwindLevel1.c UnwindLevel1-gcc-ext.c @@ -26,7 +32,11 @@ ) # See add_asm_sources() in compiler-rt for explanation of this workaround. -if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR (MINGW AND CMAKE_VERSION VERSION_LESS 3.17)) +# CMake doesn't work correctly with assembly on AIX. Workaround by compiling +# as C files as well. +if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR + (MINGW AND CMAKE_VERSION VERSION_LESS 3.17) OR + (${CMAKE_SYSTEM_NAME} MATCHES "AIX")) set_source_files_properties(${LIBUNWIND_ASM_SOURCES} PROPERTIES LANGUAGE C) endif() diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -590,6 +590,8 @@ void setSP(uint32_t value) { _registers.__r1 = value; } uint64_t getIP() const { return _registers.__srr0; } void setIP(uint32_t value) { _registers.__srr0 = value; } + uint64_t getCR() const { return _registers.__cr; } + void setCR(uint32_t value) { _registers.__cr = value; } private: struct ppc_thread_state_t { @@ -1156,6 +1158,8 @@ void setSP(uint64_t value) { _registers.__r1 = value; } uint64_t getIP() const { return _registers.__srr0; } void setIP(uint64_t value) { _registers.__srr0 = value; } + uint64_t getCR() const { return _registers.__cr; } + void setCR(uint64_t value) { _registers.__cr = value; } private: struct ppc64_thread_state_t { diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -23,6 +23,15 @@ #ifdef __APPLE__ #include #endif +#ifdef _AIX +#include +#include + +extern "C" _Unwind_Reason_Code __xlcxx_personality_v0(int, _Unwind_Action, + uint64_t, + _Unwind_Exception *, + struct _Unwind_Context *); +#endif #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) // Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and @@ -449,6 +458,12 @@ #ifdef __arm__ virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); } #endif + +#ifdef _AIX + virtual uintptr_t getDataRelBase() { + _LIBUNWIND_ABORT("getDataRelBase not implemented"); + } +#endif }; #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) @@ -901,6 +916,10 @@ virtual void saveVFPAsX(); #endif +#ifdef _AIX + virtual uintptr_t getDataRelBase(); +#endif + // libunwind does not and should not depend on C++ library which means that we // need our own defition of inline placement new. static void *operator new(size_t, UnwindCursor *p) { return p; } @@ -1192,6 +1211,16 @@ int stepWithSEHData() { /* FIXME: Implement */ return 0; } #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + bool getInfoFromTBTable(pint_t pc, R ®isters); + int stepWithTBTable(pint_t pc, tbtable *TBTable, R ®isters, + bool &isSignalFrame); + int stepWithTBTableData() { + return stepWithTBTable((pint_t)this->getReg(UNW_REG_IP), + (tbtable *)_info.unwind_info, _registers, + _isSignalFrame); + } +#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) A &_addressSpace; R _registers; @@ -1264,6 +1293,13 @@ } #endif +#ifdef _AIX +template +uintptr_t UnwindCursor::getDataRelBase() { + return (uintptr_t)_info.extra; +} +#endif + template const char *UnwindCursor::getRegisterName(int regNum) { return _registers.getRegisterName(regNum); @@ -1892,6 +1928,343 @@ } #endif +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + +// The order of bits has_vec and longtbtable of the traceback table +// structure declared in system header is flipped in newer +// AIX levels. To allow building libunwind on AIX levels that do not have the +// fix, variable TBTableByte6 which points to the byte containing these bits +// in the traceback table and the following masks are used in functions +// getInfoFromTBTable() and stepWithTBTable() for checking these bits in the +// correct order. +#define _LIBUNWIND_TBTABLE_HAS_VEC_BIT 0x80 +#define _LIBUNWIND_TBTABLE_LONGTBTABLE_BIT 0x40 + +// Exception handling info is present if set. +#define _LIBUNWIND_TBTABLE_EH_INFO 0x08 + +template +bool UnwindCursor::getInfoFromTBTable(pint_t pc, R ®isters) { + uint32_t *p = (uint32_t *)pc; + + // Keep looking forward until a word of 0 is found. The traceback + // table starts at the following word. + while (*p) + ++p; + tbtable *TBTable = (tbtable *)(p + 1); + + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if (!getFunctionName(functionBuf, sizeof(functionBuf), &offset)) { + functionName = ".anonymous."; + } + _LIBUNWIND_TRACE_UNWINDING("%s: Look up traceback table of func=%s at %p", + __func__, functionName, (void *)TBTable); + } + + // If the traceback table does not contain necessary info, bypass this frame. + if (!TBTable->tb.has_tboff) + return false; + + // Structure tbtable_ext contains important data we are looking for. + p = (uint32_t *)&TBTable->tb_ext; + + // Skip field parminfo if it exists. + if (TBTable->tb.fixedparms || TBTable->tb.floatparms) + p++; + + // p now points to tb_offset, the offset from start of function to TB table. + unw_word_t start_ip = (unw_word_t)TBTable - *p - sizeof(uint32_t); + unw_word_t end_ip = (unw_word_t)TBTable; + p++; + _LIBUNWIND_TRACE_UNWINDING("start_ip=%p, end_ip=%p\n", (void *)start_ip, + (void *)end_ip); + + // Skip field hand_mask if it exists. + if (TBTable->tb.int_hndl) + p++; + + // Pointer to the 6th byte of the traceback table. + uint8_t *TBTableByte6 = (uint8_t *)TBTable + 5; + + unw_word_t lsda = 0; + unw_word_t handler = 0; + if (TBTable->tb.lang == TB_CPLUSPLUS) { + if (TBTable->tb.has_ctl) { + // State table info is available. The ctl_info field indicates the + // number of CTL anchors. There should be only one entry for the C++ + // state table. + assert(*p == 1 && "XLC++ EH: there must be only one ctl_info entry"); + ++p; + // p points to the offset of the state table into the stack. + pint_t stateOffset = *p++; + + int framePointerReg; + + if (TBTable->tb.uses_alloca) { + // Must find the correct frame pointer register + if (TBTable->tb.name_present) { + const uint16_t name_len = *((uint16_t *)p); + p = (uint32_t *)(((char *)p) + name_len + sizeof(name_len)); + } + framePointerReg = *((char *)p); + } else { + framePointerReg = 1; // default frame pointer == SP + } + + _LIBUNWIND_TRACE_UNWINDING( + "framePointerReg=%d, framePointer=%p, " + "stateOffset=%#lx\n", + framePointerReg, (void *)_registers.getRegister(framePointerReg), + stateOffset); + lsda = _registers.getRegister(framePointerReg) + stateOffset; + handler = reinterpret_cast(__xlcxx_personality_v0); + _LIBUNWIND_TRACE_UNWINDING("State table: LSDA=%p, Personality=%p\n", + (void *)lsda, (void *)handler); + } else if (*TBTableByte6 & _LIBUNWIND_TBTABLE_LONGTBTABLE_BIT) { + // Check traceback table bit longtbtable. This is equivelent to + // "if (TBTable->tb.longtbtable)". If it is set, the range table + // info may be available. + + // p points to field name len. + uint8_t *charPtr = (uint8_t *)p; + + // Skip fields name_len and name if they exist. + if (TBTable->tb.name_present) + charPtr = charPtr + *((uint16_t *)charPtr) + sizeof(uint16_t); + + // Skip field alloc_reg if it exists. + if (TBTable->tb.uses_alloca) + charPtr++; + + // Check traceback table bit has_vec. This is equivalent to + // "if (TBTable->tb.has_vec)". Skip struct vec_ext if it is set. + if (*TBTableByte6 & _LIBUNWIND_TBTABLE_HAS_VEC_BIT) + charPtr += sizeof(struct vec_ext); + + // charPtr points to field xtbtable. + if (*charPtr & _LIBUNWIND_TBTABLE_EH_INFO) { + // eh_info is available. + charPtr++; + // The pointer is 4-byte aligned. + if ((uintptr_t)charPtr % 4) + charPtr += 4 - (uintptr_t)charPtr % 4; + uintptr_t *ehInfo = (uintptr_t *)*( + uintptr_t *)(registers.getRegister(2) + *(uintptr_t *)charPtr); + + // ehInfo points to structure en_info. The first member is version. + // Only version 0 is currently supported. + assert(*(uint32_t *)ehInfo == 0 && + "XLC++ EH: ehInfo version other than 0 is not supported"); + + // Increment ehInfo to point to member lsda. + ++ehInfo; + lsda = *ehInfo++; + + // enInfo now points to member personality. + handler = *ehInfo; + _LIBUNWIND_TRACE_UNWINDING("Range table: LSDA=%#lx, Personality=%#lx\n", + lsda, handler); + } + } + } + + _info.start_ip = start_ip; + _info.end_ip = end_ip; + _info.lsda = lsda; + _info.handler = handler; + _info.gp = 0; + _info.flags = 0; + _info.format = 0; + _info.unwind_info = (unw_word_t)TBTable; + _info.unwind_info_size = 0; + _info.extra = registers.getRegister(2); + + return true; +} + +// Step back up the stack following the frame back link. +template +int UnwindCursor::stepWithTBTable(pint_t pc, tbtable *TBTable, + R ®isters, bool &isSignalFrame) { + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if (!getFunctionName(functionBuf, sizeof(functionBuf), &offset)) { + functionName = ".anonymous."; + } + _LIBUNWIND_TRACE_UNWINDING("%s: Look up traceback table of func=%s at %p", + __func__, functionName, (void *)TBTable); + } + +#if defined(__powerpc64__) + // Instruction to reload TOC register "l r2,40(r1)" + const uint32_t loadTOCRegInst = 0xe8410028; + const int32_t unwPPCF0Index = UNW_PPC64_F0; + const int32_t unwPPCV0Index = UNW_PPC64_V0; +#else + // Instruction to reload TOC register "l r2,20(r1)" + const uint32_t loadTOCRegInst = 0x80410014; + const int32_t unwPPCF0Index = UNW_PPC_F0; + const int32_t unwPPCV0Index = UNW_PPC_V0; +#endif + + R newRegisters = registers; + + // lastStack points to the stack frame of the next routine up. + pint_t lastStack = *((pint_t *)registers.getSP()); + + // Return address is the address after call site instruction. + pint_t returnAddress; + + if (isSignalFrame) { + _LIBUNWIND_TRACE_UNWINDING("Possible signal handler frame: lastStack=%p", + (void *)lastStack); + + sigcontext *sigContext = (sigcontext *)(((char *)lastStack) + STKMIN); + returnAddress = sigContext->sc_jmpbuf.jmp_context.iar; + + _LIBUNWIND_TRACE_UNWINDING("From sigContext=%p, returnAddress=%p\n", + (void *)sigContext, (void *)returnAddress); + + if (returnAddress < 0x10000000) { + // Try again using STKMINALIGN + sigContext = (sigcontext *)(((char *)lastStack) + STKMINALIGN); + returnAddress = sigContext->sc_jmpbuf.jmp_context.iar; + if (returnAddress < 0x10000000) { + _LIBUNWIND_TRACE_UNWINDING("Bad returnAddress=%p\n", + (void *)returnAddress); + return UNW_EBADFRAME; + } else { + _LIBUNWIND_TRACE_UNWINDING("Tried again using STKMINALIGN: " + "sigContext=%p, returnAddress=%p. " + "Seems to be a valid address\n", + (void *)sigContext, (void *)returnAddress); + } + } + // Restore the condition register from sigcontext. + newRegisters.setCR(sigContext->sc_jmpbuf.jmp_context.cr); + + // Restore GPRs from sigcontext. + for (int i = 0; i < 32; ++i) + newRegisters.setRegister(i, sigContext->sc_jmpbuf.jmp_context.gpr[i]); + + // Restore FPRs from sigcontext. + for (int i = 0; i < 32; ++i) + newRegisters.setFloatRegister(i + unwPPCF0Index, + sigContext->sc_jmpbuf.jmp_context.fpr[i]); + + // Restore vector registers if there is an associated extended context + // structure. + if (sigContext->sc_jmpbuf.jmp_context.msr & __EXTCTX) { + ucontext_t *uContext = (ucontext_t *)sigContext; + if (uContext->__extctx->__extctx_magic == __EXTCTX_MAGIC) { + for (int i = 0; i < 32; ++i) + newRegisters.setVectorRegister( + i + unwPPCV0Index, + *(v128 *)(&(uContext->__extctx->__vmx.__vr[i]))); + } + } + } else { + // Step up a normal frame. + returnAddress = ((pint_t *)lastStack)[2]; + + _LIBUNWIND_TRACE_UNWINDING("Extract info from lastStack=%p, " + "returnAddress=%p\n", + (void *)lastStack, (void *)returnAddress); + _LIBUNWIND_TRACE_UNWINDING("fpr_regs=%d, gpr_regs=%d, vr_regs=%d, " + "saves_cr=%d\n", + TBTable->tb.fpr_saved, TBTable->tb.gpr_saved, + TBTable->tb_ext.vec_ext.vr_saved, + TBTable->tb.saves_cr); + + // Restore FP registers. + char *ptrToRegs = (char *)lastStack; + double *FPRegs = + (double *)(ptrToRegs - (TBTable->tb.fpr_saved * sizeof(double))); + for (int i = 0; i < TBTable->tb.fpr_saved; ++i) + newRegisters.setFloatRegister( + 32 - TBTable->tb.fpr_saved + i + unwPPCF0Index, FPRegs[i]); + + // Restore GP registers. + ptrToRegs = (char *)FPRegs; + uintptr_t *GPRegs = + (uintptr_t *)(ptrToRegs - (TBTable->tb.gpr_saved * sizeof(uintptr_t))); + for (int i = 0; i < TBTable->tb.gpr_saved; ++i) + newRegisters.setRegister(32 - TBTable->tb.gpr_saved + i, GPRegs[i]); + + // Restore Vector registers. + ptrToRegs = (char *)GPRegs; + + // Pointer to the 6th byte of the traceback table. + uint8_t *TBTableByte6 = (uint8_t *)TBTable + 5; + + // Check traceback table bit has_vec. This is equivelent to + // "if (TBTable->tb.has_vec)". If it is set, vector info is present. + if (*TBTableByte6 & _LIBUNWIND_TBTABLE_HAS_VEC_BIT) { + // Saved vector registers are 16-byte aligned. + if ((uintptr_t)ptrToRegs % 16) + ptrToRegs += 16 - (uintptr_t)ptrToRegs % 16; + v128 *VecRegs = (v128 *)(ptrToRegs - (TBTable->tb_ext.vec_ext.vr_saved * + sizeof(v128))); + for (int i = 0; i < TBTable->tb_ext.vec_ext.vr_saved; ++i) + newRegisters.setVectorRegister(32 - TBTable->tb_ext.vec_ext.vr_saved + + i + unwPPCV0Index, + VecRegs[i]); + } + if (TBTable->tb.saves_cr) { + // Get the saved condition register. The condition register is only + // a single word. + newRegisters.setCR(*((uint32_t *)(lastStack + sizeof(uintptr_t)))); + } + + // Restore the SP. + newRegisters.setSP(lastStack); + + // The first instruction after return. + uint32_t firstInstruction = *(uint32_t *)returnAddress; + + // Do we need to set the TOC register? + _LIBUNWIND_TRACE_UNWINDING("Current gpr2=%p\n", + (void *)newRegisters.getRegister(2)); + if (firstInstruction == loadTOCRegInst) { + _LIBUNWIND_TRACE_UNWINDING("Set gpr2=%p from frame\n", + (void *)((pint_t *)lastStack)[5]); + newRegisters.setRegister(2, ((pint_t *)lastStack)[5]); + } + } + _LIBUNWIND_TRACE_UNWINDING("lastStack=%p, returnAddress=%p, pc=%p\n", + (void *)lastStack, (void *)returnAddress, + (void *)pc); + + // The return address is the address after call site instruction, so + // setting IP to that simualates a return. + newRegisters.setIP((uintptr_t)returnAddress); + + // Simulate the step by replacing the register set with the new ones. + registers = newRegisters; + + // Check if the next frame is a signal frame. + pint_t nextStack = *((pint_t *)registers.getSP()); + + // Return address is the address after call site instruction. + pint_t nextReturnAddress = ((pint_t *)nextStack)[2]; + + if (nextReturnAddress > 0x01 && nextReturnAddress < 0x10000) { + _LIBUNWIND_TRACE_UNWINDING("The next is a signal handler frame: " + "nextStack=%p, next return address=%p\n", + (void *)nextStack, (void *)nextReturnAddress); + isSignalFrame = true; + } else { + isSignalFrame = false; + } + + return UNW_STEP_SUCCESS; +} +#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) template void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { @@ -1918,7 +2291,14 @@ // To disambiguate this, back up the pc when we know it is a return // address. if (isReturnAddress) +#if defined(_AIX) + // PC needs to be a 4-byte aligned address to be able to look for a + // word of 0 that indicates the start of the traceback table at the end + // of a function on AIX. + pc -= 4; +#else --pc; +#endif // Ask address space object to find unwind sections for this pc. UnwindInfoSections sects; @@ -1952,6 +2332,12 @@ return; #endif +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + // If there is unwind info in the traceback table, look there next. + if (this->getInfoFromTBTable(pc, _registers)) + return; +#endif + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) // If there is dwarf unwind info, look there next. if (sects.dwarf_section != 0) { @@ -2086,6 +2472,8 @@ result = this->stepWithCompactEncoding(); #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) result = this->stepWithSEHData(); +#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + result = this->stepWithTBTableData(); #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) result = this->stepWithDwarfFDE(); #elif defined(_LIBUNWIND_ARM_EHABI) diff --git a/libunwind/src/UnwindLevel1-gcc-ext.c b/libunwind/src/UnwindLevel1-gcc-ext.c --- a/libunwind/src/UnwindLevel1-gcc-ext.c +++ b/libunwind/src/UnwindLevel1-gcc-ext.c @@ -68,9 +68,13 @@ /// relative encodings. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) { - (void)context; _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); +#if defined(_AIX) + return unw_get_data_rel_base((unw_cursor_t *)context); +#else + (void)context; _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); +#endif } diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c --- a/libunwind/src/UnwindLevel1.c +++ b/libunwind/src/UnwindLevel1.c @@ -432,11 +432,13 @@ _LIBUNWIND_TRACE_API( "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, (void *)context, result); +#if !defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) if (result != 0) { if (*((uint8_t *)result) != 0xFF) _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF", result); } +#endif return result; } diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -8,7 +8,9 @@ #include "assembly.h" +#if !defined(_AIX) .text +#endif #if !defined(__USING_SJLJ_EXCEPTIONS__) @@ -134,7 +136,7 @@ // load register (GPR) #define PPC64_LR(n) \ - ld %r##n, (8 * (n + 2))(%r3) + ld GPR(n), (8 * (n + 2))(GPR(3)) // restore integral registers // skip r0 for now @@ -176,12 +178,12 @@ // (note that this also restores floating point registers and V registers, // because part of VS is mapped to these registers) - addi %r4, %r3, PPC64_OFFS_FP + addi GPR(4), GPR(3), PPC64_OFFS_FP // load VS register #define PPC64_LVS(n) \ - lxvd2x %vs##n, 0, %r4 ;\ - addi %r4, %r4, 16 + lxvd2x VSR(n), 0, GPR(4) ;\ + addi GPR(4), GPR(4), 16 // restore the first 32 VS regs (and also all floating point regs) PPC64_LVS(0) @@ -217,27 +219,36 @@ PPC64_LVS(30) PPC64_LVS(31) - // use VRSAVE to conditionally restore the remaining VS regs, - // that are where the V regs are mapped +#define PPC64_CLVS_RESTORE(n) \ + addi GPR(4), GPR(3), PPC64_OFFS_FP + n * 16 ;\ + lxvd2x VSR(n), 0, GPR(4) - ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave - cmpwi %r5, 0 +#if !defined(_AIX) + // use VRSAVE to conditionally restore the remaining VS regs, that are + // where the V regs are mapped. In the AIX ABI, VRSAVE is not used. + ld GPR(5), PPC64_OFFS_VRSAVE(GPR(3)) // test VRsave + cmpwi GPR(5), 0 beq Lnovec // conditionally load VS -#define PPC64_CLVS_BOTTOM(n) \ - beq Ldone##n ;\ - addi %r4, %r3, PPC64_OFFS_FP + n * 16 ;\ - lxvd2x %vs##n, 0, %r4 ;\ +#define PPC64_CLVSl(n) \ + andis. GPR(0), GPR(5), (1 PPC_SHIFT(47-n)) ;\ + beq Ldone##n ;\ + PPC64_CLVS_RESTORE(n) ;\ Ldone##n: -#define PPC64_CLVSl(n) \ - andis. %r0, %r5, (1<<(47-n)) ;\ -PPC64_CLVS_BOTTOM(n) +#define PPC64_CLVSh(n) \ + andi. GPR(0), GPR(5), (1 PPC_SHIFT(63-n)) ;\ + beq Ldone##n ;\ + PPC64_CLVS_RESTORE(n) ;\ +Ldone##n: + +#else + +#define PPC64_CLVSl(n) PPC64_CLVS_RESTORE(n) +#define PPC64_CLVSh(n) PPC64_CLVS_RESTORE(n) -#define PPC64_CLVSh(n) \ - andi. %r0, %r5, (1<<(63-n)) ;\ -PPC64_CLVS_BOTTOM(n) +#endif // !defined(_AIX) PPC64_CLVSl(32) PPC64_CLVSl(33) @@ -276,7 +287,7 @@ // load FP register #define PPC64_LF(n) \ - lfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) + lfd FPR(n), (PPC64_OFFS_FP + n * 16)(GPR(3)) // restore float registers PPC64_LF(0) @@ -313,32 +324,44 @@ PPC64_LF(31) #if defined(__ALTIVEC__) - // restore vector registers if any are in use - ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave - cmpwi %r5, 0 - beq Lnovec - subi %r4, %r1, 16 + subi GPR(4), GPR(1), 16 // r4 is now a 16-byte aligned pointer into the red zone // the _vectorScalarRegisters may not be 16-byte aligned // so copy via red zone temp buffer -#define PPC64_CLV_UNALIGNED_BOTTOM(n) \ - beq Ldone##n ;\ - ld %r0, (PPC64_OFFS_V + n * 16)(%r3) ;\ - std %r0, 0(%r4) ;\ - ld %r0, (PPC64_OFFS_V + n * 16 + 8)(%r3) ;\ - std %r0, 8(%r4) ;\ - lvx %v##n, 0, %r4 ;\ +#define PPC64_CLV_UNALIGNED_RESTORE(n) \ + ld GPR(0), (PPC64_OFFS_V + n * 16)(GPR(3)) ;\ + std GPR(0), 0(GPR(4)) ;\ + ld GPR(0), (PPC64_OFFS_V + n * 16 + 8)(GPR(3)) ;\ + std GPR(0), 8(GPR(4)) ;\ + lvx VR(n), 0, GPR(4) + +#if !defined(_AIX) + // restore vector registers if any are in use. In the AIX ABI, VRSAVE is + // not used. + ld GPR(5), PPC64_OFFS_VRSAVE(GPR(3)) // test VRsave + cmpwi GPR(5), 0 + beq Lnovec + +#define PPC64_CLV_UNALIGNEDl(n) \ + andis. GPR(0), GPR(5), (1 PPC_SHIFT(15-n)) ;\ + beq Ldone##n ;\ + PPC64_CLV_UNALIGNED_RESTORE(n) ;\ Ldone ## n: -#define PPC64_CLV_UNALIGNEDl(n) \ - andis. %r0, %r5, (1<<(15-n)) ;\ -PPC64_CLV_UNALIGNED_BOTTOM(n) +#define PPC64_CLV_UNALIGNEDh(n) \ + andi. GPR(0), GPR(5), (1 PPC_SHIFT(31-n)) ;\ + beq Ldone##n ;\ + PPC64_CLV_UNALIGNED_RESTORE(n) ;\ +Ldone ## n: + +#else + +#define PPC64_CLV_UNALIGNEDl(n) PPC64_CLV_UNALIGNED_RESTORE(n) +#define PPC64_CLV_UNALIGNEDh(n) PPC64_CLV_UNALIGNED_RESTORE(n) -#define PPC64_CLV_UNALIGNEDh(n) \ - andi. %r0, %r5, (1<<(31-n)) ;\ -PPC64_CLV_UNALIGNED_BOTTOM(n) +#endif // !defined(_AIX) PPC64_CLV_UNALIGNEDl(0) PPC64_CLV_UNALIGNEDl(1) @@ -377,16 +400,28 @@ #endif Lnovec: - ld %r0, PPC64_OFFS_CR(%r3) - mtcr %r0 - ld %r0, PPC64_OFFS_SRR0(%r3) - mtctr %r0 + ld GPR(0), PPC64_OFFS_CR(GPR(3)) + mtcr GPR(0) + ld GPR(0), PPC64_OFFS_SRR0(GPR(3)) + mtctr GPR(0) - PPC64_LR(0) PPC64_LR(5) PPC64_LR(4) +#if defined(_AIX) + // After setting GPR1 to a higher address, AIX wipes out the original + // stack space below that address invalidated by the new GPR1 value. Use + // GPR0 to save the value of GPR3 in the context before it is wiped out. + // This compromises the content of GPR0 which is a volatile register. + ld GPR(0), (8 * (3 + 2))(GPR(3)) +#else + PPC64_LR(0) +#endif PPC64_LR(1) +#if defined(_AIX) + mr 3, 0 +#else PPC64_LR(3) +#endif bctr #elif defined(__ppc__) @@ -402,113 +437,115 @@ // restore integral registerrs // skip r0 for now // skip r1 for now - lwz %r2, 16(%r3) + lwz GPR(2), 16(GPR(3)) // skip r3 for now // skip r4 for now // skip r5 for now - lwz %r6, 32(%r3) - lwz %r7, 36(%r3) - lwz %r8, 40(%r3) - lwz %r9, 44(%r3) - lwz %r10, 48(%r3) - lwz %r11, 52(%r3) - lwz %r12, 56(%r3) - lwz %r13, 60(%r3) - lwz %r14, 64(%r3) - lwz %r15, 68(%r3) - lwz %r16, 72(%r3) - lwz %r17, 76(%r3) - lwz %r18, 80(%r3) - lwz %r19, 84(%r3) - lwz %r20, 88(%r3) - lwz %r21, 92(%r3) - lwz %r22, 96(%r3) - lwz %r23,100(%r3) - lwz %r24,104(%r3) - lwz %r25,108(%r3) - lwz %r26,112(%r3) - lwz %r27,116(%r3) - lwz %r28,120(%r3) - lwz %r29,124(%r3) - lwz %r30,128(%r3) - lwz %r31,132(%r3) + lwz GPR(6), 32(GPR(3)) + lwz GPR(7), 36(GPR(3)) + lwz GPR(8), 40(GPR(3)) + lwz GPR(9), 44(GPR(3)) + lwz GPR(10), 48(GPR(3)) + lwz GPR(11), 52(GPR(3)) + lwz GPR(12), 56(GPR(3)) + lwz GPR(13), 60(GPR(3)) + lwz GPR(14), 64(GPR(3)) + lwz GPR(15), 68(GPR(3)) + lwz GPR(16), 72(GPR(3)) + lwz GPR(17), 76(GPR(3)) + lwz GPR(18), 80(GPR(3)) + lwz GPR(19), 84(GPR(3)) + lwz GPR(20), 88(GPR(3)) + lwz GPR(21), 92(GPR(3)) + lwz GPR(22), 96(GPR(3)) + lwz GPR(23),100(GPR(3)) + lwz GPR(24),104(GPR(3)) + lwz GPR(25),108(GPR(3)) + lwz GPR(26),112(GPR(3)) + lwz GPR(27),116(GPR(3)) + lwz GPR(28),120(GPR(3)) + lwz GPR(29),124(GPR(3)) + lwz GPR(30),128(GPR(3)) + lwz GPR(31),132(GPR(3)) #ifndef __NO_FPRS__ // restore float registers - lfd %f0, 160(%r3) - lfd %f1, 168(%r3) - lfd %f2, 176(%r3) - lfd %f3, 184(%r3) - lfd %f4, 192(%r3) - lfd %f5, 200(%r3) - lfd %f6, 208(%r3) - lfd %f7, 216(%r3) - lfd %f8, 224(%r3) - lfd %f9, 232(%r3) - lfd %f10,240(%r3) - lfd %f11,248(%r3) - lfd %f12,256(%r3) - lfd %f13,264(%r3) - lfd %f14,272(%r3) - lfd %f15,280(%r3) - lfd %f16,288(%r3) - lfd %f17,296(%r3) - lfd %f18,304(%r3) - lfd %f19,312(%r3) - lfd %f20,320(%r3) - lfd %f21,328(%r3) - lfd %f22,336(%r3) - lfd %f23,344(%r3) - lfd %f24,352(%r3) - lfd %f25,360(%r3) - lfd %f26,368(%r3) - lfd %f27,376(%r3) - lfd %f28,384(%r3) - lfd %f29,392(%r3) - lfd %f30,400(%r3) - lfd %f31,408(%r3) + lfd FPR(0), 160(GPR(3)) + lfd FPR(1), 168(GPR(3)) + lfd FPR(2), 176(GPR(3)) + lfd FPR(3), 184(GPR(3)) + lfd FPR(4), 192(GPR(3)) + lfd FPR(5), 200(GPR(3)) + lfd FPR(6), 208(GPR(3)) + lfd FPR(7), 216(GPR(3)) + lfd FPR(8), 224(GPR(3)) + lfd FPR(9), 232(GPR(3)) + lfd FPR(10),240(GPR(3)) + lfd FPR(11),248(GPR(3)) + lfd FPR(12),256(GPR(3)) + lfd FPR(13),264(GPR(3)) + lfd FPR(14),272(GPR(3)) + lfd FPR(15),280(GPR(3)) + lfd FPR(16),288(GPR(3)) + lfd FPR(17),296(GPR(3)) + lfd FPR(18),304(GPR(3)) + lfd FPR(19),312(GPR(3)) + lfd FPR(20),320(GPR(3)) + lfd FPR(21),328(GPR(3)) + lfd FPR(22),336(GPR(3)) + lfd FPR(23),344(GPR(3)) + lfd FPR(24),352(GPR(3)) + lfd FPR(25),360(GPR(3)) + lfd FPR(26),368(GPR(3)) + lfd FPR(27),376(GPR(3)) + lfd FPR(28),384(GPR(3)) + lfd FPR(29),392(GPR(3)) + lfd FPR(30),400(GPR(3)) + lfd FPR(31),408(GPR(3)) #endif #if defined(__ALTIVEC__) - // restore vector registers if any are in use - lwz %r5, 156(%r3) // test VRsave - cmpwi %r5, 0 - beq Lnovec - - subi %r4, %r1, 16 - rlwinm %r4, %r4, 0, 0, 27 // mask low 4-bits + subi GPR(4), GPR(1), 16 + rlwinm GPR(4), GPR(4), 0, 0, 27 // mask low 4-bits // r4 is now a 16-byte aligned pointer into the red zone // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer - + +#define LOAD_VECTOR_RESTORE(_index) \ + lwz GPR(0), 424+_index*16(GPR(3)) SEPARATOR \ + stw GPR(0), 0(GPR(4)) SEPARATOR \ + lwz GPR(0), 424+_index*16+4(GPR(3)) SEPARATOR \ + stw GPR(0), 4(GPR(4)) SEPARATOR \ + lwz GPR(0), 424+_index*16+8(GPR(3)) SEPARATOR \ + stw GPR(0), 8(GPR(4)) SEPARATOR \ + lwz GPR(0), 424+_index*16+12(GPR(3)) SEPARATOR \ + stw GPR(0), 12(GPR(4)) SEPARATOR \ + lvx VR(_index), 0, GPR(4) + +#if !defined(_AIX) + // restore vector registers if any are in use. In the AIX ABI, VRSAVE + // is not used. + lwz GPR(5), 156(GPR(3)) // test VRsave + cmpwi GPR(5), 0 + beq Lnovec #define LOAD_VECTOR_UNALIGNEDl(_index) \ - andis. %r0, %r5, (1<<(15-_index)) SEPARATOR \ - beq Ldone ## _index SEPARATOR \ - lwz %r0, 424+_index*16(%r3) SEPARATOR \ - stw %r0, 0(%r4) SEPARATOR \ - lwz %r0, 424+_index*16+4(%r3) SEPARATOR \ - stw %r0, 4(%r4) SEPARATOR \ - lwz %r0, 424+_index*16+8(%r3) SEPARATOR \ - stw %r0, 8(%r4) SEPARATOR \ - lwz %r0, 424+_index*16+12(%r3) SEPARATOR \ - stw %r0, 12(%r4) SEPARATOR \ - lvx %v ## _index, 0, %r4 SEPARATOR \ + andis. GPR(0), GPR(5), (1 PPC_SHIFT(15-_index)) SEPARATOR \ + beq Ldone ## _index SEPARATOR \ + LOAD_VECTOR_RESTORE(_index) SEPARATOR \ Ldone ## _index: #define LOAD_VECTOR_UNALIGNEDh(_index) \ - andi. %r0, %r5, (1<<(31-_index)) SEPARATOR \ - beq Ldone ## _index SEPARATOR \ - lwz %r0, 424+_index*16(%r3) SEPARATOR \ - stw %r0, 0(%r4) SEPARATOR \ - lwz %r0, 424+_index*16+4(%r3) SEPARATOR \ - stw %r0, 4(%r4) SEPARATOR \ - lwz %r0, 424+_index*16+8(%r3) SEPARATOR \ - stw %r0, 8(%r4) SEPARATOR \ - lwz %r0, 424+_index*16+12(%r3) SEPARATOR \ - stw %r0, 12(%r4) SEPARATOR \ - lvx %v ## _index, 0, %r4 SEPARATOR \ + andi. GPR(0), GPR(5), (1 PPC_SHIFT(31-_index)) SEPARATOR \ + beq Ldone ## _index SEPARATOR \ + LOAD_VECTOR_RESTORE(_index) SEPARATOR \ Ldone ## _index: +#else + +#define LOAD_VECTOR_UNALIGNEDl(_index) LOAD_VECTOR_RESTORE(_index) +#define LOAD_VECTOR_UNALIGNEDh(_index) LOAD_VECTOR_RESTORE(_index) + +#endif // !defined(_AIX) LOAD_VECTOR_UNALIGNEDl(0) LOAD_VECTOR_UNALIGNEDl(1) @@ -545,17 +582,17 @@ #endif Lnovec: - lwz %r0, 136(%r3) // __cr - mtcr %r0 - lwz %r0, 148(%r3) // __ctr - mtctr %r0 - lwz %r0, 0(%r3) // __ssr0 - mtctr %r0 - lwz %r0, 8(%r3) // do r0 now - lwz %r5, 28(%r3) // do r5 now - lwz %r4, 24(%r3) // do r4 now - lwz %r1, 12(%r3) // do sp now - lwz %r3, 20(%r3) // do r3 last + lwz GPR(0), 136(GPR(3)) // __cr + mtcr GPR(0) + lwz GPR(0), 148(GPR(3)) // __ctr + mtctr GPR(0) + lwz GPR(0), 0(GPR(3)) // __ssr0 + mtctr GPR(0) + lwz GPR(0), 8(GPR(3)) // do r0 now + lwz GPR(5), 28(GPR(3)) // do r5 now + lwz GPR(4), 24(GPR(3)) // do r4 now + lwz GPR(1), 12(GPR(3)) // do sp now + lwz GPR(3), 20(GPR(3)) // do r3 last bctr #elif defined(__aarch64__) diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -8,7 +8,9 @@ #include "assembly.h" +#if !defined(_AIX) .text +#endif #if !defined(__USING_SJLJ_EXCEPTIONS__) @@ -331,16 +333,19 @@ // On entry: // thread_state pointer is in r3 // +#if defined(_AIX) +DEFINE_LIBUNWIND_FUNCTION_AND_WEAKALIAS(__unw_getcontext, unw_getcontext) +#else DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) - +#endif // store register (GPR) #define PPC64_STR(n) \ - std %r##n, (8 * (n + 2))(%r3) + std GPR(n), (8 * (n + 2))(GPR(3)) // save GPRs PPC64_STR(0) - mflr %r0 - std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0 + mflr GPR(0) + std GPR(0), PPC64_OFFS_SRR0(GPR(3)) // store lr as ssr0 PPC64_STR(1) PPC64_STR(2) PPC64_STR(3) @@ -373,28 +378,28 @@ PPC64_STR(30) PPC64_STR(31) - mfcr %r0 - std %r0, PPC64_OFFS_CR(%r3) - mfxer %r0 - std %r0, PPC64_OFFS_XER(%r3) - mflr %r0 - std %r0, PPC64_OFFS_LR(%r3) - mfctr %r0 - std %r0, PPC64_OFFS_CTR(%r3) - mfvrsave %r0 - std %r0, PPC64_OFFS_VRSAVE(%r3) + mfcr GPR(0) + std GPR(0), PPC64_OFFS_CR(GPR(3)) + mfxer GPR(0) + std GPR(0), PPC64_OFFS_XER(GPR(3)) + mflr GPR(0) + std GPR(0), PPC64_OFFS_LR(GPR(3)) + mfctr GPR(0) + std GPR(0), PPC64_OFFS_CTR(GPR(3)) + mfvrsave GPR(0) + std GPR(0), PPC64_OFFS_VRSAVE(GPR(3)) #if defined(__VSX__) // save VS registers // (note that this also saves floating point registers and V registers, // because part of VS is mapped to these registers) - addi %r4, %r3, PPC64_OFFS_FP + addi GPR(4), GPR(3), PPC64_OFFS_FP // store VS register -#define PPC64_STVS(n) \ - stxvd2x %vs##n, 0, %r4 ;\ - addi %r4, %r4, 16 +#define PPC64_STVS(n) \ + stxvd2x VSR(n), 0, GPR(4) ;\ + addi GPR(4), GPR(4), 16 PPC64_STVS(0) PPC64_STVS(1) @@ -465,7 +470,7 @@ // store FP register #define PPC64_STF(n) \ - stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) + stfd FPR(n), (PPC64_OFFS_FP + n * 16)(GPR(3)) // save float registers PPC64_STF(0) @@ -507,14 +512,14 @@ // Use 16-bytes below the stack pointer as an // aligned buffer to save each vector register. // Note that the stack pointer is always 16-byte aligned. - subi %r4, %r1, 16 + subi GPR(4), GPR(1), 16 -#define PPC64_STV_UNALIGNED(n) \ - stvx %v##n, 0, %r4 ;\ - ld %r5, 0(%r4) ;\ - std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\ - ld %r5, 8(%r4) ;\ - std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3) +#define PPC64_STV_UNALIGNED(n) \ + stvx VR(n), 0, GPR(4) ;\ + ld GPR(5), 0(GPR(4)) ;\ + std GPR(5), (PPC64_OFFS_V + n * 16)(GPR(3)) ;\ + ld GPR(5), 8(GPR(4)) ;\ + std GPR(5), (PPC64_OFFS_V + n * 16 + 8)(GPR(3)) PPC64_STV_UNALIGNED(0) PPC64_STV_UNALIGNED(1) @@ -552,7 +557,7 @@ #endif #endif - li %r3, 0 // return UNW_ESUCCESS + li GPR(3), 0 // return UNW_ESUCCESS blr @@ -564,141 +569,145 @@ // On entry: // thread_state pointer is in r3 // +#if defined(_AIX) +DEFINE_LIBUNWIND_FUNCTION_AND_WEAKALIAS(__unw_getcontext, unw_getcontext) +#else DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) - stw %r0, 8(%r3) - mflr %r0 - stw %r0, 0(%r3) // store lr as ssr0 - stw %r1, 12(%r3) - stw %r2, 16(%r3) - stw %r3, 20(%r3) - stw %r4, 24(%r3) - stw %r5, 28(%r3) - stw %r6, 32(%r3) - stw %r7, 36(%r3) - stw %r8, 40(%r3) - stw %r9, 44(%r3) - stw %r10, 48(%r3) - stw %r11, 52(%r3) - stw %r12, 56(%r3) - stw %r13, 60(%r3) - stw %r14, 64(%r3) - stw %r15, 68(%r3) - stw %r16, 72(%r3) - stw %r17, 76(%r3) - stw %r18, 80(%r3) - stw %r19, 84(%r3) - stw %r20, 88(%r3) - stw %r21, 92(%r3) - stw %r22, 96(%r3) - stw %r23,100(%r3) - stw %r24,104(%r3) - stw %r25,108(%r3) - stw %r26,112(%r3) - stw %r27,116(%r3) - stw %r28,120(%r3) - stw %r29,124(%r3) - stw %r30,128(%r3) - stw %r31,132(%r3) +#endif + stw GPR(0), 8(GPR(3)) + mflr GPR(0) + stw GPR(0), 0(GPR(3)) // store lr as ssr0 + stw GPR(1), 12(GPR(3)) + stw GPR(2), 16(GPR(3)) + stw GPR(3), 20(GPR(3)) + stw GPR(4), 24(GPR(3)) + stw GPR(5), 28(GPR(3)) + stw GPR(6), 32(GPR(3)) + stw GPR(7), 36(GPR(3)) + stw GPR(8), 40(GPR(3)) + stw GPR(9), 44(GPR(3)) + stw GPR(10), 48(GPR(3)) + stw GPR(11), 52(GPR(3)) + stw GPR(12), 56(GPR(3)) + stw GPR(13), 60(GPR(3)) + stw GPR(14), 64(GPR(3)) + stw GPR(15), 68(GPR(3)) + stw GPR(16), 72(GPR(3)) + stw GPR(17), 76(GPR(3)) + stw GPR(18), 80(GPR(3)) + stw GPR(19), 84(GPR(3)) + stw GPR(20), 88(GPR(3)) + stw GPR(21), 92(GPR(3)) + stw GPR(22), 96(GPR(3)) + stw GPR(23),100(GPR(3)) + stw GPR(24),104(GPR(3)) + stw GPR(25),108(GPR(3)) + stw GPR(26),112(GPR(3)) + stw GPR(27),116(GPR(3)) + stw GPR(28),120(GPR(3)) + stw GPR(29),124(GPR(3)) + stw GPR(30),128(GPR(3)) + stw GPR(31),132(GPR(3)) // save VRSave register - mfspr %r0, 256 - stw %r0, 156(%r3) + mfspr GPR(0), 256 + stw GPR(0), 156(GPR(3)) // save CR registers - mfcr %r0 - stw %r0, 136(%r3) + mfcr GPR(0) + stw GPR(0), 136(GPR(3)) // save CTR register - mfctr %r0 - stw %r0, 148(%r3) + mfctr GPR(0) + stw GPR(0), 148(GPR(3)) #if !defined(__NO_FPRS__) // save float registers - stfd %f0, 160(%r3) - stfd %f1, 168(%r3) - stfd %f2, 176(%r3) - stfd %f3, 184(%r3) - stfd %f4, 192(%r3) - stfd %f5, 200(%r3) - stfd %f6, 208(%r3) - stfd %f7, 216(%r3) - stfd %f8, 224(%r3) - stfd %f9, 232(%r3) - stfd %f10,240(%r3) - stfd %f11,248(%r3) - stfd %f12,256(%r3) - stfd %f13,264(%r3) - stfd %f14,272(%r3) - stfd %f15,280(%r3) - stfd %f16,288(%r3) - stfd %f17,296(%r3) - stfd %f18,304(%r3) - stfd %f19,312(%r3) - stfd %f20,320(%r3) - stfd %f21,328(%r3) - stfd %f22,336(%r3) - stfd %f23,344(%r3) - stfd %f24,352(%r3) - stfd %f25,360(%r3) - stfd %f26,368(%r3) - stfd %f27,376(%r3) - stfd %f28,384(%r3) - stfd %f29,392(%r3) - stfd %f30,400(%r3) - stfd %f31,408(%r3) + stfd FPR(0), 160(GPR(3)) + stfd FPR(1), 168(GPR(3)) + stfd FPR(2), 176(GPR(3)) + stfd FPR(3), 184(GPR(3)) + stfd FPR(4), 192(GPR(3)) + stfd FPR(5), 200(GPR(3)) + stfd FPR(6), 208(GPR(3)) + stfd FPR(7), 216(GPR(3)) + stfd FPR(8), 224(GPR(3)) + stfd FPR(9), 232(GPR(3)) + stfd FPR(10),240(GPR(3)) + stfd FPR(11),248(GPR(3)) + stfd FPR(12),256(GPR(3)) + stfd FPR(13),264(GPR(3)) + stfd FPR(14),272(GPR(3)) + stfd FPR(15),280(GPR(3)) + stfd FPR(16),288(GPR(3)) + stfd FPR(17),296(GPR(3)) + stfd FPR(18),304(GPR(3)) + stfd FPR(19),312(GPR(3)) + stfd FPR(20),320(GPR(3)) + stfd FPR(21),328(GPR(3)) + stfd FPR(22),336(GPR(3)) + stfd FPR(23),344(GPR(3)) + stfd FPR(24),352(GPR(3)) + stfd FPR(25),360(GPR(3)) + stfd FPR(26),368(GPR(3)) + stfd FPR(27),376(GPR(3)) + stfd FPR(28),384(GPR(3)) + stfd FPR(29),392(GPR(3)) + stfd FPR(30),400(GPR(3)) + stfd FPR(31),408(GPR(3)) #endif #if defined(__ALTIVEC__) // save vector registers - subi %r4, %r1, 16 - rlwinm %r4, %r4, 0, 0, 27 // mask low 4-bits + subi GPR(4), GPR(1), 16 + rlwinm GPR(4), GPR(4), 0, 0, 27 // mask low 4-bits // r4 is now a 16-byte aligned pointer into the red zone -#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ - stvx _vec, 0, %r4 SEPARATOR \ - lwz %r5, 0(%r4) SEPARATOR \ - stw %r5, _offset(%r3) SEPARATOR \ - lwz %r5, 4(%r4) SEPARATOR \ - stw %r5, _offset+4(%r3) SEPARATOR \ - lwz %r5, 8(%r4) SEPARATOR \ - stw %r5, _offset+8(%r3) SEPARATOR \ - lwz %r5, 12(%r4) SEPARATOR \ - stw %r5, _offset+12(%r3) - - SAVE_VECTOR_UNALIGNED( %v0, 424+0x000) - SAVE_VECTOR_UNALIGNED( %v1, 424+0x010) - SAVE_VECTOR_UNALIGNED( %v2, 424+0x020) - SAVE_VECTOR_UNALIGNED( %v3, 424+0x030) - SAVE_VECTOR_UNALIGNED( %v4, 424+0x040) - SAVE_VECTOR_UNALIGNED( %v5, 424+0x050) - SAVE_VECTOR_UNALIGNED( %v6, 424+0x060) - SAVE_VECTOR_UNALIGNED( %v7, 424+0x070) - SAVE_VECTOR_UNALIGNED( %v8, 424+0x080) - SAVE_VECTOR_UNALIGNED( %v9, 424+0x090) - SAVE_VECTOR_UNALIGNED(%v10, 424+0x0A0) - SAVE_VECTOR_UNALIGNED(%v11, 424+0x0B0) - SAVE_VECTOR_UNALIGNED(%v12, 424+0x0C0) - SAVE_VECTOR_UNALIGNED(%v13, 424+0x0D0) - SAVE_VECTOR_UNALIGNED(%v14, 424+0x0E0) - SAVE_VECTOR_UNALIGNED(%v15, 424+0x0F0) - SAVE_VECTOR_UNALIGNED(%v16, 424+0x100) - SAVE_VECTOR_UNALIGNED(%v17, 424+0x110) - SAVE_VECTOR_UNALIGNED(%v18, 424+0x120) - SAVE_VECTOR_UNALIGNED(%v19, 424+0x130) - SAVE_VECTOR_UNALIGNED(%v20, 424+0x140) - SAVE_VECTOR_UNALIGNED(%v21, 424+0x150) - SAVE_VECTOR_UNALIGNED(%v22, 424+0x160) - SAVE_VECTOR_UNALIGNED(%v23, 424+0x170) - SAVE_VECTOR_UNALIGNED(%v24, 424+0x180) - SAVE_VECTOR_UNALIGNED(%v25, 424+0x190) - SAVE_VECTOR_UNALIGNED(%v26, 424+0x1A0) - SAVE_VECTOR_UNALIGNED(%v27, 424+0x1B0) - SAVE_VECTOR_UNALIGNED(%v28, 424+0x1C0) - SAVE_VECTOR_UNALIGNED(%v29, 424+0x1D0) - SAVE_VECTOR_UNALIGNED(%v30, 424+0x1E0) - SAVE_VECTOR_UNALIGNED(%v31, 424+0x1F0) +#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ + stvx _vec, 0, GPR(4) SEPARATOR \ + lwz GPR(5), 0(GPR(4)) SEPARATOR \ + stw GPR(5), _offset(GPR(3)) SEPARATOR \ + lwz GPR(5), 4(GPR(4)) SEPARATOR \ + stw GPR(5), _offset+4(GPR(3)) SEPARATOR \ + lwz GPR(5), 8(GPR(4)) SEPARATOR \ + stw GPR(5), _offset+8(GPR(3)) SEPARATOR \ + lwz GPR(5), 12(GPR(4)) SEPARATOR \ + stw GPR(5), _offset+12(GPR(3)) + + SAVE_VECTOR_UNALIGNED( VR(0), 424+0x000) + SAVE_VECTOR_UNALIGNED( VR(1), 424+0x010) + SAVE_VECTOR_UNALIGNED( VR(2), 424+0x020) + SAVE_VECTOR_UNALIGNED( VR(3), 424+0x030) + SAVE_VECTOR_UNALIGNED( VR(4), 424+0x040) + SAVE_VECTOR_UNALIGNED( VR(5), 424+0x050) + SAVE_VECTOR_UNALIGNED( VR(6), 424+0x060) + SAVE_VECTOR_UNALIGNED( VR(7), 424+0x070) + SAVE_VECTOR_UNALIGNED( VR(8), 424+0x080) + SAVE_VECTOR_UNALIGNED( VR(9), 424+0x090) + SAVE_VECTOR_UNALIGNED(VR(10), 424+0x0A0) + SAVE_VECTOR_UNALIGNED(VR(11), 424+0x0B0) + SAVE_VECTOR_UNALIGNED(VR(12), 424+0x0C0) + SAVE_VECTOR_UNALIGNED(VR(13), 424+0x0D0) + SAVE_VECTOR_UNALIGNED(VR(14), 424+0x0E0) + SAVE_VECTOR_UNALIGNED(VR(15), 424+0x0F0) + SAVE_VECTOR_UNALIGNED(VR(16), 424+0x100) + SAVE_VECTOR_UNALIGNED(VR(17), 424+0x110) + SAVE_VECTOR_UNALIGNED(VR(18), 424+0x120) + SAVE_VECTOR_UNALIGNED(VR(19), 424+0x130) + SAVE_VECTOR_UNALIGNED(VR(20), 424+0x140) + SAVE_VECTOR_UNALIGNED(VR(21), 424+0x150) + SAVE_VECTOR_UNALIGNED(VR(22), 424+0x160) + SAVE_VECTOR_UNALIGNED(VR(23), 424+0x170) + SAVE_VECTOR_UNALIGNED(VR(24), 424+0x180) + SAVE_VECTOR_UNALIGNED(VR(25), 424+0x190) + SAVE_VECTOR_UNALIGNED(VR(26), 424+0x1A0) + SAVE_VECTOR_UNALIGNED(VR(27), 424+0x1B0) + SAVE_VECTOR_UNALIGNED(VR(28), 424+0x1C0) + SAVE_VECTOR_UNALIGNED(VR(29), 424+0x1D0) + SAVE_VECTOR_UNALIGNED(VR(30), 424+0x1E0) + SAVE_VECTOR_UNALIGNED(VR(31), 424+0x1F0) #endif - li %r3, 0 // return UNW_ESUCCESS + li GPR(3), 0 // return UNW_ESUCCESS blr diff --git a/libunwind/src/Unwind_AIXExtras.cpp b/libunwind/src/Unwind_AIXExtras.cpp new file mode 100644 --- /dev/null +++ b/libunwind/src/Unwind_AIXExtras.cpp @@ -0,0 +1,62 @@ +//===--------------------- Unwind_AIXExtras.cpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +//===----------------------------------------------------------------------===// + +// This file is only used for AIX. +#if defined(_AIX) + +#include "config.h" +#include "libunwind_ext.h" +#include + +namespace libunwind { +// getFuncName +// Get the function name from its traceback table. +char *getFuncName(uintptr_t Pc, uint16_t &NameLen, unw_word_t *Offset) { + uint32_t *p = (uint32_t *)Pc; + *Offset = 0; + + // Keep looking forward until a word of 0 is found. The traceback + // table starts at the following word. + while (*p) + p++; + tbtable *TBTable = (tbtable *)(p + 1); + + // Get to the name of the function. + if (TBTable->tb.name_present) { + p = (uint32_t *)&TBTable->tb_ext; + + // Skip field parminfo if it exists. + if (TBTable->tb.fixedparms || TBTable->tb.floatparms) + p++; + + // If the tb_offset field exisits, get the offset from the start of + // the function to pc. Skip the field. + if (TBTable->tb.has_tboff) { + unw_word_t StartIp = (uintptr_t)TBTable - *p - sizeof(uint32_t); + *Offset = Pc - StartIp; + p++; + } + + // Skip field hand_mask if it exists. + if (TBTable->tb.int_hndl) + p++; + + // Skip fields ctl_info and ctl_info_disp if they exist. + if (TBTable->tb.has_ctl) { + p += 1 + *p; + } + + NameLen = *((uint16_t *)p); + return (char *)p + sizeof(uint16_t); + } else { + return NULL; + } +} +} // namespace libunwind +#endif // defined(_AIX) diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h --- a/libunwind/src/assembly.h +++ b/libunwind/src/assembly.h @@ -185,12 +185,48 @@ #elif defined(__sparc__) +#elif defined(_AIX) + +#if defined(__powerpc64__) +#define PPC_RELOC_EXPR_LENGTH .llong +#elif defined(__ppc__) +#define PPC_RELOC_EXPR_LENGTH .long +#endif + +#define DEFINE_LIBUNWIND_FUNCTION_AND_WEAKALIAS(name, aliasname) \ + .toc SEPARATOR \ + .globl name SEPARATOR \ + .globl .name SEPARATOR \ + .csect name[DS] SEPARATOR \ +name: \ + .weak aliasname[DS] SEPARATOR \ + .weak .aliasname SEPARATOR \ +aliasname: \ + PPC_RELOC_EXPR_LENGTH .name, TOC[tc0], 0 SEPARATOR \ + .csect .text[PR] SEPARATOR \ +.name: \ +.aliasname: + +#define WEAK_ALIAS(name, aliasname) +#define NO_EXEC_STACK_DIRECTIVE + #else #error Unsupported target #endif +#if defined(_AIX) +#define DEFINE_LIBUNWIND_FUNCTION(name) \ + .toc SEPARATOR \ + .globl name SEPARATOR \ + .globl .name SEPARATOR \ + .csect name[DS] SEPARATOR \ +name: \ + PPC_RELOC_EXPR_LENGTH .name, TOC[tc0], 0 SEPARATOR \ + .csect .text[PR] SEPARATOR \ +.name: +#else #define DEFINE_LIBUNWIND_FUNCTION(name) \ .globl SYMBOL_NAME(name) SEPARATOR \ HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ @@ -199,6 +235,7 @@ SYMBOL_NAME(name): \ PPC64_OPD2 \ AARCH64_BTI +#endif #if defined(__arm__) #if !defined(__ARM_ARCH) @@ -216,4 +253,20 @@ #endif #endif /* __arm__ */ +#if defined(__ppc__) || defined(__powerpc64__) +#if defined(_AIX) +#define GPR(num) num +#define FPR(num) num +#define VSR(num) num +#define VR(num) num +#define PPC_SHIFT(index) <(index) +#else +#define GPR(num) %r##num +#define FPR(num) %f##num +#define VSR(num) %vs##num +#define VR(num) %v##num +#define PPC_SHIFT(index) <<(index) +#endif +#endif + #endif /* UNWIND_ASSEMBLY_H */ diff --git a/libunwind/src/config.h b/libunwind/src/config.h --- a/libunwind/src/config.h +++ b/libunwind/src/config.h @@ -43,6 +43,9 @@ // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster. #define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1 +#elif defined(_AIX) +// The traceback table at the end of each function is used for unwinding. +#define _LIBUNWIND_SUPPORT_TBTAB_UNWIND 1 #else // Assume an ELF system with a dl_iterate_phdr function. #define _LIBUNWIND_USE_DL_ITERATE_PHDR 1 @@ -57,13 +60,13 @@ #define _LIBUNWIND_EXPORT #define _LIBUNWIND_HIDDEN #else - #if !defined(__ELF__) && !defined(__MACH__) - #define _LIBUNWIND_EXPORT __declspec(dllexport) - #define _LIBUNWIND_HIDDEN - #else - #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) - #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) - #endif +#if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX) +#define _LIBUNWIND_EXPORT __declspec(dllexport) +#define _LIBUNWIND_HIDDEN +#else +#define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) +#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) +#endif #endif #define STR(a) #a @@ -80,7 +83,7 @@ __asm__(".globl " SYMBOL_NAME(aliasname)); \ __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \ _LIBUNWIND_ALIAS_VISIBILITY(SYMBOL_NAME(aliasname)); -#elif defined(__ELF__) +#elif defined(__ELF__) || defined(_AIX) #define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ __attribute__((weak, alias(#name))); diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -232,6 +232,16 @@ } _LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame) +#ifdef _AIX +_LIBUNWIND_EXPORT uintptr_t __unw_get_data_rel_base(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("unw_get_data_rel_base(cursor=%p)", + static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->getDataRelBase(); +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_data_rel_base, unw_get_data_rel_base) +#endif + #ifdef __arm__ // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD _LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) { diff --git a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h --- a/libunwind/src/libunwind_ext.h +++ b/libunwind/src/libunwind_ext.h @@ -43,6 +43,10 @@ extern int __unw_is_signal_frame(unw_cursor_t *); extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *); +#if defined(_AIX) +extern uintptr_t __unw_get_data_rel_base(unw_cursor_t *); +#endif + // SPI extern void __unw_iterate_dwarf_unwind_cache(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));