+++ /dev/null
-function(find_compiler_rt_library name dest)
- if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
- message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
- endif()
- set(dest "" PARENT_SCOPE)
- set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
- "--rtlib=compiler-rt" "--print-libgcc-file-name")
- if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
- list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
- endif()
- get_property(LIBUNWIND_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
- string(REPLACE " " ";" LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}")
- list(APPEND CLANG_COMMAND ${LIBUNWIND_CXX_FLAGS})
- execute_process(
- COMMAND ${CLANG_COMMAND}
- RESULT_VARIABLE HAD_ERROR
- OUTPUT_VARIABLE LIBRARY_FILE
- )
- string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
- file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
- string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
- if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
- message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}")
- set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE)
- else()
- message(STATUS "Failed to find compiler-rt library")
- endif()
-endfunction()
-
-function(find_compiler_rt_dir dest)
- if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
- message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
- endif()
- set(dest "" PARENT_SCOPE)
- if (APPLE)
- set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
- "-print-file-name=lib")
- execute_process(
- COMMAND ${CLANG_COMMAND}
- RESULT_VARIABLE HAD_ERROR
- OUTPUT_VARIABLE LIBRARY_DIR
- )
- string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR)
- file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR)
- set(LIBRARY_DIR "${LIBRARY_DIR}/darwin")
- else()
- set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
- "--rtlib=compiler-rt" "--print-libgcc-file-name")
- execute_process(
- COMMAND ${CLANG_COMMAND}
- RESULT_VARIABLE HAD_ERROR
- OUTPUT_VARIABLE LIBRARY_FILE
- )
- string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
- file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
- get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY)
- endif()
- if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}")
- message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}")
- set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE)
- else()
- message(STATUS "Failed to find compiler-rt directory")
- endif()
-endfunction()
-//===------------------------- __libunwind_config.h -----------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#ifndef ____LIBUNWIND_CONFIG_H__
#define ____LIBUNWIND_CONFIG_H__
+#define _LIBUNWIND_VERSION 15000
+
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
- !defined(__ARM_DWARF_EH__)
+ !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
#define _LIBUNWIND_ARM_EHABI
#endif
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
-#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64 32
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64 31
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON 34
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE 143
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X 83
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH 64
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__linux__)
# define _LIBUNWIND_CONTEXT_SIZE 167
# define _LIBUNWIND_CURSOR_SIZE 179
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64
-# elif defined(__ppc__)
+# elif defined(__powerpc__)
# define _LIBUNWIND_TARGET_PPC 1
# define _LIBUNWIND_CONTEXT_SIZE 117
# define _LIBUNWIND_CURSOR_SIZE 124
# error "Unsupported MIPS ABI and/or environment"
# endif
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
-# elif defined(__sparc__) && defined(__arch64__)
-# define _LIBUNWIND_TARGET_SPARC64 1
-# define _LIBUNWIND_CONTEXT_SIZE 33
-# define _LIBUNWIND_CURSOR_SIZE 45
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64
+#elif defined(__sparc__) && defined(__arch64__)
+#define _LIBUNWIND_TARGET_SPARC64 1
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER \
+ _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64
+#define _LIBUNWIND_CONTEXT_SIZE 33
+#define _LIBUNWIND_CURSOR_SIZE 45
# elif defined(__sparc__)
#define _LIBUNWIND_TARGET_SPARC 1
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
# define _LIBUNWIND_CONTEXT_SIZE 67
# define _LIBUNWIND_CURSOR_SIZE 79
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE
+# elif defined(__s390x__)
+# define _LIBUNWIND_TARGET_S390X 1
+# define _LIBUNWIND_CONTEXT_SIZE 34
+# define _LIBUNWIND_CURSOR_SIZE 46
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X
+#elif defined(__loongarch__)
+#define _LIBUNWIND_TARGET_LOONGARCH 1
+#if __loongarch_grlen == 64
+#define _LIBUNWIND_CONTEXT_SIZE 65
+#define _LIBUNWIND_CURSOR_SIZE 77
+#else
+#error "Unsupported LoongArch ABI"
+#endif
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER \
+ _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH
# else
# error "Unsupported architecture."
# endif
# define _LIBUNWIND_TARGET_HEXAGON 1
# define _LIBUNWIND_TARGET_RISCV 1
# define _LIBUNWIND_TARGET_VE 1
+# define _LIBUNWIND_TARGET_S390X 1
+#define _LIBUNWIND_TARGET_LOONGARCH 1
# define _LIBUNWIND_CONTEXT_SIZE 167
# define _LIBUNWIND_CURSOR_SIZE 179
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
-//===------------------------- AddressSpace.hpp ---------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#include "Registers.hpp"
#ifndef _LIBUNWIND_USE_DLADDR
- #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
+ #if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX))
#define _LIBUNWIND_USE_DLADDR 1
#else
#define _LIBUNWIND_USE_DLADDR 0
};
#endif
+#if defined(_AIX)
+namespace libunwind {
+char *getFuncNameFromTBTable(uintptr_t pc, uint16_t &NameLen,
+ unw_word_t *offset);
+}
+#endif
+
#ifdef __APPLE__
struct dyld_unwind_sections
uintptr_t dso_base;
#endif
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
- uintptr_t text_segment_length;
+ size_t text_segment_length;
#endif
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
uintptr_t dwarf_section;
- uintptr_t dwarf_section_length;
+ size_t dwarf_section_length;
#endif
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
uintptr_t dwarf_index_section;
- uintptr_t dwarf_index_section_length;
+ size_t dwarf_index_section_length;
#endif
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
uintptr_t compact_unwind_section;
- uintptr_t compact_unwind_section_length;
+ size_t compact_unwind_section_length;
#endif
#if defined(_LIBUNWIND_ARM_EHABI)
uintptr_t arm_section;
- uintptr_t arm_section_length;
+ size_t arm_section_length;
#endif
};
inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
const uint8_t *p = (uint8_t *)addr;
const uint8_t *pend = (uint8_t *)end;
- int64_t result = 0;
+ uint64_t result = 0;
int bit = 0;
uint8_t byte;
do {
if ((byte & 0x40) != 0 && bit < 64)
result |= (-1ULL) << bit;
addr = (pint_t) p;
- return result;
+ return (int64_t)result;
}
inline LocalAddressSpace::pint_t
typedef ElfW(Addr) Elf_Addr;
#endif
-static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
- Elf_Addr image_base = pinfo->dlpi_addr;
-#if defined(__ANDROID__) && __ANDROID_API__ < 18
- if (image_base == 0) {
- // Normally, an image base of 0 indicates a non-PIE executable. On
- // versions of Android prior to API 18, the dynamic linker reported a
- // dlpi_addr of 0 for PIE executables. Compute the true image base
- // using the PT_PHDR segment.
- // See https://github.com/android/ndk/issues/505.
- for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
- const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
- if (phdr->p_type == PT_PHDR) {
- image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
- phdr->p_vaddr;
- break;
- }
- }
- }
-#endif
- return image_base;
-}
-
struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
LocalAddressSpace *addressSpace;
UnwindInfoSections *sects;
// .eh_frame_hdr records the start of .eh_frame, but not its size.
// Rely on a zero terminator to find the end of the section.
cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
- cbdata->sects->dwarf_section_length = UINTPTR_MAX;
+ cbdata->sects->dwarf_section_length = SIZE_MAX;
return true;
}
}
(void)pinfo_size;
#endif
- Elf_Addr image_base = calculateImageBase(pinfo);
+ Elf_Addr image_base = pinfo->dlpi_addr;
// Most shared objects seen in this callback function likely don't contain the
// target address, so optimize for that. Scan for a matching PT_LOAD segment
info.dso_base = (uintptr_t)dyldInfo.mh;
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
- info.dwarf_section_length = dyldInfo.dwarf_section_length;
+ info.dwarf_section_length = (size_t)dyldInfo.dwarf_section_length;
#endif
info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
- info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
+ info.compact_unwind_section_length = (size_t)dyldInfo.compact_unwind_section_length;
return true;
}
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
info.dso_base = 0;
// Bare metal is statically linked, so no need to ask the dynamic loader
- info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
+ info.dwarf_section_length = (size_t)(&__eh_frame_end - &__eh_frame_start);
info.dwarf_section = (uintptr_t)(&__eh_frame_start);
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
(void *)info.dwarf_section, (void *)info.dwarf_section_length);
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
- info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
+ info.dwarf_index_section_length = (size_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
(void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
#endif
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
// Bare metal is statically linked, so no need to ask the dynamic loader
info.arm_section = (uintptr_t)(&__exidx_start);
- info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
+ info.arm_section_length = (size_t)(&__exidx_end - &__exidx_start);
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
(void *)info.arm_section, (void *)info.arm_section_length);
if (info.arm_section && info.arm_section_length)
DWORD err = GetLastError();
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
"returned error %d", (int)err);
+ (void)err;
return false;
}
(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 =
(uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
- info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
+ info.arm_section_length = (size_t)length * sizeof(EHABIIndexEntry);
if (info.arm_section && info.arm_section_length)
return true;
#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+ // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
+ // `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
+ // support for _dl_find_object on other unwind formats is not implemented,
+ // yet.
+#if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+ // We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
+#if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
+#error _dl_find_object retrieves an unexpected section type
+#endif
+ // We look-up `dl_find_object` dynamically at runtime to ensure backwards
+ // compatibility with earlier version of glibc not yet providing it. On older
+ // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
+ // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
+ static decltype(_dl_find_object) *dlFindObject;
+ static bool dlFindObjectChecked = false;
+ if (!dlFindObjectChecked) {
+ dlFindObject = reinterpret_cast<decltype(_dl_find_object) *>(
+ dlsym(RTLD_DEFAULT, "_dl_find_object"));
+ dlFindObjectChecked = true;
+ }
+ // Try to find the unwind info using `dl_find_object`
+ dl_find_object findResult;
+ if (dlFindObject && dlFindObject((void *)targetAddr, &findResult) == 0) {
+ if (findResult.dlfo_eh_frame == nullptr) {
+ // Found an entry for `targetAddr`, but there is no unwind info.
+ return false;
+ }
+ info.dso_base = reinterpret_cast<uintptr_t>(findResult.dlfo_map_start);
+ info.text_segment_length = static_cast<size_t>(
+ (char *)findResult.dlfo_map_end - (char *)findResult.dlfo_map_start);
+
+ // Record the start of PT_GNU_EH_FRAME.
+ info.dwarf_index_section =
+ reinterpret_cast<uintptr_t>(findResult.dlfo_eh_frame);
+ // `_dl_find_object` does not give us the size of PT_GNU_EH_FRAME.
+ // Setting length to `SIZE_MAX` effectively disables all range checks.
+ info.dwarf_index_section_length = SIZE_MAX;
+ EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
+ if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
+ *this, info.dwarf_index_section, info.dwarf_index_section_length,
+ hdrInfo)) {
+ return false;
+ }
+ // Record the start of the FDE and use SIZE_MAX to indicate that we do
+ // not know the end address.
+ info.dwarf_section = hdrInfo.eh_frame_ptr;
+ info.dwarf_section_length = SIZE_MAX;
+ return true;
+ }
+#endif
dl_iterate_cb_data cb_data = {this, &info, targetAddr};
int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
return static_cast<bool>(found);
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;
return true;
}
}
+#elif defined(_AIX)
+ uint16_t nameLen;
+ char *funcName = getFuncNameFromTBTable(addr, nameLen, offset);
+ if (funcName != NULL) {
+ snprintf(buf, bufLen, "%.*s", nameLen, funcName);
+ return true;
+ }
#else
(void)addr;
(void)buf;
-//===-------------------------- DwarfInstructions.hpp ---------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#include <stdio.h>
#include <stdlib.h>
-#include "dwarf2.h"
-#include "Registers.hpp"
#include "DwarfParser.hpp"
+#include "Registers.hpp"
#include "config.h"
+#include "dwarf2.h"
+#include "libunwind_ext.h"
namespace libunwind {
-/// DwarfInstructions maps abtract DWARF unwind instructions to a particular
+/// DwarfInstructions maps abstract DWARF unwind instructions to a particular
/// architecture
template <typename A, typename R>
class DwarfInstructions {
typedef typename A::sint_t sint_t;
static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
- R ®isters, bool &isSignalFrame);
+ R ®isters, bool &isSignalFrame, bool stage2);
private:
assert(0 && "getCFA(): unknown location");
__builtin_unreachable();
}
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
+ PrologInfo &prolog);
+#endif
};
+template <typename R>
+auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) {
+ return r.getWCookie();
+}
+template <typename R> uint64_t getSparcWCookie(const R &, long) {
+ return 0;
+}
template <typename A, typename R>
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
case CFI_Parser<A>::kRegisterInCFA:
return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
- case CFI_Parser<A>::kRegisterInCFADecrypt:
- return addressSpace.getP(
- cfa + (pint_t)savedReg.value) ^ registers.getWCookie();
+ case CFI_Parser<A>::kRegisterInCFADecrypt: // sparc64 specific
+ return (pint_t)(addressSpace.getP(cfa + (pint_t)savedReg.value) ^
+ getSparcWCookie(registers, 0));
case CFI_Parser<A>::kRegisterAtExpression:
return (pint_t)addressSpace.getRegister(evaluateExpression(
return addressSpace.getDouble(
evaluateExpression((pint_t)savedReg.value, addressSpace,
registers, cfa));
-
+ case CFI_Parser<A>::kRegisterUndefined:
+ return 0.0;
+ case CFI_Parser<A>::kRegisterInRegister:
+#ifndef _LIBUNWIND_TARGET_ARM
+ return registers.getFloatRegister((int)savedReg.value);
+#endif
case CFI_Parser<A>::kRegisterIsExpression:
case CFI_Parser<A>::kRegisterUnused:
- case CFI_Parser<A>::kRegisterUndefined:
case CFI_Parser<A>::kRegisterOffsetFromCFA:
- case CFI_Parser<A>::kRegisterInRegister:
case CFI_Parser<A>::kRegisterInCFADecrypt:
// FIX ME
break;
}
_LIBUNWIND_ABORT("unsupported restore location for vector register");
}
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
+ pint_t cfa, PrologInfo &prolog) {
+ pint_t raSignState;
+ auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
+ if (regloc.location == CFI_Parser<A>::kRegisterUnused)
+ raSignState = static_cast<pint_t>(regloc.value);
+ else
+ raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
+
+ // Only bit[0] is meaningful.
+ return raSignState & 0x01;
+}
+#endif
template <typename A, typename R>
int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
pint_t fdeStart, R ®isters,
- bool &isSignalFrame) {
+ bool &isSignalFrame, bool stage2) {
FDE_Info fdeInfo;
CIE_Info cieInfo;
if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
// get pointer to cfa (architecture specific)
pint_t cfa = getCFA(addressSpace, prolog, registers);
- // restore registers that DWARF says were saved
+ (void)stage2;
+ // __unw_step_stage2 is not used for cross unwinding, so we use
+ // __aarch64__ rather than LIBUNWIND_TARGET_AARCH64 to make sure we are
+ // building for AArch64 natively.
+#if defined(__aarch64__)
+ if (stage2 && cieInfo.mteTaggedFrame) {
+ pint_t sp = registers.getSP();
+ pint_t p = sp;
+ // AArch64 doesn't require the value of SP to be 16-byte aligned at
+ // all times, only at memory accesses and public interfaces [1]. Thus,
+ // a signal could arrive at a point where SP is not aligned properly.
+ // In that case, the kernel fixes up [2] the signal frame, but we
+ // still have a misaligned SP in the previous frame. If that signal
+ // handler caused stack unwinding, we would have an unaligned SP.
+ // We do not need to fix up the CFA, as that is the SP at a "public
+ // interface".
+ // [1]:
+ // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#622the-stack
+ // [2]:
+ // https://github.com/torvalds/linux/blob/1930a6e739c4b4a654a69164dbe39e554d228915/arch/arm64/kernel/signal.c#L718
+ p &= ~0xfULL;
+ // CFA is the bottom of the current stack frame.
+ for (; p < cfa; p += 16) {
+ __asm__ __volatile__(".arch armv8.5-a\n"
+ ".arch_extension memtag\n"
+ "stg %[Ptr], [%[Ptr]]\n"
+ :
+ : [Ptr] "r"(p)
+ : "memory");
+ }
+ }
+#endif
+ // restore registers that DWARF says were saved
R newRegisters = registers;
// Typically, the CFA is the stack pointer at the call site in
newRegisters.setSP(cfa);
pint_t returnAddress = 0;
- const int lastReg = R::lastDwarfRegNum();
- assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
- "register range too large");
+ constexpr int lastReg = R::lastDwarfRegNum();
+ static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
+ lastReg,
+ "register range too large");
assert(lastReg >= (int)cieInfo.returnAddressRegister &&
"register range does not contain return address register");
for (int i = 0; i <= lastReg; ++i) {
return UNW_EBADREG;
} else if (i == (int)cieInfo.returnAddressRegister) {
// Leaf function keeps the return address in register and there is no
- // explicit intructions how to restore it.
+ // explicit instructions how to restore it.
returnAddress = registers.getRegister(cieInfo.returnAddressRegister);
}
}
// restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures.
if ((R::getArch() == REGISTERS_ARM64) &&
- prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value &&
+ getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
returnAddress != 0) {
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING;
}
#endif
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY) && defined(_LIBUNWIND_TARGET_ARM) && \
+ defined(__ARM_FEATURE_PAUTH)
+ if ((R::getArch() == REGISTERS_ARM) &&
+ prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE].value) {
+ pint_t pac =
+ getSavedRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE]);
+ __asm__ __volatile__("autg %0, %1, %2"
+ :
+ : "r"(pac), "r"(returnAddress), "r"(cfa)
+ :);
+ }
+#endif
+
#if defined(_LIBUNWIND_TARGET_SPARC)
if (R::getArch() == REGISTERS_SPARC) {
// Skip call site instruction and delay slot
}
#endif
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+ // Skip call site instruction and delay slot.
+ if (R::getArch() == REGISTERS_SPARC64)
+ returnAddress += 8;
+#endif
+
#if defined(_LIBUNWIND_TARGET_PPC64)
#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
#define PPC64_ELFV1_R2_OFFSET 40
#endif
// Return address is address after call site instruction, so setting IP to
- // that does simualates a return.
+ // that does simulates a return.
newRegisters.setIP(returnAddress);
// Simulate the step by replacing the register set with the new ones.
svalue = (sint_t)*sp;
*sp = (pint_t)(svalue >> value);
if (log)
- fprintf(stderr, "shift left arithmetric\n");
+ fprintf(stderr, "shift left arithmetic\n");
break;
case DW_OP_xor:
-//===--------------------------- DwarfParser.hpp --------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
uint8_t returnAddressRegister;
#if defined(_LIBUNWIND_TARGET_AARCH64)
bool addressesSignedWithBKey;
+ bool mteTaggedFrame;
#endif
};
kRegisterUnused,
kRegisterUndefined,
kRegisterInCFA,
- kRegisterInCFADecrypt,
+ kRegisterInCFADecrypt, // sparc64 specific
kRegisterOffsetFromCFA,
kRegisterInRegister,
kRegisterAtExpression,
};
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
- uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+ size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
CIE_Info *cieInfo);
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
- FDE_Info *fdeInfo, CIE_Info *cieInfo);
+ FDE_Info *fdeInfo, CIE_Info *cieInfo,
+ bool useCIEInfo = false);
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
int arch, PrologInfo *results);
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
};
-/// Parse a FDE into a CIE_Info and an FDE_Info
+/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is
+/// true, treat cieInfo as already-parsed CIE_Info (whose start offset
+/// must match the one specified by the FDE) rather than parsing the
+/// one indicated within the FDE.
template <typename A>
const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
- FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+ FDE_Info *fdeInfo, CIE_Info *cieInfo,
+ bool useCIEInfo) {
pint_t p = fdeStart;
pint_t cfiLength = (pint_t)addressSpace.get32(p);
p += 4;
return "FDE is really a CIE"; // this is a CIE not an FDE
pint_t nextCFI = p + cfiLength;
pint_t cieStart = p - ciePointer;
- const char *err = parseCIE(addressSpace, cieStart, cieInfo);
- if (err != NULL)
- return err;
+ if (useCIEInfo) {
+ if (cieInfo->cieStart != cieStart)
+ return "CIE start does not match";
+ } else {
+ const char *err = parseCIE(addressSpace, cieStart, cieInfo);
+ if (err != NULL)
+ return err;
+ }
p += 4;
// Parse pc begin and range.
pint_t pcStart =
/// Scan an eh_frame section to find an FDE for a pc
template <typename A>
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
- uintptr_t sectionLength, pint_t fdeHint,
+ size_t sectionLength, pint_t fdeHint,
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
- const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
+ const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
? static_cast<pint_t>(-1)
: (ehSectionStart + sectionLength);
while (p < ehSectionEnd) {
cieInfo->fdesHaveAugmentationData = false;
#if defined(_LIBUNWIND_TARGET_AARCH64)
cieInfo->addressesSignedWithBKey = false;
+ cieInfo->mteTaggedFrame = false;
#endif
cieInfo->cieStart = cie;
pint_t p = cie;
while (addressSpace.get8(p) != 0)
++p;
++p;
- // parse code aligment factor
+ // parse code alignment factor
cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
// parse data alignment factor
cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
case 'B':
cieInfo->addressesSignedWithBKey = true;
break;
+ case 'G':
+ cieInfo->mteTaggedFrame = true;
+ break;
#endif
default:
// ignore unknown letters
}
-/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
+/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
template <typename A>
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
const FDE_Info &fdeInfo,
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
break;
-#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) \
- || defined(_LIBUNWIND_TARGET_SPARC64)
+#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
+ defined(_LIBUNWIND_TARGET_SPARC64)
// The same constant is used to represent different instructions on
// AArch64 (negate_ra_state) and SPARC (window_save).
static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
#if defined(_LIBUNWIND_TARGET_AARCH64)
case REGISTERS_ARM64: {
int64_t value =
- results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1;
- results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value,
+ results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;
+ results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
initialState);
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
} break;
#endif
-#if defined(_LIBUNWIND_TARGET_SPARC64)
- case REGISTERS_SPARC64:
- // Hardcodes windowed registers for SPARC
- for (reg = 16; reg < 32; reg++) {
- if (reg == 31)
- results->savedRegisters[reg].location = kRegisterInCFADecrypt;
- else
- results->savedRegisters[reg].location = kRegisterInCFA;
- results->savedRegisters[reg].value = (reg - 16) * sizeof(pint_t);
- }
- _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save");
- break;
-#endif
-
#if defined(_LIBUNWIND_TARGET_SPARC)
// case DW_CFA_GNU_window_save:
case REGISTERS_SPARC:
}
break;
#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+ // case DW_CFA_GNU_window_save:
+ case REGISTERS_SPARC64:
+ // Don't save %o0-%o7 on sparc64.
+ // https://reviews.llvm.org/D32450#736405
+
+ for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+ if (reg == UNW_SPARC_I7)
+ results->setRegister(
+ reg, kRegisterInCFADecrypt,
+ static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
+ initialState);
+ else
+ results->setRegister(
+ reg, kRegisterInCFA,
+ static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
+ initialState);
+ }
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
+ break;
+#endif
}
break;
+
#else
(void)arch;
#endif
-//===------------------------- EHHeaderParser.hpp -------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
pint_t p = ehHdrStart;
uint8_t version = addressSpace.get8(p++);
if (version != 1) {
- _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
+ _LIBUNWIND_LOG("unsupported .eh_frame_hdr version: %" PRIu8 " at %" PRIx64,
+ version, static_cast<uint64_t>(ehHdrStart));
return false;
}
if (tableEnc == DW_EH_PE_omit) {
return 0;
}
-
switch (tableEnc & 0x0f) {
case DW_EH_PE_sdata2:
case DW_EH_PE_udata2:
-//===----------------------------- Registers.hpp --------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#include <stdint.h>
#include <string.h>
-#include "libunwind.h"
+#include "cet_unwind.h"
#include "config.h"
+#include "libunwind.h"
namespace libunwind {
REGISTERS_HEXAGON,
REGISTERS_RISCV,
REGISTERS_VE,
+ REGISTERS_S390X,
+ REGISTERS_LOONGARCH,
};
#if defined(_LIBUNWIND_TARGET_I386)
class _LIBUNWIND_HIDDEN Registers_x86;
extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
+
+#if defined(_LIBUNWIND_USE_CET)
+extern "C" void *__libunwind_cet_get_jump_target() {
+ return reinterpret_cast<void *>(&__libunwind_Registers_x86_jumpto);
+}
+#endif
+
/// Registers_x86 holds the register state of a thread in a 32-bit intel
/// process.
class _LIBUNWIND_HIDDEN Registers_x86 {
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto() { __libunwind_Registers_x86_jumpto(this); }
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86;
+ }
static int getArch() { return REGISTERS_X86; }
uint32_t getSP() const { return _registers.__esp; }
void setESI(uint32_t value) { _registers.__esi = value; }
uint32_t getEDI() const { return _registers.__edi; }
void setEDI(uint32_t value) { _registers.__edi = value; }
- uint32_t getWCookie() const { return 0; }
private:
struct GPRs {
/// process.
class _LIBUNWIND_HIDDEN Registers_x86_64;
extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
+
+#if defined(_LIBUNWIND_USE_CET)
+extern "C" void *__libunwind_cet_get_jump_target() {
+ return reinterpret_cast<void *>(&__libunwind_Registers_x86_64_jumpto);
+}
+#endif
+
class _LIBUNWIND_HIDDEN Registers_x86_64 {
public:
Registers_x86_64();
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto() { __libunwind_Registers_x86_64_jumpto(this); }
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64;
+ }
static int getArch() { return REGISTERS_X86_64; }
uint64_t getSP() const { return _registers.__rsp; }
void setR14(uint64_t value) { _registers.__r14 = value; }
uint64_t getR15() const { return _registers.__r15; }
void setR15(uint64_t value) { _registers.__r15 = value; }
- uint64_t getWCookie() const { return 0; }
private:
struct GPRs {
return true;
if (regNum < 0)
return false;
- if (regNum > 15)
+ if (regNum > 16)
return false;
return true;
}
inline uint64_t Registers_x86_64::getRegister(int regNum) const {
switch (regNum) {
case UNW_REG_IP:
+ case UNW_X86_64_RIP:
return _registers.__rip;
case UNW_REG_SP:
return _registers.__rsp;
inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
switch (regNum) {
case UNW_REG_IP:
+ case UNW_X86_64_RIP:
_registers.__rip = value;
return;
case UNW_REG_SP:
inline const char *Registers_x86_64::getRegisterName(int regNum) {
switch (regNum) {
case UNW_REG_IP:
+ case UNW_X86_64_RIP:
return "rip";
case UNW_REG_SP:
return "rsp";
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC;
+ }
static int getArch() { return REGISTERS_PPC; }
uint64_t getSP() const { return _registers.__r1; }
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 getWCookie() const { return 0; }
+ uint64_t getCR() const { return _registers.__cr; }
+ void setCR(uint32_t value) { _registers.__cr = value; }
private:
struct ppc_thread_state_t {
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64;
+ }
static int getArch() { return REGISTERS_PPC64; }
uint64_t getSP() const { return _registers.__r1; }
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 getWCookie() const { return 0; }
+ uint64_t getCR() const { return _registers.__cr; }
+ void setCR(uint64_t value) { _registers.__cr = value; }
private:
struct ppc64_thread_state_t {
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto() { __libunwind_Registers_arm64_jumpto(this); }
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64;
+ }
static int getArch() { return REGISTERS_ARM64; }
uint64_t getSP() const { return _registers.__sp; }
void setIP(uint64_t value) { _registers.__pc = value; }
uint64_t getFP() const { return _registers.__fp; }
void setFP(uint64_t value) { _registers.__fp = value; }
- uint64_t getWCookie() const { return 0; }
private:
struct GPRs {
return false;
if (regNum > 95)
return false;
- if (regNum == UNW_ARM64_RA_SIGN_STATE)
+ if (regNum == UNW_AARCH64_RA_SIGN_STATE)
return true;
if ((regNum > 32) && (regNum < 64))
return false;
}
inline uint64_t Registers_arm64::getRegister(int regNum) const {
- if (regNum == UNW_REG_IP || regNum == UNW_ARM64_PC)
+ if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
return _registers.__pc;
- if (regNum == UNW_REG_SP || regNum == UNW_ARM64_SP)
+ if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
return _registers.__sp;
- if (regNum == UNW_ARM64_RA_SIGN_STATE)
+ if (regNum == UNW_AARCH64_RA_SIGN_STATE)
return _registers.__ra_sign_state;
- if (regNum == UNW_ARM64_FP)
+ if (regNum == UNW_AARCH64_FP)
return _registers.__fp;
- if (regNum == UNW_ARM64_LR)
+ if (regNum == UNW_AARCH64_LR)
return _registers.__lr;
if ((regNum >= 0) && (regNum < 29))
return _registers.__x[regNum];
}
inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
- if (regNum == UNW_REG_IP || regNum == UNW_ARM64_PC)
+ if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
_registers.__pc = value;
- else if (regNum == UNW_REG_SP || regNum == UNW_ARM64_SP)
+ else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
_registers.__sp = value;
- else if (regNum == UNW_ARM64_RA_SIGN_STATE)
+ else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
_registers.__ra_sign_state = value;
- else if (regNum == UNW_ARM64_FP)
+ else if (regNum == UNW_AARCH64_FP)
_registers.__fp = value;
- else if (regNum == UNW_ARM64_LR)
+ else if (regNum == UNW_AARCH64_LR)
_registers.__lr = value;
else if ((regNum >= 0) && (regNum < 29))
_registers.__x[regNum] = value;
return "pc";
case UNW_REG_SP:
return "sp";
- case UNW_ARM64_X0:
+ case UNW_AARCH64_X0:
return "x0";
- case UNW_ARM64_X1:
+ case UNW_AARCH64_X1:
return "x1";
- case UNW_ARM64_X2:
+ case UNW_AARCH64_X2:
return "x2";
- case UNW_ARM64_X3:
+ case UNW_AARCH64_X3:
return "x3";
- case UNW_ARM64_X4:
+ case UNW_AARCH64_X4:
return "x4";
- case UNW_ARM64_X5:
+ case UNW_AARCH64_X5:
return "x5";
- case UNW_ARM64_X6:
+ case UNW_AARCH64_X6:
return "x6";
- case UNW_ARM64_X7:
+ case UNW_AARCH64_X7:
return "x7";
- case UNW_ARM64_X8:
+ case UNW_AARCH64_X8:
return "x8";
- case UNW_ARM64_X9:
+ case UNW_AARCH64_X9:
return "x9";
- case UNW_ARM64_X10:
+ case UNW_AARCH64_X10:
return "x10";
- case UNW_ARM64_X11:
+ case UNW_AARCH64_X11:
return "x11";
- case UNW_ARM64_X12:
+ case UNW_AARCH64_X12:
return "x12";
- case UNW_ARM64_X13:
+ case UNW_AARCH64_X13:
return "x13";
- case UNW_ARM64_X14:
+ case UNW_AARCH64_X14:
return "x14";
- case UNW_ARM64_X15:
+ case UNW_AARCH64_X15:
return "x15";
- case UNW_ARM64_X16:
+ case UNW_AARCH64_X16:
return "x16";
- case UNW_ARM64_X17:
+ case UNW_AARCH64_X17:
return "x17";
- case UNW_ARM64_X18:
+ case UNW_AARCH64_X18:
return "x18";
- case UNW_ARM64_X19:
+ case UNW_AARCH64_X19:
return "x19";
- case UNW_ARM64_X20:
+ case UNW_AARCH64_X20:
return "x20";
- case UNW_ARM64_X21:
+ case UNW_AARCH64_X21:
return "x21";
- case UNW_ARM64_X22:
+ case UNW_AARCH64_X22:
return "x22";
- case UNW_ARM64_X23:
+ case UNW_AARCH64_X23:
return "x23";
- case UNW_ARM64_X24:
+ case UNW_AARCH64_X24:
return "x24";
- case UNW_ARM64_X25:
+ case UNW_AARCH64_X25:
return "x25";
- case UNW_ARM64_X26:
+ case UNW_AARCH64_X26:
return "x26";
- case UNW_ARM64_X27:
+ case UNW_AARCH64_X27:
return "x27";
- case UNW_ARM64_X28:
+ case UNW_AARCH64_X28:
return "x28";
- case UNW_ARM64_FP:
+ case UNW_AARCH64_FP:
return "fp";
- case UNW_ARM64_LR:
+ case UNW_AARCH64_LR:
return "lr";
- case UNW_ARM64_SP:
+ case UNW_AARCH64_SP:
return "sp";
- case UNW_ARM64_PC:
+ case UNW_AARCH64_PC:
return "pc";
- case UNW_ARM64_D0:
+ case UNW_AARCH64_V0:
return "d0";
- case UNW_ARM64_D1:
+ case UNW_AARCH64_V1:
return "d1";
- case UNW_ARM64_D2:
+ case UNW_AARCH64_V2:
return "d2";
- case UNW_ARM64_D3:
+ case UNW_AARCH64_V3:
return "d3";
- case UNW_ARM64_D4:
+ case UNW_AARCH64_V4:
return "d4";
- case UNW_ARM64_D5:
+ case UNW_AARCH64_V5:
return "d5";
- case UNW_ARM64_D6:
+ case UNW_AARCH64_V6:
return "d6";
- case UNW_ARM64_D7:
+ case UNW_AARCH64_V7:
return "d7";
- case UNW_ARM64_D8:
+ case UNW_AARCH64_V8:
return "d8";
- case UNW_ARM64_D9:
+ case UNW_AARCH64_V9:
return "d9";
- case UNW_ARM64_D10:
+ case UNW_AARCH64_V10:
return "d10";
- case UNW_ARM64_D11:
+ case UNW_AARCH64_V11:
return "d11";
- case UNW_ARM64_D12:
+ case UNW_AARCH64_V12:
return "d12";
- case UNW_ARM64_D13:
+ case UNW_AARCH64_V13:
return "d13";
- case UNW_ARM64_D14:
+ case UNW_AARCH64_V14:
return "d14";
- case UNW_ARM64_D15:
+ case UNW_AARCH64_V15:
return "d15";
- case UNW_ARM64_D16:
+ case UNW_AARCH64_V16:
return "d16";
- case UNW_ARM64_D17:
+ case UNW_AARCH64_V17:
return "d17";
- case UNW_ARM64_D18:
+ case UNW_AARCH64_V18:
return "d18";
- case UNW_ARM64_D19:
+ case UNW_AARCH64_V19:
return "d19";
- case UNW_ARM64_D20:
+ case UNW_AARCH64_V20:
return "d20";
- case UNW_ARM64_D21:
+ case UNW_AARCH64_V21:
return "d21";
- case UNW_ARM64_D22:
+ case UNW_AARCH64_V22:
return "d22";
- case UNW_ARM64_D23:
+ case UNW_AARCH64_V23:
return "d23";
- case UNW_ARM64_D24:
+ case UNW_AARCH64_V24:
return "d24";
- case UNW_ARM64_D25:
+ case UNW_AARCH64_V25:
return "d25";
- case UNW_ARM64_D26:
+ case UNW_AARCH64_V26:
return "d26";
- case UNW_ARM64_D27:
+ case UNW_AARCH64_V27:
return "d27";
- case UNW_ARM64_D28:
+ case UNW_AARCH64_V28:
return "d28";
- case UNW_ARM64_D29:
+ case UNW_AARCH64_V29:
return "d29";
- case UNW_ARM64_D30:
+ case UNW_AARCH64_V30:
return "d30";
- case UNW_ARM64_D31:
+ case UNW_AARCH64_V31:
return "d31";
default:
return "unknown register";
}
inline bool Registers_arm64::validFloatRegister(int regNum) const {
- if (regNum < UNW_ARM64_D0)
+ if (regNum < UNW_AARCH64_V0)
return false;
- if (regNum > UNW_ARM64_D31)
+ if (regNum > UNW_AARCH64_V31)
return false;
return true;
}
inline double Registers_arm64::getFloatRegister(int regNum) const {
assert(validFloatRegister(regNum));
- return _vectorHalfRegisters[regNum - UNW_ARM64_D0];
+ return _vectorHalfRegisters[regNum - UNW_AARCH64_V0];
}
inline void Registers_arm64::setFloatRegister(int regNum, double value) {
assert(validFloatRegister(regNum));
- _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value;
+ _vectorHalfRegisters[regNum - UNW_AARCH64_V0] = value;
}
inline bool Registers_arm64::validVectorRegister(int) const {
restoreSavedFloatRegisters();
restoreCoreAndJumpTo();
}
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM;
+ }
static int getArch() { return REGISTERS_ARM; }
uint32_t getSP() const { return _registers.__sp; }
void setSP(uint32_t value) { _registers.__sp = value; }
uint32_t getIP() const { return _registers.__pc; }
void setIP(uint32_t value) { _registers.__pc = value; }
- uint64_t getWCookie() const { return 0; }
void saveVFPAsX() {
assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
uint32_t __pc; // Program counter r15
};
+ struct PseudoRegisters {
+ uint32_t __pac; // Return Authentication Code (PAC)
+ };
+
static void saveVFPWithFSTMD(void*);
static void saveVFPWithFSTMX(void*);
static void saveVFPv3(void*);
// ARM registers
GPRs _registers;
+ PseudoRegisters _pseudo_registers;
// We save floating point registers lazily because we can't know ahead of
// time which ones are used. See EHABI #4.7.
"arm registers do not fit into unw_context_t");
// See __unw_getcontext() note about data.
memcpy(&_registers, registers, sizeof(_registers));
+ memset(&_pseudo_registers, 0, sizeof(_pseudo_registers));
memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
#if defined(__ARM_WMMX)
_saved_vfp_d0_d15(false),
_saved_vfp_d16_d31(false) {
memset(&_registers, 0, sizeof(_registers));
+ memset(&_pseudo_registers, 0, sizeof(_pseudo_registers));
memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
#if defined(__ARM_WMMX)
return true;
#endif
+#ifdef __ARM_FEATURE_PAUTH
+ if (regNum == UNW_ARM_RA_AUTH_CODE)
+ return true;
+#endif
+
return false;
}
}
#endif
+#ifdef __ARM_FEATURE_PAUTH
+ if (regNum == UNW_ARM_RA_AUTH_CODE)
+ return _pseudo_registers.__pac;
+#endif
+
_LIBUNWIND_ABORT("unsupported arm register");
}
}
#endif
+ if (regNum == UNW_ARM_RA_AUTH_CODE) {
+ _pseudo_registers.__pac = value;
+ return;
+ }
+
_LIBUNWIND_ABORT("unsupported arm register");
}
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K;
+ }
static int getArch() { return REGISTERS_OR1K; }
uint64_t getSP() const { return _registers.__r[1]; }
void setSP(uint32_t value) { _registers.__r[1] = value; }
uint64_t getIP() const { return _registers.__pc; }
void setIP(uint32_t value) { _registers.__pc = value; }
- uint64_t getWCookie() const { return 0; }
private:
struct or1k_thread_state_t {
}
#endif // _LIBUNWIND_TARGET_OR1K
-#if defined(_LIBUNWIND_TARGET_SPARC64)
-/// Registers_sparc64 holds the register state of a thread in a 64-bit
-/// sparc process.
-class _LIBUNWIND_HIDDEN Registers_sparc64 {
-public:
- Registers_sparc64();
- Registers_sparc64(const void *registers);
-
- bool validRegister(int num) const;
- uint64_t getRegister(int num) const;
- void setRegister(int num, uint64_t value);
- bool validFloatRegister(int num) const;
- double getFloatRegister(int num) const;
- void setFloatRegister(int num, double value);
- bool validVectorRegister(int num) const;
- v128 getVectorRegister(int num) const;
- void setVectorRegister(int num, v128 value);
- const char *getRegisterName(int num);
- void jumpto();
- static int lastDwarfRegNum() { return 31; }
- static int getArch() { return REGISTERS_SPARC64; }
-
- uint64_t getSP() const { return _registers.__o[6] + 2047; }
- void setSP(uint64_t value) { _registers.__o[6] = value - 2047; }
- uint64_t getIP() const { return _registers.__o[7]; }
- void setIP(uint64_t value) { _registers.__o[7] = value; }
- uint64_t getWCookie() const { return _wcookie; }
-
-private:
- struct GPRs {
- uint64_t __g[8];
- uint64_t __o[8];
- uint64_t __l[8];
- uint64_t __i[8];
- };
-
- GPRs _registers;
- uint64_t _wcookie;
-};
-
-inline Registers_sparc64::Registers_sparc64(const void *registers) {
- static_assert((check_fit<Registers_sparc64, unw_context_t>::does_fit),
- "sparc64 registers do not fit into unw_context_t");
- memcpy(&_registers, static_cast<const uint8_t *>(registers),
- sizeof(_registers));
- memcpy(&_wcookie, static_cast<const uint8_t *>(registers) + sizeof(GPRs),
- sizeof(_wcookie));
-}
-
-inline Registers_sparc64::Registers_sparc64() {
- memset(&_registers, 0, sizeof(_registers));
- _wcookie = 0;
-}
-
-inline bool Registers_sparc64::validRegister(int regNum) const {
- if (regNum == UNW_REG_IP)
- return true;
- if (regNum == UNW_REG_SP)
- return true;
- if (regNum < 0)
- return false;
- if (regNum <= 31)
- return true;
- return false;
-}
-
-inline uint64_t Registers_sparc64::getRegister(int regNum) const {
- if (regNum >= 0 && regNum <= 7)
- return _registers.__g[regNum - 0];
- if (regNum >= 8 && regNum <= 15)
- return _registers.__o[regNum - 8];
- if (regNum >= 16 && regNum <= 23)
- return _registers.__l[regNum - 16];
- if (regNum >= 24 && regNum <= 31)
- return _registers.__i[regNum - 24];
-
- switch (regNum) {
- case UNW_REG_IP:
- return _registers.__o[7] + 8;
- case UNW_REG_SP:
- return _registers.__o[6] + 2047;
- }
- _LIBUNWIND_ABORT("unsupported sparc64 register");
-}
-
-inline void Registers_sparc64::setRegister(int regNum, uint64_t value) {
- if (regNum >= 0 && regNum <= 7) {
- _registers.__g[regNum - 0] = value;
- return;
- }
- if (regNum >= 8 && regNum <= 15) {
- _registers.__o[regNum - 8] = value;
- return;
- }
- if (regNum >= 16 && regNum <= 23) {
- _registers.__l[regNum - 16] = value;
- return;
- }
- if (regNum >= 24 && regNum <= 31) {
- _registers.__i[regNum - 24] = value;
- return;
- }
-
- switch (regNum) {
- case UNW_REG_IP:
- _registers.__o[7] = value - 8;
- return;
- case UNW_REG_SP:
- _registers.__o[6] = value - 2047;
- return;
- }
- _LIBUNWIND_ABORT("unsupported sparc64 register");
-}
-
-inline bool Registers_sparc64::validFloatRegister(int) const {
- return false;
-}
-
-inline double Registers_sparc64::getFloatRegister(int) const {
- _LIBUNWIND_ABORT("no sparc64 float registers");
-}
-
-inline void Registers_sparc64::setFloatRegister(int, double) {
- _LIBUNWIND_ABORT("no sparc64 float registers");
-}
-
-inline bool Registers_sparc64::validVectorRegister(int) const {
- return false;
-}
-
-inline v128 Registers_sparc64::getVectorRegister(int) const {
- _LIBUNWIND_ABORT("no sparc64 vector registers");
-}
-
-inline void Registers_sparc64::setVectorRegister(int, v128) {
- _LIBUNWIND_ABORT("no sparc64 vector registers");
-}
-
-inline const char *Registers_sparc64::getRegisterName(int regNum) {
- return "unknown register";
-}
-
-#endif // _LIBUNWIND_TARGET_SPARC64
-
#if defined(_LIBUNWIND_TARGET_MIPS_O32)
/// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS
/// process.
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS;
+ }
static int getArch() { return REGISTERS_MIPS_O32; }
uint32_t getSP() const { return _registers.__r[29]; }
void setSP(uint32_t value) { _registers.__r[29] = value; }
uint32_t getIP() const { return _registers.__pc; }
void setIP(uint32_t value) { _registers.__pc = value; }
- uint32_t getWCookie() const { return 0; }
private:
struct mips_o32_thread_state_t {
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS;
+ }
static int getArch() { return REGISTERS_MIPS_NEWABI; }
uint64_t getSP() const { return _registers.__r[29]; }
void setSP(uint64_t value) { _registers.__r[29] = value; }
uint64_t getIP() const { return _registers.__pc; }
void setIP(uint64_t value) { _registers.__pc = value; }
- uint32_t getWCookie() const { return 0; }
private:
struct mips_newabi_thread_state_t {
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC;
+ }
static int getArch() { return REGISTERS_SPARC; }
uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6]; }
}
#endif // _LIBUNWIND_TARGET_SPARC
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+/// Registers_sparc64 holds the register state of a thread in a 64-bit
+/// sparc process.
+class _LIBUNWIND_HIDDEN Registers_sparc64 {
+public:
+ Registers_sparc64() = default;
+ Registers_sparc64(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64;
+ }
+ static int getArch() { return REGISTERS_SPARC64; }
+
+ uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6] + 2047; }
+ void setSP(uint64_t value) { _registers.__regs[UNW_SPARC_O6] = value - 2047; }
+ uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; }
+ void setIP(uint64_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
+ uint64_t getWCookie() const { return _wcookie; }
+
+private:
+ struct sparc64_thread_state_t {
+ uint64_t __regs[32];
+ };
+
+ sparc64_thread_state_t _registers{};
+ uint64_t _wcookie = 0;
+};
+
+inline Registers_sparc64::Registers_sparc64(const void *registers) {
+ static_assert((check_fit<Registers_sparc64, unw_context_t>::does_fit),
+ "sparc64 registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+ memcpy(&_wcookie,
+ static_cast<const uint8_t *>(registers) + sizeof(_registers),
+ sizeof(_wcookie));
+}
+
+inline bool Registers_sparc64::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum <= UNW_SPARC_I7)
+ return true;
+ return false;
+}
+
+inline uint64_t Registers_sparc64::getRegister(int regNum) const {
+ if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7)
+ return _registers.__regs[regNum];
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__regs[UNW_SPARC_O7];
+ case UNW_REG_SP:
+ return _registers.__regs[UNW_SPARC_O6] + 2047;
+ }
+ _LIBUNWIND_ABORT("unsupported sparc64 register");
+}
+
+inline void Registers_sparc64::setRegister(int regNum, uint64_t value) {
+ if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7) {
+ _registers.__regs[regNum] = value;
+ return;
+ }
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__regs[UNW_SPARC_O7] = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__regs[UNW_SPARC_O6] = value - 2047;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported sparc64 register");
+}
+
+inline bool Registers_sparc64::validFloatRegister(int) const { return false; }
+
+inline double Registers_sparc64::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("no sparc64 float registers");
+}
+
+inline void Registers_sparc64::setFloatRegister(int, double) {
+ _LIBUNWIND_ABORT("no sparc64 float registers");
+}
+
+inline bool Registers_sparc64::validVectorRegister(int) const { return false; }
+
+inline v128 Registers_sparc64::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no sparc64 vector registers");
+}
+
+inline void Registers_sparc64::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no sparc64 vector registers");
+}
+
+inline const char *Registers_sparc64::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "pc";
+ case UNW_SPARC_G0:
+ return "g0";
+ case UNW_SPARC_G1:
+ return "g1";
+ case UNW_SPARC_G2:
+ return "g2";
+ case UNW_SPARC_G3:
+ return "g3";
+ case UNW_SPARC_G4:
+ return "g4";
+ case UNW_SPARC_G5:
+ return "g5";
+ case UNW_SPARC_G6:
+ return "g6";
+ case UNW_SPARC_G7:
+ return "g7";
+ case UNW_SPARC_O0:
+ return "o0";
+ case UNW_SPARC_O1:
+ return "o1";
+ case UNW_SPARC_O2:
+ return "o2";
+ case UNW_SPARC_O3:
+ return "o3";
+ case UNW_SPARC_O4:
+ return "o4";
+ case UNW_SPARC_O5:
+ return "o5";
+ case UNW_REG_SP:
+ case UNW_SPARC_O6:
+ return "o6";
+ case UNW_SPARC_O7:
+ return "o7";
+ case UNW_SPARC_L0:
+ return "l0";
+ case UNW_SPARC_L1:
+ return "l1";
+ case UNW_SPARC_L2:
+ return "l2";
+ case UNW_SPARC_L3:
+ return "l3";
+ case UNW_SPARC_L4:
+ return "l4";
+ case UNW_SPARC_L5:
+ return "l5";
+ case UNW_SPARC_L6:
+ return "l6";
+ case UNW_SPARC_L7:
+ return "l7";
+ case UNW_SPARC_I0:
+ return "i0";
+ case UNW_SPARC_I1:
+ return "i1";
+ case UNW_SPARC_I2:
+ return "i2";
+ case UNW_SPARC_I3:
+ return "i3";
+ case UNW_SPARC_I4:
+ return "i4";
+ case UNW_SPARC_I5:
+ return "i5";
+ case UNW_SPARC_I6:
+ return "i6";
+ case UNW_SPARC_I7:
+ return "i7";
+ default:
+ return "unknown register";
+ }
+}
+#endif // _LIBUNWIND_TARGET_SPARC64
+
#if defined(_LIBUNWIND_TARGET_HEXAGON)
/// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6
/// process.
void setVectorRegister(int num, v128 value);
const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON;
+ }
static int getArch() { return REGISTERS_HEXAGON; }
uint32_t getSP() const { return _registers.__r[UNW_HEXAGON_R29]; }
# error "Unsupported __riscv_flen"
# endif
# else
-// This is just for supressing undeclared error of fp_t.
+// This is just for suppressing undeclared error of fp_t.
typedef double fp_t;
# endif
# else
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV;
+ }
static int getArch() { return REGISTERS_RISCV; }
reg_t getSP() const { return _registers[2]; }
void setSP(reg_t value) { _registers[2] = value; }
reg_t getIP() const { return _registers[0]; }
void setIP(reg_t value) { _registers[0] = value; }
- uint64_t getWCookie() const { return 0; }
private:
// _registers[0] holds the pc
return true;
if (regNum < 0)
return false;
+ if (regNum == UNW_RISCV_VLENB)
+ return true;
if (regNum > UNW_RISCV_F31)
return false;
return true;
return 0;
if ((regNum > 0) && (regNum < 32))
return _registers[regNum];
+ if (regNum == UNW_RISCV_VLENB) {
+ reg_t vlenb;
+ __asm__("csrr %0, 0xC22" : "=r"(vlenb));
+ return vlenb;
+ }
_LIBUNWIND_ABORT("unsupported riscv register");
}
return "ft10";
case UNW_RISCV_F31:
return "ft11";
+ case UNW_RISCV_VLENB:
+ return "vlenb";
default:
return "unknown register";
}
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE; }
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE;
+ }
static int getArch() { return REGISTERS_VE; }
uint64_t getSP() const { return _registers.__s[11]; }
}
#endif // _LIBUNWIND_TARGET_VE
+#if defined(_LIBUNWIND_TARGET_S390X)
+/// Registers_s390x holds the register state of a thread in a
+/// 64-bit Linux on IBM zSystems process.
+class _LIBUNWIND_HIDDEN Registers_s390x {
+public:
+ Registers_s390x();
+ Registers_s390x(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X;
+ }
+ static int getArch() { return REGISTERS_S390X; }
+
+ uint64_t getSP() const { return _registers.__gpr[15]; }
+ void setSP(uint64_t value) { _registers.__gpr[15] = value; }
+ uint64_t getIP() const { return _registers.__pswa; }
+ void setIP(uint64_t value) { _registers.__pswa = value; }
+
+private:
+ struct s390x_thread_state_t {
+ uint64_t __pswm; // Problem Status Word: Mask
+ uint64_t __pswa; // Problem Status Word: Address (PC)
+ uint64_t __gpr[16]; // General Purpose Registers
+ double __fpr[16]; // Floating-Point Registers
+ };
+
+ s390x_thread_state_t _registers;
+};
+
+inline Registers_s390x::Registers_s390x(const void *registers) {
+ static_assert((check_fit<Registers_s390x, unw_context_t>::does_fit),
+ "s390x registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast<const uint8_t *>(registers),
+ sizeof(_registers));
+}
+
+inline Registers_s390x::Registers_s390x() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_s390x::validRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_S390X_PSWM:
+ case UNW_S390X_PSWA:
+ case UNW_REG_IP:
+ case UNW_REG_SP:
+ return true;
+ }
+
+ if (regNum >= UNW_S390X_R0 && regNum <= UNW_S390X_R15)
+ return true;
+
+ return false;
+}
+
+inline uint64_t Registers_s390x::getRegister(int regNum) const {
+ if (regNum >= UNW_S390X_R0 && regNum <= UNW_S390X_R15)
+ return _registers.__gpr[regNum - UNW_S390X_R0];
+
+ switch (regNum) {
+ case UNW_S390X_PSWM:
+ return _registers.__pswm;
+ case UNW_S390X_PSWA:
+ case UNW_REG_IP:
+ return _registers.__pswa;
+ case UNW_REG_SP:
+ return _registers.__gpr[15];
+ }
+ _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline void Registers_s390x::setRegister(int regNum, uint64_t value) {
+ if (regNum >= UNW_S390X_R0 && regNum <= UNW_S390X_R15) {
+ _registers.__gpr[regNum - UNW_S390X_R0] = value;
+ return;
+ }
+
+ switch (regNum) {
+ case UNW_S390X_PSWM:
+ _registers.__pswm = value;
+ return;
+ case UNW_S390X_PSWA:
+ case UNW_REG_IP:
+ _registers.__pswa = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__gpr[15] = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline bool Registers_s390x::validFloatRegister(int regNum) const {
+ return regNum >= UNW_S390X_F0 && regNum <= UNW_S390X_F15;
+}
+
+inline double Registers_s390x::getFloatRegister(int regNum) const {
+ // NOTE: FPR DWARF register numbers are not consecutive.
+ switch (regNum) {
+ case UNW_S390X_F0:
+ return _registers.__fpr[0];
+ case UNW_S390X_F1:
+ return _registers.__fpr[1];
+ case UNW_S390X_F2:
+ return _registers.__fpr[2];
+ case UNW_S390X_F3:
+ return _registers.__fpr[3];
+ case UNW_S390X_F4:
+ return _registers.__fpr[4];
+ case UNW_S390X_F5:
+ return _registers.__fpr[5];
+ case UNW_S390X_F6:
+ return _registers.__fpr[6];
+ case UNW_S390X_F7:
+ return _registers.__fpr[7];
+ case UNW_S390X_F8:
+ return _registers.__fpr[8];
+ case UNW_S390X_F9:
+ return _registers.__fpr[9];
+ case UNW_S390X_F10:
+ return _registers.__fpr[10];
+ case UNW_S390X_F11:
+ return _registers.__fpr[11];
+ case UNW_S390X_F12:
+ return _registers.__fpr[12];
+ case UNW_S390X_F13:
+ return _registers.__fpr[13];
+ case UNW_S390X_F14:
+ return _registers.__fpr[14];
+ case UNW_S390X_F15:
+ return _registers.__fpr[15];
+ }
+ _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline void Registers_s390x::setFloatRegister(int regNum, double value) {
+ // NOTE: FPR DWARF register numbers are not consecutive.
+ switch (regNum) {
+ case UNW_S390X_F0:
+ _registers.__fpr[0] = value;
+ return;
+ case UNW_S390X_F1:
+ _registers.__fpr[1] = value;
+ return;
+ case UNW_S390X_F2:
+ _registers.__fpr[2] = value;
+ return;
+ case UNW_S390X_F3:
+ _registers.__fpr[3] = value;
+ return;
+ case UNW_S390X_F4:
+ _registers.__fpr[4] = value;
+ return;
+ case UNW_S390X_F5:
+ _registers.__fpr[5] = value;
+ return;
+ case UNW_S390X_F6:
+ _registers.__fpr[6] = value;
+ return;
+ case UNW_S390X_F7:
+ _registers.__fpr[7] = value;
+ return;
+ case UNW_S390X_F8:
+ _registers.__fpr[8] = value;
+ return;
+ case UNW_S390X_F9:
+ _registers.__fpr[9] = value;
+ return;
+ case UNW_S390X_F10:
+ _registers.__fpr[10] = value;
+ return;
+ case UNW_S390X_F11:
+ _registers.__fpr[11] = value;
+ return;
+ case UNW_S390X_F12:
+ _registers.__fpr[12] = value;
+ return;
+ case UNW_S390X_F13:
+ _registers.__fpr[13] = value;
+ return;
+ case UNW_S390X_F14:
+ _registers.__fpr[14] = value;
+ return;
+ case UNW_S390X_F15:
+ _registers.__fpr[15] = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline bool Registers_s390x::validVectorRegister(int /*regNum*/) const {
+ return false;
+}
+
+inline v128 Registers_s390x::getVectorRegister(int /*regNum*/) const {
+ _LIBUNWIND_ABORT("s390x vector support not implemented");
+}
+
+inline void Registers_s390x::setVectorRegister(int /*regNum*/, v128 /*value*/) {
+ _LIBUNWIND_ABORT("s390x vector support not implemented");
+}
+
+inline const char *Registers_s390x::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_S390X_R0:
+ return "r0";
+ case UNW_S390X_R1:
+ return "r1";
+ case UNW_S390X_R2:
+ return "r2";
+ case UNW_S390X_R3:
+ return "r3";
+ case UNW_S390X_R4:
+ return "r4";
+ case UNW_S390X_R5:
+ return "r5";
+ case UNW_S390X_R6:
+ return "r6";
+ case UNW_S390X_R7:
+ return "r7";
+ case UNW_S390X_R8:
+ return "r8";
+ case UNW_S390X_R9:
+ return "r9";
+ case UNW_S390X_R10:
+ return "r10";
+ case UNW_S390X_R11:
+ return "r11";
+ case UNW_S390X_R12:
+ return "r12";
+ case UNW_S390X_R13:
+ return "r13";
+ case UNW_S390X_R14:
+ return "r14";
+ case UNW_S390X_R15:
+ return "r15";
+ case UNW_S390X_F0:
+ return "f0";
+ case UNW_S390X_F1:
+ return "f1";
+ case UNW_S390X_F2:
+ return "f2";
+ case UNW_S390X_F3:
+ return "f3";
+ case UNW_S390X_F4:
+ return "f4";
+ case UNW_S390X_F5:
+ return "f5";
+ case UNW_S390X_F6:
+ return "f6";
+ case UNW_S390X_F7:
+ return "f7";
+ case UNW_S390X_F8:
+ return "f8";
+ case UNW_S390X_F9:
+ return "f9";
+ case UNW_S390X_F10:
+ return "f10";
+ case UNW_S390X_F11:
+ return "f11";
+ case UNW_S390X_F12:
+ return "f12";
+ case UNW_S390X_F13:
+ return "f13";
+ case UNW_S390X_F14:
+ return "f14";
+ case UNW_S390X_F15:
+ return "f15";
+ }
+ return "unknown register";
+}
+#endif // _LIBUNWIND_TARGET_S390X
+
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+/// Registers_loongarch holds the register state of a thread in a 64-bit
+/// LoongArch process.
+class _LIBUNWIND_HIDDEN Registers_loongarch {
+public:
+ Registers_loongarch();
+ Registers_loongarch(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH;
+ }
+ static int getArch() { return REGISTERS_LOONGARCH; }
+
+ uint64_t getSP() const { return _registers.__r[3]; }
+ void setSP(uint64_t value) { _registers.__r[3] = value; }
+ uint64_t getIP() const { return _registers.__pc; }
+ void setIP(uint64_t value) { _registers.__pc = value; }
+
+private:
+ struct loongarch_thread_state_t {
+ uint64_t __r[32];
+ uint64_t __pc;
+ };
+
+ loongarch_thread_state_t _registers;
+#if __loongarch_frlen == 64
+ double _floats[32];
+#endif
+};
+
+inline Registers_loongarch::Registers_loongarch(const void *registers) {
+ static_assert((check_fit<Registers_loongarch, unw_context_t>::does_fit),
+ "loongarch registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+ static_assert(sizeof(_registers) == 0x108,
+ "expected float registers to be at offset 264");
+#if __loongarch_frlen == 64
+ memcpy(_floats, static_cast<const uint8_t *>(registers) + sizeof(_registers),
+ sizeof(_floats));
+#endif
+}
+
+inline Registers_loongarch::Registers_loongarch() {
+ memset(&_registers, 0, sizeof(_registers));
+#if __loongarch_frlen == 64
+ memset(&_floats, 0, sizeof(_floats));
+#endif
+}
+
+inline bool Registers_loongarch::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP || regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0 || regNum > UNW_LOONGARCH_F31)
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_loongarch::getRegister(int regNum) const {
+ if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+ return _registers.__r[regNum - UNW_LOONGARCH_R0];
+
+ if (regNum == UNW_REG_IP)
+ return _registers.__pc;
+ if (regNum == UNW_REG_SP)
+ return _registers.__r[3];
+ _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline void Registers_loongarch::setRegister(int regNum, uint64_t value) {
+ if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+ _registers.__r[regNum - UNW_LOONGARCH_R0] = value;
+ else if (regNum == UNW_REG_IP)
+ _registers.__pc = value;
+ else if (regNum == UNW_REG_SP)
+ _registers.__r[3] = value;
+ else
+ _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline const char *Registers_loongarch::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "$pc";
+ case UNW_REG_SP:
+ return "$sp";
+ case UNW_LOONGARCH_R0:
+ return "$r0";
+ case UNW_LOONGARCH_R1:
+ return "$r1";
+ case UNW_LOONGARCH_R2:
+ return "$r2";
+ case UNW_LOONGARCH_R3:
+ return "$r3";
+ case UNW_LOONGARCH_R4:
+ return "$r4";
+ case UNW_LOONGARCH_R5:
+ return "$r5";
+ case UNW_LOONGARCH_R6:
+ return "$r6";
+ case UNW_LOONGARCH_R7:
+ return "$r7";
+ case UNW_LOONGARCH_R8:
+ return "$r8";
+ case UNW_LOONGARCH_R9:
+ return "$r9";
+ case UNW_LOONGARCH_R10:
+ return "$r10";
+ case UNW_LOONGARCH_R11:
+ return "$r11";
+ case UNW_LOONGARCH_R12:
+ return "$r12";
+ case UNW_LOONGARCH_R13:
+ return "$r13";
+ case UNW_LOONGARCH_R14:
+ return "$r14";
+ case UNW_LOONGARCH_R15:
+ return "$r15";
+ case UNW_LOONGARCH_R16:
+ return "$r16";
+ case UNW_LOONGARCH_R17:
+ return "$r17";
+ case UNW_LOONGARCH_R18:
+ return "$r18";
+ case UNW_LOONGARCH_R19:
+ return "$r19";
+ case UNW_LOONGARCH_R20:
+ return "$r20";
+ case UNW_LOONGARCH_R21:
+ return "$r21";
+ case UNW_LOONGARCH_R22:
+ return "$r22";
+ case UNW_LOONGARCH_R23:
+ return "$r23";
+ case UNW_LOONGARCH_R24:
+ return "$r24";
+ case UNW_LOONGARCH_R25:
+ return "$r25";
+ case UNW_LOONGARCH_R26:
+ return "$r26";
+ case UNW_LOONGARCH_R27:
+ return "$r27";
+ case UNW_LOONGARCH_R28:
+ return "$r28";
+ case UNW_LOONGARCH_R29:
+ return "$r29";
+ case UNW_LOONGARCH_R30:
+ return "$r30";
+ case UNW_LOONGARCH_R31:
+ return "$r31";
+ case UNW_LOONGARCH_F0:
+ return "$f0";
+ case UNW_LOONGARCH_F1:
+ return "$f1";
+ case UNW_LOONGARCH_F2:
+ return "$f2";
+ case UNW_LOONGARCH_F3:
+ return "$f3";
+ case UNW_LOONGARCH_F4:
+ return "$f4";
+ case UNW_LOONGARCH_F5:
+ return "$f5";
+ case UNW_LOONGARCH_F6:
+ return "$f6";
+ case UNW_LOONGARCH_F7:
+ return "$f7";
+ case UNW_LOONGARCH_F8:
+ return "$f8";
+ case UNW_LOONGARCH_F9:
+ return "$f9";
+ case UNW_LOONGARCH_F10:
+ return "$f10";
+ case UNW_LOONGARCH_F11:
+ return "$f11";
+ case UNW_LOONGARCH_F12:
+ return "$f12";
+ case UNW_LOONGARCH_F13:
+ return "$f13";
+ case UNW_LOONGARCH_F14:
+ return "$f14";
+ case UNW_LOONGARCH_F15:
+ return "$f15";
+ case UNW_LOONGARCH_F16:
+ return "$f16";
+ case UNW_LOONGARCH_F17:
+ return "$f17";
+ case UNW_LOONGARCH_F18:
+ return "$f18";
+ case UNW_LOONGARCH_F19:
+ return "$f19";
+ case UNW_LOONGARCH_F20:
+ return "$f20";
+ case UNW_LOONGARCH_F21:
+ return "$f21";
+ case UNW_LOONGARCH_F22:
+ return "$f22";
+ case UNW_LOONGARCH_F23:
+ return "$f23";
+ case UNW_LOONGARCH_F24:
+ return "$f24";
+ case UNW_LOONGARCH_F25:
+ return "$f25";
+ case UNW_LOONGARCH_F26:
+ return "$f26";
+ case UNW_LOONGARCH_F27:
+ return "$f27";
+ case UNW_LOONGARCH_F28:
+ return "$f28";
+ case UNW_LOONGARCH_F29:
+ return "$f29";
+ case UNW_LOONGARCH_F30:
+ return "$f30";
+ case UNW_LOONGARCH_F31:
+ return "$f31";
+ default:
+ return "unknown register";
+ }
+}
+
+inline bool Registers_loongarch::validFloatRegister(int regNum) const {
+ if (regNum < UNW_LOONGARCH_F0 || regNum > UNW_LOONGARCH_F31)
+ return false;
+ return true;
+}
+
+inline double Registers_loongarch::getFloatRegister(int regNum) const {
+#if __loongarch_frlen == 64
+ assert(validFloatRegister(regNum));
+ return _floats[regNum - UNW_LOONGARCH_F0];
+#else
+ _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline void Registers_loongarch::setFloatRegister(int regNum, double value) {
+#if __loongarch_frlen == 64
+ assert(validFloatRegister(regNum));
+ _floats[regNum - UNW_LOONGARCH_F0] = value;
+#else
+ _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline bool Registers_loongarch::validVectorRegister(int) const {
+ return false;
+}
+
+inline v128 Registers_loongarch::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+
+inline void Registers_loongarch::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+#endif //_LIBUNWIND_TARGET_LOONGARCH
+
} // namespace libunwind
#endif // __REGISTERS_HPP__
-//===------------------------- UnwindCursor.hpp ---------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#ifndef __UNWINDCURSOR_HPP__
#define __UNWINDCURSOR_HPP__
+#include "cet_unwind.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
+#ifdef _AIX
+#include <dlfcn.h>
+#include <sys/debug.h>
+#include <sys/pseg.h>
+#endif
+
+#if defined(_LIBUNWIND_TARGET_LINUX) && \
+ (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_S390X))
+#include <sys/syscall.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
+#endif
+
+#include "AddressSpace.hpp"
+#include "CompactUnwinder.hpp"
+#include "config.h"
+#include "DwarfInstructions.hpp"
+#include "EHHeaderParser.hpp"
+#include "libunwind.h"
+#include "libunwind_ext.h"
+#include "Registers.hpp"
+#include "RWMutex.hpp"
+#include "Unwind-EHABI.h"
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and
#endif
-#include "config.h"
-
-#include "AddressSpace.hpp"
-#include "CompactUnwinder.hpp"
-#include "config.h"
-#include "DwarfInstructions.hpp"
-#include "EHHeaderParser.hpp"
-#include "libunwind.h"
-#include "Registers.hpp"
-#include "RWMutex.hpp"
-#include "Unwind-EHABI.h"
-
namespace libunwind {
static thread_local UnwindInfoSectionsCache uwis_cache;
virtual void setFloatReg(int, unw_fpreg_t) {
_LIBUNWIND_ABORT("setFloatReg not implemented");
}
- virtual int step() { _LIBUNWIND_ABORT("step not implemented"); }
+ virtual int step(bool = false) { _LIBUNWIND_ABORT("step not implemented"); }
virtual void getInfo(unw_proc_info_t *) {
_LIBUNWIND_ABORT("getInfo not implemented");
}
#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_USE_CET)
+ virtual void *get_registers() {
+ _LIBUNWIND_ABORT("get_registers not implemented");
+ }
+#endif
};
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
virtual bool validFloatReg(int);
virtual unw_fpreg_t getFloatReg(int);
virtual void setFloatReg(int, unw_fpreg_t);
- virtual int step();
+ virtual int step(bool = false);
virtual void getInfo(unw_proc_info_t *);
virtual void jumpto();
virtual bool isSignalFrame();
void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; }
// libunwind does not and should not depend on C++ library which means that we
- // need our own defition of inline placement new.
+ // need our own definition of inline placement new.
static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
private:
pint_t getLastPC() const { return _dispContext.ControlPc; }
void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; }
RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) {
+#ifdef __arm__
+ // Remove the thumb bit; FunctionEntry ranges don't include the thumb bit.
+ pc &= ~1U;
+#endif
+ // If pc points exactly at the end of the range, we might resolve the
+ // next function instead. Decrement pc by 1 to fit inside the current
+ // function.
+ pc -= 1;
_dispContext.FunctionEntry = RtlLookupFunctionEntry(pc,
&_dispContext.ImageBase,
_dispContext.HistoryTable);
_msContext.D[i - UNW_ARM_D0] = d.w;
}
#elif defined(_LIBUNWIND_TARGET_AARCH64)
- for (int i = UNW_ARM64_X0; i <= UNW_ARM64_X30; ++i)
- _msContext.X[i - UNW_ARM64_X0] = r.getRegister(i);
+ for (int i = UNW_AARCH64_X0; i <= UNW_ARM64_X30; ++i)
+ _msContext.X[i - UNW_AARCH64_X0] = r.getRegister(i);
_msContext.Sp = r.getRegister(UNW_REG_SP);
_msContext.Pc = r.getRegister(UNW_REG_IP);
- for (int i = UNW_ARM64_D0; i <= UNW_ARM64_D31; ++i)
- _msContext.V[i - UNW_ARM64_D0].D[0] = r.getFloatRegister(i);
+ for (int i = UNW_AARCH64_V0; i <= UNW_ARM64_D31; ++i)
+ _msContext.V[i - UNW_AARCH64_V0].D[0] = r.getFloatRegister(i);
#endif
}
#if defined(_LIBUNWIND_TARGET_X86_64)
if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true;
#elif defined(_LIBUNWIND_TARGET_ARM)
- if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true;
+ if ((regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) ||
+ regNum == UNW_ARM_RA_AUTH_CODE)
+ return true;
#elif defined(_LIBUNWIND_TARGET_AARCH64)
- if (regNum >= UNW_ARM64_X0 && regNum <= UNW_ARM64_X30) return true;
+ if (regNum >= UNW_AARCH64_X0 && regNum <= UNW_ARM64_X30) return true;
#endif
return false;
}
#elif defined(_LIBUNWIND_TARGET_AARCH64)
case UNW_REG_SP: return _msContext.Sp;
case UNW_REG_IP: return _msContext.Pc;
- default: return _msContext.X[regNum - UNW_ARM64_X0];
+ default: return _msContext.X[regNum - UNW_AARCH64_X0];
#endif
}
_LIBUNWIND_ABORT("unsupported register");
#elif defined(_LIBUNWIND_TARGET_AARCH64)
case UNW_REG_SP: _msContext.Sp = value; break;
case UNW_REG_IP: _msContext.Pc = value; break;
- case UNW_ARM64_X0:
- case UNW_ARM64_X1:
- case UNW_ARM64_X2:
- case UNW_ARM64_X3:
- case UNW_ARM64_X4:
- case UNW_ARM64_X5:
- case UNW_ARM64_X6:
- case UNW_ARM64_X7:
- case UNW_ARM64_X8:
- case UNW_ARM64_X9:
- case UNW_ARM64_X10:
- case UNW_ARM64_X11:
- case UNW_ARM64_X12:
- case UNW_ARM64_X13:
- case UNW_ARM64_X14:
- case UNW_ARM64_X15:
- case UNW_ARM64_X16:
- case UNW_ARM64_X17:
- case UNW_ARM64_X18:
- case UNW_ARM64_X19:
- case UNW_ARM64_X20:
- case UNW_ARM64_X21:
- case UNW_ARM64_X22:
- case UNW_ARM64_X23:
- case UNW_ARM64_X24:
- case UNW_ARM64_X25:
- case UNW_ARM64_X26:
- case UNW_ARM64_X27:
- case UNW_ARM64_X28:
- case UNW_ARM64_FP:
- case UNW_ARM64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break;
+ case UNW_AARCH64_X0:
+ case UNW_AARCH64_X1:
+ case UNW_AARCH64_X2:
+ case UNW_AARCH64_X3:
+ case UNW_AARCH64_X4:
+ case UNW_AARCH64_X5:
+ case UNW_AARCH64_X6:
+ case UNW_AARCH64_X7:
+ case UNW_AARCH64_X8:
+ case UNW_AARCH64_X9:
+ case UNW_AARCH64_X10:
+ case UNW_AARCH64_X11:
+ case UNW_AARCH64_X12:
+ case UNW_AARCH64_X13:
+ case UNW_AARCH64_X14:
+ case UNW_AARCH64_X15:
+ case UNW_AARCH64_X16:
+ case UNW_AARCH64_X17:
+ case UNW_AARCH64_X18:
+ case UNW_AARCH64_X19:
+ case UNW_AARCH64_X20:
+ case UNW_AARCH64_X21:
+ case UNW_AARCH64_X22:
+ case UNW_AARCH64_X23:
+ case UNW_AARCH64_X24:
+ case UNW_AARCH64_X25:
+ case UNW_AARCH64_X26:
+ case UNW_AARCH64_X27:
+ case UNW_AARCH64_X28:
+ case UNW_AARCH64_FP:
+ case UNW_AARCH64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break;
#endif
default:
_LIBUNWIND_ABORT("unsupported register");
if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true;
if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true;
#elif defined(_LIBUNWIND_TARGET_AARCH64)
- if (regNum >= UNW_ARM64_D0 && regNum <= UNW_ARM64_D31) return true;
+ if (regNum >= UNW_AARCH64_V0 && regNum <= UNW_ARM64_D31) return true;
#else
(void)regNum;
#endif
}
_LIBUNWIND_ABORT("unsupported float register");
#elif defined(_LIBUNWIND_TARGET_AARCH64)
- return _msContext.V[regNum - UNW_ARM64_D0].D[0];
+ return _msContext.V[regNum - UNW_AARCH64_V0].D[0];
#else
(void)regNum;
_LIBUNWIND_ABORT("float registers unimplemented");
uint32_t w;
float f;
} d;
- d.f = value;
+ d.f = (float)value;
_msContext.S[regNum - UNW_ARM_S0] = d.w;
}
if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
}
_LIBUNWIND_ABORT("unsupported float register");
#elif defined(_LIBUNWIND_TARGET_AARCH64)
- _msContext.V[regNum - UNW_ARM64_D0].D[0] = value;
+ _msContext.V[regNum - UNW_AARCH64_V0].D[0] = value;
#else
(void)regNum;
(void)value;
virtual bool validFloatReg(int);
virtual unw_fpreg_t getFloatReg(int);
virtual void setFloatReg(int, unw_fpreg_t);
- virtual int step();
+ virtual int step(bool stage2 = false);
virtual void getInfo(unw_proc_info_t *);
virtual void jumpto();
virtual bool isSignalFrame();
virtual void saveVFPAsX();
#endif
+#ifdef _AIX
+ virtual uintptr_t getDataRelBase();
+#endif
+
+#if defined(_LIBUNWIND_USE_CET)
+ virtual void *get_registers() { return &_registers; }
+#endif
+
// libunwind does not and should not depend on C++ library which means that we
- // need our own defition of inline placement new.
+ // need our own definition of inline placement new.
static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
private:
}
#endif
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
bool setInfoForSigReturn() {
R dummy;
return setInfoForSigReturn(dummy);
R dummy;
return stepThroughSigReturn(dummy);
}
+#if defined(_LIBUNWIND_TARGET_AARCH64)
bool setInfoForSigReturn(Registers_arm64 &);
int stepThroughSigReturn(Registers_arm64 &);
+#endif
+#if defined(_LIBUNWIND_TARGET_S390X)
+ bool setInfoForSigReturn(Registers_s390x &);
+ int stepThroughSigReturn(Registers_s390x &);
+#endif
template <typename Registers> bool setInfoForSigReturn(Registers &) {
return false;
}
pint_t pc, uintptr_t dso_base);
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s,
uint32_t fdeSectionOffsetHint=0);
- int stepWithDwarfFDE() {
- return DwarfInstructions<A, R>::stepWithDwarf(_addressSpace,
- (pint_t)this->getReg(UNW_REG_IP),
- (pint_t)_info.unwind_info,
- _registers, _isSignalFrame);
+ int stepWithDwarfFDE(bool stage2) {
+ return DwarfInstructions<A, R>::stepWithDwarf(
+ _addressSpace, (pint_t)this->getReg(UNW_REG_IP),
+ (pint_t)_info.unwind_info, _registers, _isSignalFrame, stage2);
}
#endif
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
bool getInfoFromCompactEncodingSection(pint_t pc,
const UnwindInfoSections §s);
- int stepWithCompactEncoding() {
- #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+ int stepWithCompactEncoding(bool stage2 = false) {
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
if ( compactSaysUseDwarf() )
- return stepWithDwarfFDE();
- #endif
+ return stepWithDwarfFDE(stage2);
+#endif
R dummy;
return stepWithCompactEncoding(dummy);
}
}
#endif
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+ int stepWithCompactEncoding(Registers_loongarch &) { return UNW_EINVAL; }
+#endif
+
#if defined(_LIBUNWIND_TARGET_SPARC)
int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
#endif
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+ int stepWithCompactEncoding(Registers_sparc64 &) { return UNW_EINVAL; }
+#endif
+
#if defined (_LIBUNWIND_TARGET_RISCV)
int stepWithCompactEncoding(Registers_riscv &) {
return UNW_EINVAL;
}
#endif
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+ bool compactSaysUseDwarf(Registers_loongarch &, uint32_t *) const {
+ return true;
+ }
+#endif
+
#if defined(_LIBUNWIND_TARGET_SPARC)
bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
#endif
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+ bool compactSaysUseDwarf(Registers_sparc64 &, uint32_t *) const {
+ return true;
+ }
+#endif
+
#if defined (_LIBUNWIND_TARGET_RISCV)
bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const {
return true;
}
#endif
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+ compact_unwind_encoding_t dwarfEncoding(Registers_loongarch &) const {
+ return 0;
+ }
+#endif
+
#if defined(_LIBUNWIND_TARGET_SPARC)
compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
#endif
-#if defined (_LIBUNWIND_TARGET_SPARC64)
+#if defined(_LIBUNWIND_TARGET_SPARC64)
compact_unwind_encoding_t dwarfEncoding(Registers_sparc64 &) const {
return 0;
}
}
#endif
+#if defined (_LIBUNWIND_TARGET_S390X)
+ compact_unwind_encoding_t dwarfEncoding(Registers_s390x &) const {
+ return 0;
+ }
+#endif
+
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
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(reinterpret_cast<pint_t>(this->getReg(UNW_REG_IP)),
+ reinterpret_cast<tbtable *>(_info.unwind_info),
+ _registers, _isSignalFrame);
+ }
+#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
A &_addressSpace;
R _registers;
unw_proc_info_t _info;
bool _unwindInfoMissing;
bool _isSignalFrame;
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
bool _isSigReturn = false;
#endif
};
}
#endif
+#ifdef _AIX
+template <typename A, typename R>
+uintptr_t UnwindCursor<A, R>::getDataRelBase() {
+ return reinterpret_cast<uintptr_t>(_info.extra);
+}
+#endif
+
template <typename A, typename R>
const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
return _registers.getRegisterName(regNum);
_info.handler = 0;
}
}
-#elif defined(_LIBUNWIND_TARGET_ARM)
- _info.end_ip = _info.start_ip + unwindEntry->FunctionLength;
- _info.lsda = 0; // FIXME
- _info.handler = 0; // FIXME
#endif
setLastPC(pc);
return true;
}
#endif
+#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+// Masks for traceback table field xtbtable.
+enum xTBTableMask : uint8_t {
+ reservedBit = 0x02, // The traceback table was incorrectly generated if set
+ // (see comments in function getInfoFromTBTable().
+ ehInfoBit = 0x08 // Exception handling info is present if set
+};
+
+enum frameType : unw_word_t {
+ frameWithXLEHStateTable = 0,
+ frameWithEHInfo = 1
+};
+
+extern "C" {
+typedef _Unwind_Reason_Code __xlcxx_personality_v0_t(int, _Unwind_Action,
+ uint64_t,
+ _Unwind_Exception *,
+ struct _Unwind_Context *);
+__attribute__((__weak__)) __xlcxx_personality_v0_t __xlcxx_personality_v0;
+}
+
+static __xlcxx_personality_v0_t *xlcPersonalityV0;
+static RWMutex xlcPersonalityV0InitLock;
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromTBTable(pint_t pc, R ®isters) {
+ uint32_t *p = reinterpret_cast<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 = reinterpret_cast<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,
+ reinterpret_cast<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 = reinterpret_cast<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 =
+ reinterpret_cast<unw_word_t>(TBTable) - *p - sizeof(uint32_t);
+ unw_word_t end_ip = reinterpret_cast<unw_word_t>(TBTable);
+ ++p;
+
+ _LIBUNWIND_TRACE_UNWINDING("start_ip=%p, end_ip=%p\n",
+ reinterpret_cast<void *>(start_ip),
+ reinterpret_cast<void *>(end_ip));
+
+ // Skip field hand_mask if it exists.
+ if (TBTable->tb.int_hndl)
+ ++p;
+
+ unw_word_t lsda = 0;
+ unw_word_t handler = 0;
+ unw_word_t flags = frameType::frameWithXLEHStateTable;
+
+ if (TBTable->tb.lang == TB_CPLUSPLUS && 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 && "libunwind: there must be only one ctl_info entry");
+ ++p;
+ // p points to the offset of the state table into the stack.
+ pint_t stateTableOffset = *p++;
+
+ int framePointerReg;
+
+ // Skip fields name_len and name if exist.
+ if (TBTable->tb.name_present) {
+ const uint16_t name_len = *(reinterpret_cast<uint16_t *>(p));
+ p = reinterpret_cast<uint32_t *>(reinterpret_cast<char *>(p) + name_len +
+ sizeof(uint16_t));
+ }
+
+ if (TBTable->tb.uses_alloca)
+ framePointerReg = *(reinterpret_cast<char *>(p));
+ else
+ framePointerReg = 1; // default frame pointer == SP
+
+ _LIBUNWIND_TRACE_UNWINDING(
+ "framePointerReg=%d, framePointer=%p, "
+ "stateTableOffset=%#lx\n",
+ framePointerReg,
+ reinterpret_cast<void *>(_registers.getRegister(framePointerReg)),
+ stateTableOffset);
+ lsda = _registers.getRegister(framePointerReg) + stateTableOffset;
+
+ // Since the traceback table generated by the legacy XLC++ does not
+ // provide the location of the personality for the state table,
+ // function __xlcxx_personality_v0(), which is the personality for the state
+ // table and is exported from libc++abi, is directly assigned as the
+ // handler here. When a legacy XLC++ frame is encountered, the symbol
+ // is resolved dynamically using dlopen() to avoid hard dependency from
+ // libunwind on libc++abi.
+
+ // Resolve the function pointer to the state table personality if it has
+ // not already.
+ if (xlcPersonalityV0 == NULL) {
+ xlcPersonalityV0InitLock.lock();
+ if (xlcPersonalityV0 == NULL) {
+ // If libc++abi is statically linked in, symbol __xlcxx_personality_v0
+ // has been resolved at the link time.
+ xlcPersonalityV0 = &__xlcxx_personality_v0;
+ if (xlcPersonalityV0 == NULL) {
+ // libc++abi is dynamically linked. Resolve __xlcxx_personality_v0
+ // using dlopen().
+ const char libcxxabi[] = "libc++abi.a(libc++abi.so.1)";
+ void *libHandle;
+ // The AIX dlopen() sets errno to 0 when it is successful, which
+ // clobbers the value of errno from the user code. This is an AIX
+ // bug because according to POSIX it should not set errno to 0. To
+ // workaround before AIX fixes the bug, errno is saved and restored.
+ int saveErrno = errno;
+ libHandle = dlopen(libcxxabi, RTLD_MEMBER | RTLD_NOW);
+ if (libHandle == NULL) {
+ _LIBUNWIND_TRACE_UNWINDING("dlopen() failed with errno=%d\n",
+ errno);
+ assert(0 && "dlopen() failed");
+ }
+ xlcPersonalityV0 = reinterpret_cast<__xlcxx_personality_v0_t *>(
+ dlsym(libHandle, "__xlcxx_personality_v0"));
+ if (xlcPersonalityV0 == NULL) {
+ _LIBUNWIND_TRACE_UNWINDING("dlsym() failed with errno=%d\n", errno);
+ assert(0 && "dlsym() failed");
+ }
+ dlclose(libHandle);
+ errno = saveErrno;
+ }
+ }
+ xlcPersonalityV0InitLock.unlock();
+ }
+ handler = reinterpret_cast<unw_word_t>(xlcPersonalityV0);
+ _LIBUNWIND_TRACE_UNWINDING("State table: LSDA=%p, Personality=%p\n",
+ reinterpret_cast<void *>(lsda),
+ reinterpret_cast<void *>(handler));
+ } else if (TBTable->tb.longtbtable) {
+ // This frame has the traceback table extension. Possible cases are
+ // 1) a C++ frame that has the 'eh_info' structure; 2) a C++ frame that
+ // is not EH aware; or, 3) a frame of other languages. We need to figure out
+ // if the traceback table extension contains the 'eh_info' structure.
+ //
+ // We also need to deal with the complexity arising from some XL compiler
+ // versions use the wrong ordering of 'longtbtable' and 'has_vec' bits
+ // where the 'longtbtable' bit is meant to be the 'has_vec' bit and vice
+ // versa. For frames of code generated by those compilers, the 'longtbtable'
+ // bit may be set but there isn't really a traceback table extension.
+ //
+ // In </usr/include/sys/debug.h>, there is the following definition of
+ // 'struct tbtable_ext'. It is not really a structure but a dummy to
+ // collect the description of optional parts of the traceback table.
+ //
+ // struct tbtable_ext {
+ // ...
+ // char alloca_reg; /* Register for alloca automatic storage */
+ // struct vec_ext vec_ext; /* Vector extension (if has_vec is set) */
+ // unsigned char xtbtable; /* More tbtable fields, if longtbtable is set*/
+ // };
+ //
+ // Depending on how the 'has_vec'/'longtbtable' bit is interpreted, the data
+ // following 'alloca_reg' can be treated either as 'struct vec_ext' or
+ // 'unsigned char xtbtable'. 'xtbtable' bits are defined in
+ // </usr/include/sys/debug.h> as flags. The 7th bit '0x02' is currently
+ // unused and should not be set. 'struct vec_ext' is defined in
+ // </usr/include/sys/debug.h> as follows:
+ //
+ // struct vec_ext {
+ // unsigned vr_saved:6; /* Number of non-volatile vector regs saved
+ // */
+ // /* first register saved is assumed to be */
+ // /* 32 - vr_saved */
+ // unsigned saves_vrsave:1; /* Set if vrsave is saved on the stack */
+ // unsigned has_varargs:1;
+ // ...
+ // };
+ //
+ // Here, the 7th bit is used as 'saves_vrsave'. To determine whether it
+ // is 'struct vec_ext' or 'xtbtable' that follows 'alloca_reg',
+ // we checks if the 7th bit is set or not because 'xtbtable' should
+ // never have the 7th bit set. The 7th bit of 'xtbtable' will be reserved
+ // in the future to make sure the mitigation works. This mitigation
+ // is not 100% bullet proof because 'struct vec_ext' may not always have
+ // 'saves_vrsave' bit set.
+ //
+ // 'reservedBit' is defined in enum 'xTBTableMask' above as the mask for
+ // checking the 7th bit.
+
+ // p points to field name len.
+ uint8_t *charPtr = reinterpret_cast<uint8_t *>(p);
+
+ // Skip fields name_len and name if they exist.
+ if (TBTable->tb.name_present) {
+ const uint16_t name_len = *(reinterpret_cast<uint16_t *>(charPtr));
+ charPtr = charPtr + name_len + sizeof(uint16_t);
+ }
+
+ // Skip field alloc_reg if it exists.
+ if (TBTable->tb.uses_alloca)
+ ++charPtr;
+
+ // Check traceback table bit has_vec. Skip struct vec_ext if it exists.
+ if (TBTable->tb.has_vec)
+ // Note struct vec_ext does exist at this point because whether the
+ // ordering of longtbtable and has_vec bits is correct or not, both
+ // are set.
+ charPtr += sizeof(struct vec_ext);
+
+ // charPtr points to field 'xtbtable'. Check if the EH info is available.
+ // Also check if the reserved bit of the extended traceback table field
+ // 'xtbtable' is set. If it is, the traceback table was incorrectly
+ // generated by an XL compiler that uses the wrong ordering of 'longtbtable'
+ // and 'has_vec' bits and this is in fact 'struct vec_ext'. So skip the
+ // frame.
+ if ((*charPtr & xTBTableMask::ehInfoBit) &&
+ !(*charPtr & xTBTableMask::reservedBit)) {
+ // Mark this frame has the new EH info.
+ flags = frameType::frameWithEHInfo;
+
+ // eh_info is available.
+ charPtr++;
+ // The pointer is 4-byte aligned.
+ if (reinterpret_cast<uintptr_t>(charPtr) % 4)
+ charPtr += 4 - reinterpret_cast<uintptr_t>(charPtr) % 4;
+ uintptr_t *ehInfo =
+ reinterpret_cast<uintptr_t *>(*(reinterpret_cast<uintptr_t *>(
+ registers.getRegister(2) +
+ *(reinterpret_cast<uintptr_t *>(charPtr)))));
+
+ // ehInfo points to structure en_info. The first member is version.
+ // Only version 0 is currently supported.
+ assert(*(reinterpret_cast<uint32_t *>(ehInfo)) == 0 &&
+ "libunwind: 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 = flags;
+ _info.format = 0;
+ _info.unwind_info = reinterpret_cast<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 <typename A, typename R>
+int UnwindCursor<A, R>::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,
+ reinterpret_cast<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 = *(reinterpret_cast<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",
+ reinterpret_cast<void *>(lastStack));
+
+ sigcontext *sigContext = reinterpret_cast<sigcontext *>(
+ reinterpret_cast<char *>(lastStack) + STKMIN);
+ returnAddress = sigContext->sc_jmpbuf.jmp_context.iar;
+
+ _LIBUNWIND_TRACE_UNWINDING("From sigContext=%p, returnAddress=%p\n",
+ reinterpret_cast<void *>(sigContext),
+ reinterpret_cast<void *>(returnAddress));
+
+ if (returnAddress < 0x10000000) {
+ // Try again using STKMINALIGN
+ sigContext = reinterpret_cast<sigcontext *>(
+ reinterpret_cast<char *>(lastStack) + STKMINALIGN);
+ returnAddress = sigContext->sc_jmpbuf.jmp_context.iar;
+ if (returnAddress < 0x10000000) {
+ _LIBUNWIND_TRACE_UNWINDING("Bad returnAddress=%p\n",
+ reinterpret_cast<void *>(returnAddress));
+ return UNW_EBADFRAME;
+ } else {
+ _LIBUNWIND_TRACE_UNWINDING("Tried again using STKMINALIGN: "
+ "sigContext=%p, returnAddress=%p. "
+ "Seems to be a valid address\n",
+ reinterpret_cast<void *>(sigContext),
+ reinterpret_cast<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 = reinterpret_cast<ucontext_t *>(sigContext);
+ if (uContext->__extctx->__extctx_magic == __EXTCTX_MAGIC) {
+ for (int i = 0; i < 32; ++i)
+ newRegisters.setVectorRegister(
+ i + unwPPCV0Index, *(reinterpret_cast<v128 *>(
+ &(uContext->__extctx->__vmx.__vr[i]))));
+ }
+ }
+ } else {
+ // Step up a normal frame.
+ returnAddress = reinterpret_cast<pint_t *>(lastStack)[2];
+
+ _LIBUNWIND_TRACE_UNWINDING("Extract info from lastStack=%p, "
+ "returnAddress=%p\n",
+ reinterpret_cast<void *>(lastStack),
+ reinterpret_cast<void *>(returnAddress));
+ _LIBUNWIND_TRACE_UNWINDING("fpr_regs=%d, gpr_regs=%d, saves_cr=%d\n",
+ TBTable->tb.fpr_saved, TBTable->tb.gpr_saved,
+ TBTable->tb.saves_cr);
+
+ // Restore FP registers.
+ char *ptrToRegs = reinterpret_cast<char *>(lastStack);
+ double *FPRegs = reinterpret_cast<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 = reinterpret_cast<char *>(FPRegs);
+ uintptr_t *GPRegs = reinterpret_cast<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 = reinterpret_cast<char *>(GPRegs);
+
+ // Restore vector registers only if this is a Clang frame. Also
+ // check if traceback table bit has_vec is set. If it is, structure
+ // vec_ext is available.
+ if (_info.flags == frameType::frameWithEHInfo && TBTable->tb.has_vec) {
+
+ // Get to the vec_ext structure to check if vector registers are saved.
+ uint32_t *p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
+
+ // Skip field parminfo if exists.
+ if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
+ ++p;
+
+ // Skip field tb_offset if exists.
+ if (TBTable->tb.has_tboff)
+ ++p;
+
+ // Skip field hand_mask if exists.
+ if (TBTable->tb.int_hndl)
+ ++p;
+
+ // Skip fields ctl_info and ctl_info_disp if exist.
+ if (TBTable->tb.has_ctl) {
+ // Skip field ctl_info.
+ ++p;
+ // Skip field ctl_info_disp.
+ ++p;
+ }
+
+ // Skip fields name_len and name if exist.
+ // p is supposed to point to field name_len now.
+ uint8_t *charPtr = reinterpret_cast<uint8_t *>(p);
+ if (TBTable->tb.name_present) {
+ const uint16_t name_len = *(reinterpret_cast<uint16_t *>(charPtr));
+ charPtr = charPtr + name_len + sizeof(uint16_t);
+ }
+
+ // Skip field alloc_reg if it exists.
+ if (TBTable->tb.uses_alloca)
+ ++charPtr;
+
+ struct vec_ext *vec_ext = reinterpret_cast<struct vec_ext *>(charPtr);
+
+ _LIBUNWIND_TRACE_UNWINDING("vr_saved=%d\n", vec_ext->vr_saved);
+
+ // Restore vector register(s) if saved on the stack.
+ if (vec_ext->vr_saved) {
+ // Saved vector registers are 16-byte aligned.
+ if (reinterpret_cast<uintptr_t>(ptrToRegs) % 16)
+ ptrToRegs -= reinterpret_cast<uintptr_t>(ptrToRegs) % 16;
+ v128 *VecRegs = reinterpret_cast<v128 *>(ptrToRegs - vec_ext->vr_saved *
+ sizeof(v128));
+ for (int i = 0; i < vec_ext->vr_saved; ++i) {
+ newRegisters.setVectorRegister(
+ 32 - 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(
+ *(reinterpret_cast<uint32_t *>(lastStack + sizeof(uintptr_t))));
+ }
+
+ // Restore the SP.
+ newRegisters.setSP(lastStack);
+
+ // The first instruction after return.
+ uint32_t firstInstruction = *(reinterpret_cast<uint32_t *>(returnAddress));
+
+ // Do we need to set the TOC register?
+ _LIBUNWIND_TRACE_UNWINDING(
+ "Current gpr2=%p\n",
+ reinterpret_cast<void *>(newRegisters.getRegister(2)));
+ if (firstInstruction == loadTOCRegInst) {
+ _LIBUNWIND_TRACE_UNWINDING(
+ "Set gpr2=%p from frame\n",
+ reinterpret_cast<void *>(reinterpret_cast<pint_t *>(lastStack)[5]));
+ newRegisters.setRegister(2, reinterpret_cast<pint_t *>(lastStack)[5]);
+ }
+ }
+ _LIBUNWIND_TRACE_UNWINDING("lastStack=%p, returnAddress=%p, pc=%p\n",
+ reinterpret_cast<void *>(lastStack),
+ reinterpret_cast<void *>(returnAddress),
+ reinterpret_cast<void *>(pc));
+
+ // The return address is the address after call site instruction, so
+ // setting IP to that simulates a return.
+ newRegisters.setIP(reinterpret_cast<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 = *(reinterpret_cast<pint_t *>(registers.getSP()));
+
+ // Return address is the address after call site instruction.
+ pint_t nextReturnAddress = reinterpret_cast<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",
+ reinterpret_cast<void *>(nextStack),
+ reinterpret_cast<void *>(nextReturnAddress));
+ isSignalFrame = true;
+ } else {
+ isSignalFrame = false;
+ }
+
+ return UNW_STEP_SUCCESS;
+}
+#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
template <typename A, typename R>
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
_isSigReturn = false;
#endif
// 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;
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) {
}
#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
if (setInfoForSigReturn())
return;
#endif
_unwindInfoMissing = true;
}
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
+ defined(_LIBUNWIND_TARGET_AARCH64)
template <typename A, typename R>
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
// Look for the sigreturn trampoline. The trampoline's body is two
//
// [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+ // The PC might contain an invalid address if the unwind info is bad, so
+ // directly accessing it could cause a segfault. Use process_vm_readv to read
+ // the memory safely instead. process_vm_readv was added in Linux 3.2, and
+ // AArch64 supported was added in Linux 3.7, so the syscall is guaranteed to
+ // be present. Unfortunately, there are Linux AArch64 environments where the
+ // libc wrapper for the syscall might not be present (e.g. Android 5), so call
+ // the syscall directly instead.
+ uint32_t instructions[2];
+ struct iovec local_iov = {&instructions, sizeof instructions};
+ struct iovec remote_iov = {reinterpret_cast<void *>(pc), sizeof instructions};
+ long bytesRead =
+ syscall(SYS_process_vm_readv, getpid(), &local_iov, 1, &remote_iov, 1, 0);
// Look for instructions: mov x8, #0x8b; svc #0x0
- if (_addressSpace.get32(pc) == 0xd2801168 &&
- _addressSpace.get32(pc + 4) == 0xd4000001) {
- _info = {};
- _isSigReturn = true;
- return true;
- }
- return false;
+ if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+ instructions[1] != 0xd4000001)
+ return false;
+
+ _info = {};
+ _info.start_ip = pc;
+ _info.end_ip = pc + 4;
+ _isSigReturn = true;
+ return true;
}
template <typename A, typename R>
for (int i = 0; i <= 30; ++i) {
uint64_t value = _addressSpace.get64(sigctx + kOffsetGprs +
static_cast<pint_t>(i * 8));
- _registers.setRegister(UNW_ARM64_X0 + i, value);
+ _registers.setRegister(UNW_AARCH64_X0 + i, value);
}
_registers.setSP(_addressSpace.get64(sigctx + kOffsetSp));
_registers.setIP(_addressSpace.get64(sigctx + kOffsetPc));
_isSignalFrame = true;
return UNW_STEP_SUCCESS;
}
-#endif // defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
+ // defined(_LIBUNWIND_TARGET_AARCH64)
+
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
+ defined(_LIBUNWIND_TARGET_S390X)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_s390x &) {
+ // Look for the sigreturn trampoline. The trampoline's body is a
+ // specific instruction (see below). Typically the trampoline comes from the
+ // vDSO (i.e. the __kernel_[rt_]sigreturn function). A libc might provide its
+ // own restorer function, though, or user-mode QEMU might write a trampoline
+ // onto the stack.
+ const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+ // The PC might contain an invalid address if the unwind info is bad, so
+ // directly accessing it could cause a segfault. Use process_vm_readv to
+ // read the memory safely instead.
+ uint16_t inst;
+ struct iovec local_iov = {&inst, sizeof inst};
+ struct iovec remote_iov = {reinterpret_cast<void *>(pc), sizeof inst};
+ long bytesRead = process_vm_readv(getpid(), &local_iov, 1, &remote_iov, 1, 0);
+ if (bytesRead == sizeof inst && (inst == 0x0a77 || inst == 0x0aad)) {
+ _info = {};
+ _info.start_ip = pc;
+ _info.end_ip = pc + 2;
+ _isSigReturn = true;
+ return true;
+ }
+ return false;
+}
template <typename A, typename R>
-int UnwindCursor<A, R>::step() {
+int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
+ // Determine current SP.
+ const pint_t sp = static_cast<pint_t>(this->getReg(UNW_REG_SP));
+ // According to the s390x ABI, the CFA is at (incoming) SP + 160.
+ const pint_t cfa = sp + 160;
+
+ // Determine current PC and instruction there (this must be either
+ // a "svc __NR_sigreturn" or "svc __NR_rt_sigreturn").
+ const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+ const uint16_t inst = _addressSpace.get16(pc);
+
+ // Find the addresses of the signo and sigcontext in the frame.
+ pint_t pSigctx = 0;
+ pint_t pSigno = 0;
+
+ // "svc __NR_sigreturn" uses a non-RT signal trampoline frame.
+ if (inst == 0x0a77) {
+ // Layout of a non-RT signal trampoline frame, starting at the CFA:
+ // - 8-byte signal mask
+ // - 8-byte pointer to sigcontext, followed by signo
+ // - 4-byte signo
+ pSigctx = _addressSpace.get64(cfa + 8);
+ pSigno = pSigctx + 344;
+ }
+
+ // "svc __NR_rt_sigreturn" uses a RT signal trampoline frame.
+ if (inst == 0x0aad) {
+ // Layout of a RT signal trampoline frame, starting at the CFA:
+ // - 8-byte retcode (+ alignment)
+ // - 128-byte siginfo struct (starts with signo)
+ // - ucontext struct:
+ // - 8-byte long (uc_flags)
+ // - 8-byte pointer (uc_link)
+ // - 24-byte stack_t
+ // - 8 bytes of padding because sigcontext has 16-byte alignment
+ // - sigcontext/mcontext_t
+ pSigctx = cfa + 8 + 128 + 8 + 8 + 24 + 8;
+ pSigno = cfa + 8;
+ }
+
+ assert(pSigctx != 0);
+ assert(pSigno != 0);
+
+ // Offsets from sigcontext to each register.
+ const pint_t kOffsetPc = 8;
+ const pint_t kOffsetGprs = 16;
+ const pint_t kOffsetFprs = 216;
+
+ // Restore all registers.
+ for (int i = 0; i < 16; ++i) {
+ uint64_t value = _addressSpace.get64(pSigctx + kOffsetGprs +
+ static_cast<pint_t>(i * 8));
+ _registers.setRegister(UNW_S390X_R0 + i, value);
+ }
+ for (int i = 0; i < 16; ++i) {
+ static const int fpr[16] = {
+ UNW_S390X_F0, UNW_S390X_F1, UNW_S390X_F2, UNW_S390X_F3,
+ UNW_S390X_F4, UNW_S390X_F5, UNW_S390X_F6, UNW_S390X_F7,
+ UNW_S390X_F8, UNW_S390X_F9, UNW_S390X_F10, UNW_S390X_F11,
+ UNW_S390X_F12, UNW_S390X_F13, UNW_S390X_F14, UNW_S390X_F15
+ };
+ double value = _addressSpace.getDouble(pSigctx + kOffsetFprs +
+ static_cast<pint_t>(i * 8));
+ _registers.setFloatRegister(fpr[i], value);
+ }
+ _registers.setIP(_addressSpace.get64(pSigctx + kOffsetPc));
+
+ // SIGILL, SIGFPE and SIGTRAP are delivered with psw_addr
+ // after the faulting instruction rather than before it.
+ // Do not set _isSignalFrame in that case.
+ uint32_t signo = _addressSpace.get32(pSigno);
+ _isSignalFrame = (signo != 4 && signo != 5 && signo != 8);
+
+ return UNW_STEP_SUCCESS;
+}
+#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
+ // defined(_LIBUNWIND_TARGET_S390X)
+
+template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
+ (void)stage2;
// Bottom of stack is defined is when unwind info cannot be found.
if (_unwindInfoMissing)
return UNW_STEP_END;
// Use unwinding info to modify register set as if function returned.
int result;
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
if (_isSigReturn) {
result = this->stepThroughSigReturn();
} else
#endif
{
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
- result = this->stepWithCompactEncoding();
+ result = this->stepWithCompactEncoding(stage2);
#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();
+ result = this->stepWithDwarfFDE(stage2);
#elif defined(_LIBUNWIND_ARM_EHABI)
result = this->stepWithEHABI();
#else
buf, bufLen, offset);
}
+#if defined(_LIBUNWIND_USE_CET)
+extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) {
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->get_registers();
+}
+#endif
} // namespace libunwind
#endif // __UNWINDCURSOR_HPP__
-//===-------------------- UnwindRegistersRestore.S ------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#include "assembly.h"
+#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+#define FROM_16_TO_31 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+
+#define FROM_0_TO_31 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+#define FROM_32_TO_63 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
+
+#if defined(_AIX)
+ .toc
+#else
.text
+#endif
#if !defined(__USING_SJLJ_EXCEPTIONS__)
# + return address +
# +-----------------------+ <-- SP
# + +
+
+ _LIBUNWIND_CET_ENDBR
movl 4(%esp), %eax
# set up eax and ret on new stack location
movl 28(%eax), %edx # edx holds new stack pointer
# skip ss
# skip eflags
pop %eax # eax was already pushed on new stack
- ret # eip was already pushed on new stack
+ pop %ecx
+ jmp *%ecx
# skip cs
# skip ds
# skip es
# On entry, thread_state pointer is in rdi
#endif
+ _LIBUNWIND_CET_ENDBR
movq 56(%rdi), %rax # rax holds new stack pointer
subq $16, %rax
movq %rax, 56(%rdi)
#endif
movq 56(%rdi), %rsp # cut back rsp to new location
pop %rdi # rdi was saved here earlier
- ret # rip was saved here
+ pop %rcx
+ jmpq *%rcx
#elif defined(__powerpc64__)
addi 4, 3, PPC64_OFFS_FP
// load VS register
+#ifdef __LITTLE_ENDIAN__
+// For little-endian targets, we need a swap since lxvd2x will load the register
+// in the incorrect doubleword order.
+// FIXME: when supporting targets older than Power9 on LE is no longer required,
+// this can be changed to simply `lxv n, (16 * n)(4)`.
#define PPC64_LVS(n) \
lxvd2x n, 0, 4 ;\
+ xxswapd n, n ;\
addi 4, 4, 16
+#else
+#define PPC64_LVS(n) \
+ lxvd2x n, 0, 4 ;\
+ addi 4, 4, 16
+#endif
// restore the first 32 VS regs (and also all floating point regs)
PPC64_LVS(0)
PPC64_LVS(30)
PPC64_LVS(31)
- // use VRSAVE to conditionally restore the remaining VS regs,
- // that are where the V regs are mapped
+#ifdef __LITTLE_ENDIAN__
+#define PPC64_CLVS_RESTORE(n) \
+ addi 4, 3, PPC64_OFFS_FP + n * 16 ;\
+ lxvd2x n, 0, 4 ;\
+ xxswapd n, n
+#else
+#define PPC64_CLVS_RESTORE(n) \
+ addi 4, 3, PPC64_OFFS_FP + n * 16 ;\
+ lxvd2x n, 0, 4
+#endif
+#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 5, PPC64_OFFS_VRSAVE(3) // test VRsave
cmpwi 5, 0
beq Lnovec
// conditionally load VS
-#define PPC64_CLVS_BOTTOM(n) \
- beq Ldone##n ;\
- addi 4, 3, PPC64_OFFS_FP + n * 16 ;\
- lxvd2x n, 0, 4 ;\
+#define PPC64_CLVSl(n) \
+ andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n)) ;\
+ beq Ldone##n ;\
+ PPC64_CLVS_RESTORE(n) ;\
+Ldone##n:
+
+#define PPC64_CLVSh(n) \
+ andi. 0, 5, (1 PPC_LEFT_SHIFT(63-n)) ;\
+ beq Ldone##n ;\
+ PPC64_CLVS_RESTORE(n) ;\
Ldone##n:
-#define PPC64_CLVSl(n) \
- andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n)) ;\
-PPC64_CLVS_BOTTOM(n)
+#else
-#define PPC64_CLVSh(n) \
- andi. 0, 5, (1 PPC_LEFT_SHIFT(63-n)) ;\
-PPC64_CLVS_BOTTOM(n)
+#define PPC64_CLVSl(n) PPC64_CLVS_RESTORE(n)
+#define PPC64_CLVSh(n) PPC64_CLVS_RESTORE(n)
+
+#endif // !defined(_AIX)
PPC64_CLVSl(32)
PPC64_CLVSl(33)
PPC64_LF(31)
#if defined(__ALTIVEC__)
- // restore vector registers if any are in use
+
+#define PPC64_CLV_UNALIGNED_RESTORE(n) \
+ ld 0, (PPC64_OFFS_V + n * 16)(3) ;\
+ std 0, 0(4) ;\
+ ld 0, (PPC64_OFFS_V + n * 16 + 8)(3) ;\
+ std 0, 8(4) ;\
+ lvx n, 0, 4
+
+#if !defined(_AIX)
+ // restore vector registers if any are in use. In the AIX ABI, VRSAVE is
+ // not used.
ld 5, PPC64_OFFS_VRSAVE(3) // test VRsave
cmpwi 5, 0
beq Lnovec
- subi 4, 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_UNALIGNEDl(n) \
+ andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n)) ;\
+ beq Ldone##n ;\
+ PPC64_CLV_UNALIGNED_RESTORE(n) ;\
+Ldone ## n:
-#define PPC64_CLV_UNALIGNED_BOTTOM(n) \
- beq Ldone##n ;\
- ld 0, (PPC64_OFFS_V + n * 16)(3) ;\
- std 0, 0(4) ;\
- ld 0, (PPC64_OFFS_V + n * 16 + 8)(3) ;\
- std 0, 8(4) ;\
- lvx n, 0, 4 ;\
+#define PPC64_CLV_UNALIGNEDh(n) \
+ andi. 0, 5, (1 PPC_LEFT_SHIFT(31-n)) ;\
+ beq Ldone##n ;\
+ PPC64_CLV_UNALIGNED_RESTORE(n) ;\
Ldone ## n:
-#define PPC64_CLV_UNALIGNEDl(n) \
- andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n)) ;\
-PPC64_CLV_UNALIGNED_BOTTOM(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. 0, 5, (1 PPC_LEFT_SHIFT(31-n)) ;\
-PPC64_CLV_UNALIGNED_BOTTOM(n)
+#endif // !defined(_AIX)
+
+ subi 4, 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
PPC64_CLV_UNALIGNEDl(0)
PPC64_CLV_UNALIGNEDl(1)
ld 0, PPC64_OFFS_SRR0(3)
mtctr 0
+#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 0, (8 * (3 + 2))(3)
+#else
PPC64_LR(0)
+#endif
PPC64_LR(5)
PPC64_LR(4)
PPC64_LR(1)
+#if defined(_AIX)
+ mr 3, 0
+#else
PPC64_LR(3)
+#endif
bctr
-#elif defined(__ppc__)
+#elif defined(__powerpc__)
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
//
// thread_state pointer is in r3
//
- // restore integral registerrs
+ // restore integral registers
// skip r0 for now
// skip r1 for now
lwz 2, 16(3)
#endif
#if defined(__ALTIVEC__)
- // restore vector registers if any are in use
+
+#define LOAD_VECTOR_RESTORE(_index) \
+ lwz 0, 424+_index*16(3) SEPARATOR \
+ stw 0, 0(4) SEPARATOR \
+ lwz 0, 424+_index*16+4(3) SEPARATOR \
+ stw 0, 4(4) SEPARATOR \
+ lwz 0, 424+_index*16+8(3) SEPARATOR \
+ stw 0, 8(4) SEPARATOR \
+ lwz 0, 424+_index*16+12(3) SEPARATOR \
+ stw 0, 12(4) SEPARATOR \
+ lvx _index, 0, 4
+
+#if !defined(_AIX)
+ // restore vector registers if any are in use. In the AIX ABI, VRSAVE
+ // is not used.
lwz 5, 156(3) // test VRsave
cmpwi 5, 0
beq Lnovec
- subi 4, 1, 16
- rlwinm 4, 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_UNALIGNEDl(_index) \
- andis. 0, 5, (1 PPC_LEFT_SHIFT(15-_index)) SEPARATOR \
- beq Ldone ## _index SEPARATOR \
- lwz 0, 424+_index*16(3) SEPARATOR \
- stw 0, 0(%r4) SEPARATOR \
- lwz 0, 424+_index*16+4(%r3) SEPARATOR \
- stw 0, 4(%r4) SEPARATOR \
- lwz 0, 424+_index*16+8(%r3) SEPARATOR \
- stw 0, 8(%r4) SEPARATOR \
- lwz 0, 424+_index*16+12(%r3) SEPARATOR \
- stw 0, 12(%r4) SEPARATOR \
- lvx _index, 0, 4 SEPARATOR \
+#define LOAD_VECTOR_UNALIGNEDl(_index) \
+ andis. 0, 5, (1 PPC_LEFT_SHIFT(15-_index)) SEPARATOR \
+ beq Ldone ## _index SEPARATOR \
+ LOAD_VECTOR_RESTORE(_index) SEPARATOR \
Ldone ## _index:
-#define LOAD_VECTOR_UNALIGNEDh(_index) \
- andi. 0, 5, (1 PPC_LEFT_SHIFT(31-_index)) SEPARATOR \
- beq Ldone ## _index SEPARATOR \
- lwz 0, 424+_index*16(3) SEPARATOR \
- stw 0, 0(4) SEPARATOR \
- lwz 0, 424+_index*16+4(3) SEPARATOR \
- stw 0, 4(4) SEPARATOR \
- lwz 0, 424+_index*16+8(3) SEPARATOR \
- stw 0, 8(%r4) SEPARATOR \
- lwz 0, 424+_index*16+12(3) SEPARATOR \
- stw 0, 12(4) SEPARATOR \
- lvx _index, 0, 4 SEPARATOR \
+#define LOAD_VECTOR_UNALIGNEDh(_index) \
+ andi. 0, 5, (1 PPC_LEFT_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)
+
+ subi 4, 1, 16
+ rlwinm 4, 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
LOAD_VECTOR_UNALIGNEDl(0)
LOAD_VECTOR_UNALIGNEDl(1)
ldr sp, [lr, #52]
ldr lr, [lr, #60] @ restore pc into lr
#endif
+#if defined(__ARM_FEATURE_BTI_DEFAULT) && !defined(__ARM_ARCH_ISA_ARM)
+ // 'bx' is not BTI setting when used with lr, therefore r12 is used instead
+ mov r12, lr
+ JMP(r12)
+#else
JMP(lr)
+#endif
@
@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
l.lwz r30,120(r3)
l.lwz r31,124(r3)
+ # load new pc into ra
+ l.lwz r9, 128(r3)
+
# at last, restore r3
l.lwz r3, 12(r3)
- # load new pc into ra
- l.lwz r9, 128(r3)
# jump to pc
l.jr r9
l.nop
.set noreorder
.set nomacro
#ifdef __mips_hard_float
- ldc1 $f0, (8 * 35)($4)
- ldc1 $f1, (8 * 36)($4)
- ldc1 $f2, (8 * 37)($4)
- ldc1 $f3, (8 * 38)($4)
- ldc1 $f4, (8 * 39)($4)
- ldc1 $f5, (8 * 40)($4)
- ldc1 $f6, (8 * 41)($4)
- ldc1 $f7, (8 * 42)($4)
- ldc1 $f8, (8 * 43)($4)
- ldc1 $f9, (8 * 44)($4)
- ldc1 $f10, (8 * 45)($4)
- ldc1 $f11, (8 * 46)($4)
- ldc1 $f12, (8 * 47)($4)
- ldc1 $f13, (8 * 48)($4)
- ldc1 $f14, (8 * 49)($4)
- ldc1 $f15, (8 * 50)($4)
- ldc1 $f16, (8 * 51)($4)
- ldc1 $f17, (8 * 52)($4)
- ldc1 $f18, (8 * 53)($4)
- ldc1 $f19, (8 * 54)($4)
- ldc1 $f20, (8 * 55)($4)
- ldc1 $f21, (8 * 56)($4)
- ldc1 $f22, (8 * 57)($4)
- ldc1 $f23, (8 * 58)($4)
- ldc1 $f24, (8 * 59)($4)
- ldc1 $f25, (8 * 60)($4)
- ldc1 $f26, (8 * 61)($4)
- ldc1 $f27, (8 * 62)($4)
- ldc1 $f28, (8 * 63)($4)
- ldc1 $f29, (8 * 64)($4)
- ldc1 $f30, (8 * 65)($4)
- ldc1 $f31, (8 * 66)($4)
+ .irp i,FROM_0_TO_31
+ ldc1 $f\i, (280+8*\i)($4)
+ .endr
#endif
// restore hi and lo
ld $8, (8 * 33)($4)
ld $2, (8 * 2)($4)
ld $3, (8 * 3)($4)
// skip a0 for now
- ld $5, (8 * 5)($4)
- ld $6, (8 * 6)($4)
- ld $7, (8 * 7)($4)
- ld $8, (8 * 8)($4)
- ld $9, (8 * 9)($4)
- ld $10, (8 * 10)($4)
- ld $11, (8 * 11)($4)
- ld $12, (8 * 12)($4)
- ld $13, (8 * 13)($4)
- ld $14, (8 * 14)($4)
- ld $15, (8 * 15)($4)
- ld $16, (8 * 16)($4)
- ld $17, (8 * 17)($4)
- ld $18, (8 * 18)($4)
- ld $19, (8 * 19)($4)
- ld $20, (8 * 20)($4)
- ld $21, (8 * 21)($4)
- ld $22, (8 * 22)($4)
- ld $23, (8 * 23)($4)
- ld $24, (8 * 24)($4)
- ld $25, (8 * 25)($4)
- ld $26, (8 * 26)($4)
- ld $27, (8 * 27)($4)
- ld $28, (8 * 28)($4)
- ld $29, (8 * 29)($4)
- ld $30, (8 * 30)($4)
+ .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
+ ld $\i, (8 * \i)($4)
+ .endr
// load new pc into ra
ld $31, (8 * 32)($4)
// jump to ra, load a0 in the delay slot
#elif defined(__sparc__) && defined(__arch64__)
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv)
-#
-# void libunwind::Registers_sparc64::jumpto()
-#
-# On entry:
-# thread_state pointer is in %o0
-#
+//
+// void libunwind::Registers_sparc64::jumpto()
+//
+// On entry:
+// thread_state pointer is in %o0
+//
+ .register %g2, #scratch
+ .register %g3, #scratch
+ .register %g6, #scratch
+ .register %g7, #scratch
flushw
ldx [%o0 + 0x08], %g1
ldx [%o0 + 0x10], %g2
ldx [%o0 + 0xe8], %i5
ldx [%o0 + 0xf0], %i6
ldx [%o0 + 0xf8], %i7
- jmpl %o7 + 8, %g0
+ jmp %o7
ldx [%o0 + 0x40], %o0
#elif defined(__sparc__)
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
# if defined(__riscv_flen)
- FLOAD f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0)
- FLOAD f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0)
- FLOAD f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0)
- FLOAD f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0)
- FLOAD f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0)
- FLOAD f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0)
- FLOAD f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0)
- FLOAD f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0)
- FLOAD f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0)
- FLOAD f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0)
- FLOAD f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0)
- FLOAD f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0)
- FLOAD f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0)
- FLOAD f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0)
- FLOAD f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0)
- FLOAD f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0)
- FLOAD f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0)
- FLOAD f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0)
- FLOAD f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0)
- FLOAD f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0)
- FLOAD f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0)
- FLOAD f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0)
- FLOAD f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0)
- FLOAD f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0)
- FLOAD f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0)
- FLOAD f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0)
- FLOAD f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0)
- FLOAD f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0)
- FLOAD f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0)
- FLOAD f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0)
- FLOAD f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0)
- FLOAD f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0)
+ .irp i,FROM_0_TO_31
+ FLOAD f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
+ .endr
# endif
// x0 is zero
ILOAD x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra
- ILOAD x2, (RISCV_ISIZE * 2)(a0)
- ILOAD x3, (RISCV_ISIZE * 3)(a0)
- ILOAD x4, (RISCV_ISIZE * 4)(a0)
- ILOAD x5, (RISCV_ISIZE * 5)(a0)
- ILOAD x6, (RISCV_ISIZE * 6)(a0)
- ILOAD x7, (RISCV_ISIZE * 7)(a0)
- ILOAD x8, (RISCV_ISIZE * 8)(a0)
- ILOAD x9, (RISCV_ISIZE * 9)(a0)
+ .irp i,2,3,4,5,6,7,8,9
+ ILOAD x\i, (RISCV_ISIZE * \i)(a0)
+ .endr
// skip a0 for now
- ILOAD x11, (RISCV_ISIZE * 11)(a0)
- ILOAD x12, (RISCV_ISIZE * 12)(a0)
- ILOAD x13, (RISCV_ISIZE * 13)(a0)
- ILOAD x14, (RISCV_ISIZE * 14)(a0)
- ILOAD x15, (RISCV_ISIZE * 15)(a0)
- ILOAD x16, (RISCV_ISIZE * 16)(a0)
- ILOAD x17, (RISCV_ISIZE * 17)(a0)
- ILOAD x18, (RISCV_ISIZE * 18)(a0)
- ILOAD x19, (RISCV_ISIZE * 19)(a0)
- ILOAD x20, (RISCV_ISIZE * 20)(a0)
- ILOAD x21, (RISCV_ISIZE * 21)(a0)
- ILOAD x22, (RISCV_ISIZE * 22)(a0)
- ILOAD x23, (RISCV_ISIZE * 23)(a0)
- ILOAD x24, (RISCV_ISIZE * 24)(a0)
- ILOAD x25, (RISCV_ISIZE * 25)(a0)
- ILOAD x26, (RISCV_ISIZE * 26)(a0)
- ILOAD x27, (RISCV_ISIZE * 27)(a0)
- ILOAD x28, (RISCV_ISIZE * 28)(a0)
- ILOAD x29, (RISCV_ISIZE * 29)(a0)
- ILOAD x30, (RISCV_ISIZE * 30)(a0)
- ILOAD x31, (RISCV_ISIZE * 31)(a0)
+ .irp i,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ ILOAD x\i, (RISCV_ISIZE * \i)(a0)
+ .endr
ILOAD x10, (RISCV_ISIZE * 10)(a0) // restore a0
ret // jump to ra
+#elif defined(__s390x__)
+
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
+//
+// void libunwind::Registers_s390x::jumpto()
+//
+// On entry:
+// thread_state pointer is in r2
+//
+
+ // Skip PSWM, but load PSWA into r1
+ lg %r1, 8(%r2)
+
+ // Restore FPRs
+ .irp i,FROM_0_TO_15
+ ld %f\i, (144+8*\i)(%r2)
+ .endr
+
+ // Restore GPRs - skipping %r0 and %r1
+ lmg %r2, %r15, 32(%r2)
+
+ // Return to PSWA (was loaded into %r1 above)
+ br %r1
+
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+//
+// void libunwind::Registers_loongarch::jumpto()
+//
+// On entry:
+// thread_state pointer is in $a0($r4)
+//
+ .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
+# if __loongarch_frlen == 64
+ .irp i,FROM_0_TO_31
+ fld.d $f\i, $a0, (8 * 33 + 8 * \i)
+ .endr
+# endif
+
+ // $r0 is zero
+ .irp i,1,2,3
+ ld.d $r\i, $a0, (8 * \i)
+ .endr
+ // skip $a0 for now
+ .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ ld.d $r\i, $a0, (8 * \i)
+ .endr
+
+ ld.d $ra, $a0, (8 * 32) // load new pc into $ra
+ ld.d $a0, $a0, (8 * 4) // restore $a0 last
+
+ jr $ra
+
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
-//===------------------------ UnwindRegistersSave.S -----------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#include "assembly.h"
+#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+#define FROM_16_TO_31 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+
+#define FROM_0_TO_31 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+#define FROM_32_TO_63 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
+
+#if defined(_AIX)
+ .toc
+#else
.text
+#endif
#if !defined(__USING_SJLJ_EXCEPTIONS__)
# + +
#
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+
+ _LIBUNWIND_CET_ENDBR
push %eax
movl 8(%esp), %eax
movl %ebx, 4(%eax)
#define TMP %rsi
#endif
+ _LIBUNWIND_CET_ENDBR
movq %rax, (PTR)
movq %rbx, 8(PTR)
movq %rcx, 16(PTR)
.set noat
.set noreorder
.set nomacro
- sd $1, (8 * 1)($4)
- sd $2, (8 * 2)($4)
- sd $3, (8 * 3)($4)
- sd $4, (8 * 4)($4)
- sd $5, (8 * 5)($4)
- sd $6, (8 * 6)($4)
- sd $7, (8 * 7)($4)
- sd $8, (8 * 8)($4)
- sd $9, (8 * 9)($4)
- sd $10, (8 * 10)($4)
- sd $11, (8 * 11)($4)
- sd $12, (8 * 12)($4)
- sd $13, (8 * 13)($4)
- sd $14, (8 * 14)($4)
- sd $15, (8 * 15)($4)
- sd $16, (8 * 16)($4)
- sd $17, (8 * 17)($4)
- sd $18, (8 * 18)($4)
- sd $19, (8 * 19)($4)
- sd $20, (8 * 20)($4)
- sd $21, (8 * 21)($4)
- sd $22, (8 * 22)($4)
- sd $23, (8 * 23)($4)
- sd $24, (8 * 24)($4)
- sd $25, (8 * 25)($4)
- sd $26, (8 * 26)($4)
- sd $27, (8 * 27)($4)
- sd $28, (8 * 28)($4)
- sd $29, (8 * 29)($4)
- sd $30, (8 * 30)($4)
- sd $31, (8 * 31)($4)
+ .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ sd $\i, (8 * \i)($4)
+ .endr
# Store return address to pc
sd $31, (8 * 32)($4)
# hi and lo
mflo $8
sd $8, (8 * 34)($4)
#ifdef __mips_hard_float
- sdc1 $f0, (8 * 35)($4)
- sdc1 $f1, (8 * 36)($4)
- sdc1 $f2, (8 * 37)($4)
- sdc1 $f3, (8 * 38)($4)
- sdc1 $f4, (8 * 39)($4)
- sdc1 $f5, (8 * 40)($4)
- sdc1 $f6, (8 * 41)($4)
- sdc1 $f7, (8 * 42)($4)
- sdc1 $f8, (8 * 43)($4)
- sdc1 $f9, (8 * 44)($4)
- sdc1 $f10, (8 * 45)($4)
- sdc1 $f11, (8 * 46)($4)
- sdc1 $f12, (8 * 47)($4)
- sdc1 $f13, (8 * 48)($4)
- sdc1 $f14, (8 * 49)($4)
- sdc1 $f15, (8 * 50)($4)
- sdc1 $f16, (8 * 51)($4)
- sdc1 $f17, (8 * 52)($4)
- sdc1 $f18, (8 * 53)($4)
- sdc1 $f19, (8 * 54)($4)
- sdc1 $f20, (8 * 55)($4)
- sdc1 $f21, (8 * 56)($4)
- sdc1 $f22, (8 * 57)($4)
- sdc1 $f23, (8 * 58)($4)
- sdc1 $f24, (8 * 59)($4)
- sdc1 $f25, (8 * 60)($4)
- sdc1 $f26, (8 * 61)($4)
- sdc1 $f27, (8 * 62)($4)
- sdc1 $f28, (8 * 63)($4)
- sdc1 $f29, (8 * 64)($4)
- sdc1 $f30, (8 * 65)($4)
- sdc1 $f31, (8 * 66)($4)
+ .irp i,FROM_0_TO_31
+ sdc1 $f\i, (280+8*\i)($4)
+ .endr
#endif
jr $31
# return UNW_ESUCCESS
// On entry:
// thread_state pointer is in r3
//
+#if defined(_AIX)
+DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(__unw_getcontext, unw_getcontext)
+#else
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
-
+#endif
// store register (GPR)
#define PPC64_STR(n) \
std n, (8 * (n + 2))(3)
addi 4, 3, PPC64_OFFS_FP
// store VS register
+#ifdef __LITTLE_ENDIAN__
+// For little-endian targets, we need a swap since stxvd2x will store the
+// register in the incorrect doubleword order.
+// FIXME: when supporting targets older than Power9 on LE is no longer required
+// this can be changed to simply `stxv n, 16 * n(4)`.
+#define PPC64_STVS(n) \
+ xxswapd n, n ;\
+ stxvd2x n, 0, 4 ;\
+ addi 4, 4, 16
+#else
#define PPC64_STVS(n) \
stxvd2x n, 0, 4 ;\
addi 4, 4, 16
+#endif
PPC64_STVS(0)
PPC64_STVS(1)
blr
-#elif defined(__ppc__)
+#elif defined(__powerpc__)
//
// extern int unw_getcontext(unw_context_t* thread_state)
// On entry:
// thread_state pointer is in r3
//
+#if defined(_AIX)
+DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(__unw_getcontext, unw_getcontext)
+#else
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+#endif
stw 0, 8(3)
mflr 0
stw 0, 0(3) // store lr as ssr0
l.sw 132(r3), r0
#elif defined(__hexagon__)
-
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
#elif defined(__sparc__) && defined(__arch64__)
#
-# extern int unw_getcontext(unw_context_t* thread_state)
+# extern int __unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in %o0
#
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+ .register %g2, #scratch
+ .register %g3, #scratch
+ .register %g6, #scratch
+ .register %g7, #scratch
stx %g1, [%o0 + 0x08]
stx %g2, [%o0 + 0x10]
stx %g3, [%o0 + 0x18]
stx %i7, [%o0 + 0xf8]
# save StackGhost cookie
- add %i7, %g0, %g4
+ mov %i7, %g4
save %sp, -176, %sp
# register window flush necessary even without StackGhost
flushw
restore
ldx [%sp + 2047 + 0x78], %g5
xor %g4, %g5, %g4
+ stx %g4, [%o0 + 0x100]
retl
- stx %g4, [%o0 + 0x100]
+ # return UNW_ESUCCESS
+ clr %o0
#elif defined(__sparc__)
#
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
ISTORE x1, (RISCV_ISIZE * 0)(a0) // store ra as pc
- ISTORE x1, (RISCV_ISIZE * 1)(a0)
- ISTORE x2, (RISCV_ISIZE * 2)(a0)
- ISTORE x3, (RISCV_ISIZE * 3)(a0)
- ISTORE x4, (RISCV_ISIZE * 4)(a0)
- ISTORE x5, (RISCV_ISIZE * 5)(a0)
- ISTORE x6, (RISCV_ISIZE * 6)(a0)
- ISTORE x7, (RISCV_ISIZE * 7)(a0)
- ISTORE x8, (RISCV_ISIZE * 8)(a0)
- ISTORE x9, (RISCV_ISIZE * 9)(a0)
- ISTORE x10, (RISCV_ISIZE * 10)(a0)
- ISTORE x11, (RISCV_ISIZE * 11)(a0)
- ISTORE x12, (RISCV_ISIZE * 12)(a0)
- ISTORE x13, (RISCV_ISIZE * 13)(a0)
- ISTORE x14, (RISCV_ISIZE * 14)(a0)
- ISTORE x15, (RISCV_ISIZE * 15)(a0)
- ISTORE x16, (RISCV_ISIZE * 16)(a0)
- ISTORE x17, (RISCV_ISIZE * 17)(a0)
- ISTORE x18, (RISCV_ISIZE * 18)(a0)
- ISTORE x19, (RISCV_ISIZE * 19)(a0)
- ISTORE x20, (RISCV_ISIZE * 20)(a0)
- ISTORE x21, (RISCV_ISIZE * 21)(a0)
- ISTORE x22, (RISCV_ISIZE * 22)(a0)
- ISTORE x23, (RISCV_ISIZE * 23)(a0)
- ISTORE x24, (RISCV_ISIZE * 24)(a0)
- ISTORE x25, (RISCV_ISIZE * 25)(a0)
- ISTORE x26, (RISCV_ISIZE * 26)(a0)
- ISTORE x27, (RISCV_ISIZE * 27)(a0)
- ISTORE x28, (RISCV_ISIZE * 28)(a0)
- ISTORE x29, (RISCV_ISIZE * 29)(a0)
- ISTORE x30, (RISCV_ISIZE * 30)(a0)
- ISTORE x31, (RISCV_ISIZE * 31)(a0)
+ .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ ISTORE x\i, (RISCV_ISIZE * \i)(a0)
+ .endr
# if defined(__riscv_flen)
- FSTORE f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0)
- FSTORE f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0)
- FSTORE f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0)
- FSTORE f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0)
- FSTORE f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0)
- FSTORE f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0)
- FSTORE f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0)
- FSTORE f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0)
- FSTORE f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0)
- FSTORE f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0)
- FSTORE f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0)
- FSTORE f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0)
- FSTORE f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0)
- FSTORE f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0)
- FSTORE f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0)
- FSTORE f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0)
- FSTORE f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0)
- FSTORE f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0)
- FSTORE f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0)
- FSTORE f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0)
- FSTORE f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0)
- FSTORE f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0)
- FSTORE f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0)
- FSTORE f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0)
- FSTORE f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0)
- FSTORE f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0)
- FSTORE f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0)
- FSTORE f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0)
- FSTORE f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0)
- FSTORE f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0)
- FSTORE f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0)
- FSTORE f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0)
+ .irp i,FROM_0_TO_31
+ FSTORE f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
+ .endr
# endif
li a0, 0 // return UNW_ESUCCESS
ret // jump to ra
+
+#elif defined(__s390x__)
+
+//
+// extern int __unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+// thread_state pointer is in r2
+//
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+
+ // Save GPRs
+ stmg %r0, %r15, 16(%r2)
+
+ // Save PSWM
+ epsw %r0, %r1
+ stm %r0, %r1, 0(%r2)
+
+ // Store return address as PSWA
+ stg %r14, 8(%r2)
+
+ // Save FPRs
+ .irp i,FROM_0_TO_15
+ std %f\i, (144+8*\i)(%r2)
+ .endr
+
+ // Return UNW_ESUCCESS
+ lghi %r2, 0
+ br %r14
+
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in $a0($r4)
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+ .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ st.d $r\i, $a0, (8*\i)
+ .endr
+ st.d $r1, $a0, (8 * 32) // store $ra to pc
+
+# if __loongarch_frlen == 64
+ .irp i,FROM_0_TO_31
+ fst.d $f\i, $a0, (8 * 33 + 8 * \i)
+ .endr
+# endif
+
+ move $a0, $zero // UNW_ESUCCESS
+ jr $ra
+
#endif
WEAK_ALIAS(__unw_getcontext, unw_getcontext)
#ifndef UNWIND_ASSEMBLY_H
#define UNWIND_ASSEMBLY_H
+#if defined(__linux__) && defined(__CET__)
+#include <cet.h>
+#define _LIBUNWIND_CET_ENDBR _CET_ENDBR
+#else
+#define _LIBUNWIND_CET_ENDBR
+#endif
+
#if defined(__powerpc64__)
#define SEPARATOR ;
#define PPC64_OFFS_SRR0 0
#define SEPARATOR ;
#endif
-#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
+#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1) && \
+ !defined(_AIX)
#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR
#define PPC64_OPD2 SEPARATOR \
.p2align 3 SEPARATOR \
#define PPC64_OPD2
#endif
-#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#if defined(__aarch64__) && defined(__ARM_FEATURE_BTI_DEFAULT)
.pushsection ".note.gnu.property", "a" SEPARATOR \
.balign 8 SEPARATOR \
.long 4 SEPARATOR \
#define AARCH64_BTI
#endif
+#if !defined(__aarch64__)
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+ .eabi_attribute Tag_PAC_extension, 2
+ .eabi_attribute Tag_PACRET_use, 1
+#endif
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+ .eabi_attribute Tag_BTI_extension, 1
+ .eabi_attribute Tag_BTI_use, 1
+#endif
+#endif
+
#define GLUE2(a, b) a ## b
#define GLUE(a, b) GLUE2(a, b)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
#elif defined(__sparc__)
+#elif defined(_AIX)
+
+#if defined(__powerpc64__)
+#define VBYTE_LEN 8
+#define CSECT_ALIGN 3
+#else
+#define VBYTE_LEN 4
+#define CSECT_ALIGN 2
+#endif
+
+// clang-format off
+#define DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(name, aliasname) \
+ .csect .text[PR], 2 SEPARATOR \
+ .csect .name[PR], 2 SEPARATOR \
+ .globl name[DS] SEPARATOR \
+ .globl .name[PR] SEPARATOR \
+ .align 4 SEPARATOR \
+ .csect name[DS], CSECT_ALIGN SEPARATOR \
+aliasname: \
+ .vbyte VBYTE_LEN, .name[PR] SEPARATOR \
+ .vbyte VBYTE_LEN, TOC[TC0] SEPARATOR \
+ .vbyte VBYTE_LEN, 0 SEPARATOR \
+ .weak aliasname SEPARATOR \
+ .weak .aliasname SEPARATOR \
+ .csect .name[PR], 2 SEPARATOR \
+.aliasname: \
+
+#define WEAK_ALIAS(name, aliasname)
+#define NO_EXEC_STACK_DIRECTIVE
+
+// clang-format on
#else
#error Unsupported target
#endif
+#if defined(_AIX)
+ // clang-format off
+#define DEFINE_LIBUNWIND_FUNCTION(name) \
+ .globl name[DS] SEPARATOR \
+ .globl .name SEPARATOR \
+ .align 4 SEPARATOR \
+ .csect name[DS], CSECT_ALIGN SEPARATOR \
+ .vbyte VBYTE_LEN, .name SEPARATOR \
+ .vbyte VBYTE_LEN, TOC[TC0] SEPARATOR \
+ .vbyte VBYTE_LEN, 0 SEPARATOR \
+ .csect .text[PR], 2 SEPARATOR \
+.name:
+ // clang-format on
+#else
#define DEFINE_LIBUNWIND_FUNCTION(name) \
.globl SYMBOL_NAME(name) SEPARATOR \
HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_NAME(name): \
PPC64_OPD2 \
AARCH64_BTI
+#endif
#if defined(__arm__)
#if !defined(__ARM_ARCH)
#endif
#endif /* __arm__ */
-#if defined(__ppc__) || defined(__powerpc64__)
+#if defined(__powerpc__)
#define PPC_LEFT_SHIFT(index) << (index)
#endif
-//===----------------------------- config.h -------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// 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
#define _LIBUNWIND_EXPORT
#define _LIBUNWIND_HIDDEN
#else
- #if !defined(__ELF__) && !defined(__MACH__)
+ #if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX)
#define _LIBUNWIND_EXPORT __declspec(dllexport)
#define _LIBUNWIND_HIDDEN
#else
__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)));
#define _LIBUNWIND_BUILD_SJLJ_APIS
#endif
-#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
#define _LIBUNWIND_SUPPORT_FRAME_APIS
#endif
-#if defined(__i386__) || defined(__x86_64__) || \
- defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \
- (!defined(__APPLE__) && defined(__arm__)) || \
- defined(__aarch64__) || \
- defined(__mips__) || \
- defined(__riscv) || \
- defined(__sparc64__) || \
- defined(__hexagon__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \
+ (!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) || \
+ defined(__mips__) || defined(__riscv) || defined(__hexagon__) || \
+ defined(__sparc__) || defined(__s390x__) || defined(__loongarch__)
#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
#define _LIBUNWIND_BUILD_ZERO_COST_APIS
#endif
#ifdef __cplusplus
extern "C" {
#endif
- extern bool logAPIs();
- extern bool logUnwinding();
- extern bool logDWARF();
+ extern bool logAPIs(void);
+ extern bool logUnwinding(void);
+ extern bool logDWARF(void);
#ifdef __cplusplus
}
#endif
-//===--------------------------- libunwind.cpp ----------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#include <libunwind.h>
-#include "libunwind_ext.h"
#include "config.h"
+#include "libunwind_ext.h"
#include <stdlib.h>
# define REGISTER_KIND Registers_x86_64
#elif defined(__powerpc64__)
# define REGISTER_KIND Registers_ppc64
-#elif defined(__ppc__)
+#elif defined(__powerpc__)
# define REGISTER_KIND Registers_ppc
#elif defined(__aarch64__)
# define REGISTER_KIND Registers_arm64
#elif defined(__mips__)
# warning The MIPS architecture is not supported with this ABI and environment!
#elif defined(__sparc__) && defined(__arch64__)
-# define REGISTER_KIND Registers_sparc64
+#define REGISTER_KIND Registers_sparc64
#elif defined(__sparc__)
# define REGISTER_KIND Registers_sparc
#elif defined(__riscv)
# define REGISTER_KIND Registers_riscv
#elif defined(__ve__)
# define REGISTER_KIND Registers_ve
+#elif defined(__s390x__)
+# define REGISTER_KIND Registers_s390x
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+#define REGISTER_KIND Registers_loongarch
#else
# error Architecture not supported
#endif
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
if (co->validReg(regNum)) {
co->setReg(regNum, (pint_t)value);
- // specical case altering IP to re-find info (being called by personality
+ // special case altering IP to re-find info (being called by personality
// function)
if (regNum == UNW_REG_IP) {
unw_proc_info_t info;
}
_LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step)
+// Move cursor to next frame and for stage2 of unwinding.
+// This resets MTE tags of tagged frames to zero.
+extern "C" _LIBUNWIND_HIDDEN int __unw_step_stage2(unw_cursor_t *cursor) {
+ _LIBUNWIND_TRACE_API("__unw_step_stage2(cursor=%p)",
+ static_cast<void *>(cursor));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->step(true);
+}
+
/// Get unwind info at cursor position in stack frame.
_LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor,
unw_proc_info_t *info) {
}
_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<void *>(cursor));
+ AbstractUnwindCursor *co = reinterpret_cast<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) {
// fde is own mh_group
DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
}
+
+void __unw_add_dynamic_eh_frame_section(unw_word_t eh_frame_start) {
+ // The eh_frame section start serves as the mh_group
+ unw_word_t mh_group = eh_frame_start;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ auto p = (LocalAddressSpace::pint_t)eh_frame_start;
+ while (true) {
+ if (CFI_Parser<LocalAddressSpace>::decodeFDE(
+ LocalAddressSpace::sThisAddressSpace, p, &fdeInfo, &cieInfo,
+ true) == NULL) {
+ DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
+ fdeInfo.pcStart, fdeInfo.pcEnd,
+ fdeInfo.fdeStart);
+ p += fdeInfo.fdeLength;
+ } else if (CFI_Parser<LocalAddressSpace>::parseCIE(
+ LocalAddressSpace::sThisAddressSpace, p, &cieInfo) == NULL) {
+ p += cieInfo.cieLength;
+ } else
+ return;
+ }
+}
+
+void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) {
+ // The eh_frame section start serves as the mh_group
+ DwarfFDECache<LocalAddressSpace>::removeAllIn(
+ (LocalAddressSpace::pint_t)eh_frame_start);
+}
+
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
#endif // !defined(__USING_SJLJ_EXCEPTIONS__)