Commit 2f635c3ce9
Changed files (21)
lib
libunwind
lib/libunwind/include/__libunwind_config.h
@@ -9,8 +9,10 @@
#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
@@ -27,6 +29,7 @@
#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
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__linux__)
@@ -158,6 +161,11 @@
# 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
# else
# error "Unsupported architecture."
# endif
@@ -176,6 +184,7 @@
# define _LIBUNWIND_TARGET_HEXAGON 1
# define _LIBUNWIND_TARGET_RISCV 1
# define _LIBUNWIND_TARGET_VE 1
+# define _LIBUNWIND_TARGET_S390X 1
# define _LIBUNWIND_CONTEXT_SIZE 167
# define _LIBUNWIND_CURSOR_SIZE 179
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
lib/libunwind/include/libunwind.h
@@ -81,7 +81,7 @@ typedef struct unw_addr_space *unw_addr_space_t;
typedef int unw_regnum_t;
typedef uintptr_t unw_word_t;
-#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
+#if defined(__arm__) && !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
typedef uint64_t unw_fpreg_t;
#else
typedef double unw_fpreg_t;
@@ -120,6 +120,9 @@ extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;
extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL;
#endif
+#ifdef _AIX
+extern uintptr_t unw_get_data_rel_base(unw_cursor_t *) LIBUNWIND_AVAIL;
+#endif
extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL;
@@ -1174,4 +1177,46 @@ enum {
UNW_VE_VL = 145,
};
+// s390x register numbers
+enum {
+ UNW_S390X_R0 = 0,
+ UNW_S390X_R1 = 1,
+ UNW_S390X_R2 = 2,
+ UNW_S390X_R3 = 3,
+ UNW_S390X_R4 = 4,
+ UNW_S390X_R5 = 5,
+ UNW_S390X_R6 = 6,
+ UNW_S390X_R7 = 7,
+ UNW_S390X_R8 = 8,
+ UNW_S390X_R9 = 9,
+ UNW_S390X_R10 = 10,
+ UNW_S390X_R11 = 11,
+ UNW_S390X_R12 = 12,
+ UNW_S390X_R13 = 13,
+ UNW_S390X_R14 = 14,
+ UNW_S390X_R15 = 15,
+ UNW_S390X_F0 = 16,
+ UNW_S390X_F2 = 17,
+ UNW_S390X_F4 = 18,
+ UNW_S390X_F6 = 19,
+ UNW_S390X_F1 = 20,
+ UNW_S390X_F3 = 21,
+ UNW_S390X_F5 = 22,
+ UNW_S390X_F7 = 23,
+ UNW_S390X_F8 = 24,
+ UNW_S390X_F10 = 25,
+ UNW_S390X_F12 = 26,
+ UNW_S390X_F14 = 27,
+ UNW_S390X_F9 = 28,
+ UNW_S390X_F11 = 29,
+ UNW_S390X_F13 = 30,
+ UNW_S390X_F15 = 31,
+ // 32-47 Control Registers
+ // 48-63 Access Registers
+ UNW_S390X_PSWM = 64,
+ UNW_S390X_PSWA = 65,
+ // 66-67 Reserved
+ // 68-83 Vector Registers %v16-%v31
+};
+
#endif
lib/libunwind/include/unwind.h
@@ -160,7 +160,7 @@ extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
extern void *_Unwind_FindEnclosingFunction(void *pc);
// Mac OS X does not support text-rel and data-rel addressing so these functions
-// are unimplemented
+// are unimplemented.
extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context)
LIBUNWIND_UNAVAIL;
extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
lib/libunwind/src/AddressSpace.hpp
@@ -24,7 +24,7 @@
#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
@@ -45,6 +45,13 @@ struct EHABIIndexEntry {
};
#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
@@ -544,6 +551,7 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
DWORD err = GetLastError();
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
"returned error %d", (int)err);
+ (void)err;
return false;
}
@@ -580,6 +588,11 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
(void)targetAddr;
(void)info;
return true;
+#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+ // The traceback table is used for unwinding.
+ (void)targetAddr;
+ (void)info;
+ return true;
#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
int length = 0;
info.arm_section =
@@ -596,7 +609,6 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
return false;
}
-
inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
// TO DO: if OS has way to dynamically register FDEs, check that.
(void)targetAddr;
@@ -616,6 +628,13 @@ inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
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;
lib/libunwind/src/assembly.h
@@ -67,7 +67,8 @@
#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 \
@@ -203,12 +204,57 @@
#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 \
@@ -217,6 +263,7 @@
SYMBOL_NAME(name): \
PPC64_OPD2 \
AARCH64_BTI
+#endif
#if defined(__arm__)
#if !defined(__ARM_ARCH)
lib/libunwind/src/cet_unwind.h
@@ -36,6 +36,6 @@
#endif
extern void *__libunwind_cet_get_registers(unw_cursor_t *);
-extern void *__libunwind_cet_get_jump_target();
+extern void *__libunwind_cet_get_jump_target(void);
#endif
lib/libunwind/src/config.h
@@ -43,6 +43,9 @@
// For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
// API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
#define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1
+#elif defined(_AIX)
+// The traceback table at the end of each function is used for unwinding.
+#define _LIBUNWIND_SUPPORT_TBTAB_UNWIND 1
#else
// Assume an ELF system with a dl_iterate_phdr function.
#define _LIBUNWIND_USE_DL_ITERATE_PHDR 1
@@ -57,7 +60,7 @@
#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
@@ -80,7 +83,7 @@
__asm__(".globl " SYMBOL_NAME(aliasname)); \
__asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \
_LIBUNWIND_ALIAS_VISIBILITY(SYMBOL_NAME(aliasname))
-#elif defined(__ELF__)
+#elif defined(__ELF__) || defined(_AIX)
#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \
extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \
__attribute__((weak, alias(#name)));
@@ -112,7 +115,7 @@
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \
(!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) || \
defined(__mips__) || defined(__riscv) || defined(__hexagon__) || \
- defined(__sparc__)
+ defined(__sparc__) || defined(__s390x__)
#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
#define _LIBUNWIND_BUILD_ZERO_COST_APIS
#endif
@@ -188,9 +191,9 @@
#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
lib/libunwind/src/DwarfInstructions.hpp
@@ -72,6 +72,10 @@ 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>
@@ -166,6 +170,21 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
}
_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,
@@ -194,9 +213,10 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
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) {
@@ -235,7 +255,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// 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_AARCH64_RA_SIGN_STATE].value &&
+ getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
returnAddress != 0) {
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING;
lib/libunwind/src/EHHeaderParser.hpp
@@ -57,7 +57,8 @@ bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
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;
}
lib/libunwind/src/libunwind.cpp
@@ -75,6 +75,8 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
# define REGISTER_KIND Registers_riscv
#elif defined(__ve__)
# define REGISTER_KIND Registers_ve
+#elif defined(__s390x__)
+# define REGISTER_KIND Registers_s390x
#else
# error Architecture not supported
#endif
@@ -247,6 +249,16 @@ _LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) {
}
_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) {
lib/libunwind/src/libunwind_ext.h
@@ -43,6 +43,10 @@ extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t);
extern int __unw_is_signal_frame(unw_cursor_t *);
extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *);
+#if defined(_AIX)
+extern uintptr_t __unw_get_data_rel_base(unw_cursor_t *);
+#endif
+
// SPI
extern void __unw_iterate_dwarf_unwind_cache(void (*func)(
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
lib/libunwind/src/Registers.hpp
@@ -39,6 +39,7 @@ enum {
REGISTERS_HEXAGON,
REGISTERS_RISCV,
REGISTERS_VE,
+ REGISTERS_S390X,
};
#if defined(_LIBUNWIND_TARGET_I386)
@@ -69,7 +70,9 @@ public:
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; }
@@ -285,7 +288,9 @@ public:
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; }
@@ -602,13 +607,17 @@ public:
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 getCR() const { return _registers.__cr; }
+ void setCR(uint32_t value) { _registers.__cr = value; }
private:
struct ppc_thread_state_t {
@@ -1168,13 +1177,17 @@ public:
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 getCR() const { return _registers.__cr; }
+ void setCR(uint64_t value) { _registers.__cr = value; }
private:
struct ppc64_thread_state_t {
@@ -1813,7 +1826,9 @@ public:
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; }
@@ -2103,7 +2118,9 @@ public:
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; }
@@ -2603,7 +2620,9 @@ public:
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]; }
@@ -2800,7 +2819,9 @@ public:
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]; }
@@ -3127,7 +3148,9 @@ public:
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]; }
@@ -3422,7 +3445,9 @@ public:
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]; }
@@ -3606,7 +3631,7 @@ public:
void setVectorRegister(int num, v128 value);
const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() {
+ static constexpr int lastDwarfRegNum() {
return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64;
}
static int getArch() { return REGISTERS_SPARC64; }
@@ -3791,7 +3816,9 @@ public:
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]; }
@@ -4004,7 +4031,9 @@ public:
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]; }
@@ -4290,7 +4319,9 @@ public:
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]; }
@@ -4712,6 +4743,295 @@ inline const char *Registers_ve::getRegisterName(int regNum) {
}
#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
+
+
} // namespace libunwind
#endif // __REGISTERS_HPP__
lib/libunwind/src/Unwind-EHABI.cpp
@@ -432,10 +432,11 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
uint32_t sp;
uint32_t pac;
_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
- _Unwind_VRS_Get(context, _UVRSC_PSEUDO, UNW_ARM_RA_AUTH_CODE,
- _UVRSD_UINT32, &pac);
+ _Unwind_VRS_Get(context, _UVRSC_PSEUDO, 0, _UVRSD_UINT32, &pac);
__asm__ __volatile__("autg %0, %1, %2" : : "r"(pac), "r"(lr), "r"(sp) :);
}
+#else
+ (void)hasReturnAddrAuthCode;
#endif
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr);
}
@@ -1136,8 +1137,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
}
uint32_t pac = *sp++;
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
- return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_RA_AUTH_CODE,
- _UVRSD_UINT32, &pac);
+ return _Unwind_VRS_Set(context, _UVRSC_PSEUDO, 0, _UVRSD_UINT32, &pac);
}
}
_LIBUNWIND_ABORT("unsupported register class");
@@ -1193,6 +1193,7 @@ _Unwind_DeleteException(_Unwind_Exception *exception_object) {
extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
__gnu_unwind_frame(_Unwind_Exception *exception_object,
struct _Unwind_Context *context) {
+ (void)exception_object;
unw_cursor_t *cursor = (unw_cursor_t *)context;
switch (__unw_step(cursor)) {
case UNW_STEP_SUCCESS:
lib/libunwind/src/Unwind-seh.cpp
@@ -104,7 +104,7 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
if (!ctx) {
__unw_init_seh(&cursor, disp->ContextRecord);
__unw_seh_set_disp_ctx(&cursor, disp);
- __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1);
+ __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc);
ctx = (struct _Unwind_Context *)&cursor;
if (!IS_UNWINDING(ms_exc->ExceptionFlags)) {
@@ -255,8 +255,8 @@ unwind_phase2_forced(unw_context_t *uc,
(frameInfo.start_ip + offset > frameInfo.end_ip))
functionName = ".anonymous.";
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64
- ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64,
+ "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
+ ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
(void *)exception_object, frameInfo.start_ip, functionName,
frameInfo.lsda, frameInfo.handler);
}
lib/libunwind/src/Unwind_AIXExtras.cpp
@@ -0,0 +1,63 @@
+//===--------------------- Unwind_AIXExtras.cpp -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//===----------------------------------------------------------------------===//
+
+// This file is only used for AIX.
+#if defined(_AIX)
+
+#include "config.h"
+#include "libunwind_ext.h"
+#include <sys/debug.h>
+
+namespace libunwind {
+// getFuncNameFromTBTable
+// Get the function name from its traceback table.
+char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
+ unw_word_t *Offset) {
+ uint32_t *p = reinterpret_cast<uint32_t *>(Pc);
+ *Offset = 0;
+
+ // Keep looking forward until a word of 0 is found. The traceback
+ // table starts at the following word.
+ while (*p)
+ p++;
+ tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
+
+ if (!TBTable->tb.name_present)
+ return NULL;
+
+ // Get to the name of the function.
+ p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
+
+ // Skip field parminfo if it exists.
+ if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
+ p++;
+
+ // If the tb_offset field exisits, get the offset from the start of
+ // the function to pc. Skip the field.
+ if (TBTable->tb.has_tboff) {
+ unw_word_t StartIp =
+ reinterpret_cast<uintptr_t>(TBTable) - *p - sizeof(uint32_t);
+ *Offset = Pc - StartIp;
+ p++;
+ }
+
+ // Skip field hand_mask if it exists.
+ if (TBTable->tb.int_hndl)
+ p++;
+
+ // Skip fields ctl_info and ctl_info_disp if they exist.
+ if (TBTable->tb.has_ctl) {
+ p += 1 + *p;
+ }
+
+ NameLen = *(reinterpret_cast<uint16_t *>(p));
+ return reinterpret_cast<char *>(p) + sizeof(uint16_t);
+}
+} // namespace libunwind
+#endif // defined(_AIX)
lib/libunwind/src/UnwindCursor.hpp
@@ -24,6 +24,19 @@
#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
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and
@@ -451,6 +464,12 @@ public:
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");
@@ -499,6 +518,14 @@ 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);
@@ -844,7 +871,7 @@ void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
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) {
@@ -910,9 +937,14 @@ public:
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.
static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
@@ -937,7 +969,7 @@ private:
}
#endif
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
bool setInfoForSigReturn() {
R dummy;
return setInfoForSigReturn(dummy);
@@ -946,8 +978,14 @@ private:
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;
}
@@ -1204,6 +1242,12 @@ private:
}
#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)
@@ -1220,13 +1264,23 @@ private:
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
};
@@ -1292,6 +1346,13 @@ template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {
}
#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);
@@ -1912,20 +1973,517 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
_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;
+ 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);
+ }
+ }
+ 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 simualates 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
@@ -1948,7 +2506,14 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// 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;
@@ -1982,6 +2547,12 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
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) {
@@ -2027,7 +2598,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
}
#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
@@ -2036,7 +2607,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
_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
@@ -2055,14 +2627,28 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
//
// [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>
@@ -2096,7 +2682,114 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
_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>::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() {
@@ -2106,7 +2799,7 @@ int UnwindCursor<A, R>::step() {
// 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
@@ -2116,6 +2809,8 @@ int UnwindCursor<A, R>::step() {
result = this->stepWithCompactEncoding();
#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
result = this->stepWithSEHData();
+#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+ result = this->stepWithTBTableData();
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
result = this->stepWithDwarfFDE();
#elif defined(_LIBUNWIND_ARM_EHABI)
lib/libunwind/src/UnwindLevel1-gcc-ext.c
@@ -59,12 +59,15 @@ _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
/// relative encodings.
_LIBUNWIND_EXPORT uintptr_t
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
- (void)context;
_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
+#if defined(_AIX)
+ return unw_get_data_rel_base((unw_cursor_t *)context);
+#else
+ (void)context;
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
+#endif
}
-
/// Called by personality handler during phase 2 to get base address for text
/// relative encodings.
_LIBUNWIND_EXPORT uintptr_t
lib/libunwind/src/UnwindLevel1.c
@@ -44,7 +44,11 @@
// directly jump to __libunwind_Registerts_x86/x86_64_jumpto instead of using
// a regular function call to avoid pushing to CET shadow stack again.
#if !defined(_LIBUNWIND_USE_CET)
-#define __unw_phase2_resume(cursor, fn) __unw_resume((cursor))
+#define __unw_phase2_resume(cursor, fn) \
+ do { \
+ (void)fn; \
+ __unw_resume((cursor)); \
+ } while (0)
#elif defined(_LIBUNWIND_TARGET_I386)
#define __unw_phase2_resume(cursor, fn) \
do { \
@@ -480,11 +484,13 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
_LIBUNWIND_TRACE_API(
"_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
(void *)context, result);
+#if !defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
if (result != 0) {
if (*((uint8_t *)result) != 0xFF)
_LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",
result);
}
+#endif
return result;
}
lib/libunwind/src/UnwindRegistersRestore.S
@@ -8,7 +8,11 @@
#include "assembly.h"
+#if defined(_AIX)
+ .toc
+#else
.text
+#endif
#if !defined(__USING_SJLJ_EXCEPTIONS__)
@@ -222,27 +226,36 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
PPC64_LVS(30)
PPC64_LVS(31)
- // use VRSAVE to conditionally restore the remaining VS regs,
- // that are where the V regs are mapped
+#define PPC64_CLVS_RESTORE(n) \
+ addi 4, 3, PPC64_OFFS_FP + n * 16 ;\
+ lxvd2x n, 0, 4
+#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_CLVSl(n) \
- andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n)) ;\
-PPC64_CLVS_BOTTOM(n)
+#define PPC64_CLVSh(n) \
+ andi. 0, 5, (1 PPC_LEFT_SHIFT(63-n)) ;\
+ beq Ldone##n ;\
+ PPC64_CLVS_RESTORE(n) ;\
+Ldone##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)
@@ -318,32 +331,44 @@ PPC64_CLVS_BOTTOM(n)
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)
+
+#endif // !defined(_AIX)
-#define PPC64_CLV_UNALIGNEDh(n) \
- andi. 0, 5, (1 PPC_LEFT_SHIFT(31-n)) ;\
-PPC64_CLV_UNALIGNED_BOTTOM(n)
+ 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)
@@ -387,11 +412,23 @@ Lnovec:
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(__powerpc__)
@@ -475,45 +512,48 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
#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)
@@ -1212,6 +1252,43 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
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
+ ld %f0, 144(%r2)
+ ld %f1, 152(%r2)
+ ld %f2, 160(%r2)
+ ld %f3, 168(%r2)
+ ld %f4, 176(%r2)
+ ld %f5, 184(%r2)
+ ld %f6, 192(%r2)
+ ld %f7, 200(%r2)
+ ld %f8, 208(%r2)
+ ld %f9, 216(%r2)
+ ld %f10, 224(%r2)
+ ld %f11, 232(%r2)
+ ld %f12, 240(%r2)
+ ld %f13, 248(%r2)
+ ld %f14, 256(%r2)
+ ld %f15, 264(%r2)
+
+ // Restore GPRs - skipping %r0 and %r1
+ lmg %r2, %r15, 32(%r2)
+
+ // Return to PSWA (was loaded into %r1 above)
+ br %r1
+
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
lib/libunwind/src/UnwindRegistersSave.S
@@ -8,7 +8,11 @@
#include "assembly.h"
+#if defined(_AIX)
+ .toc
+#else
.text
+#endif
#if !defined(__USING_SJLJ_EXCEPTIONS__)
@@ -334,8 +338,11 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
// 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)
@@ -567,7 +574,11 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
// 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
@@ -1168,6 +1179,49 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
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
+ std %f0, 144(%r2)
+ std %f1, 152(%r2)
+ std %f2, 160(%r2)
+ std %f3, 168(%r2)
+ std %f4, 176(%r2)
+ std %f5, 184(%r2)
+ std %f6, 192(%r2)
+ std %f7, 200(%r2)
+ std %f8, 208(%r2)
+ std %f9, 216(%r2)
+ std %f10, 224(%r2)
+ std %f11, 232(%r2)
+ std %f12, 240(%r2)
+ std %f13, 248(%r2)
+ std %f14, 256(%r2)
+ std %f15, 264(%r2)
+
+ // Return UNW_ESUCCESS
+ lghi %r2, 0
+ br %r14
+
#endif
WEAK_ALIAS(__unw_getcontext, unw_getcontext)
src/libunwind.zig
@@ -33,17 +33,6 @@ pub fn buildStaticLib(comp: *Compilation) !void {
.directory = null, // Put it in the cache directory.
.basename = basename,
};
- const unwind_src_list = [_][]const u8{
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "libunwind.cpp",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-EHABI.cpp",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-seh.cpp",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1.c",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1-gcc-ext.c",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-sjlj.c",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S",
- "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c",
- };
var c_source_files: [unwind_src_list.len]Compilation.CSourceFile = undefined;
for (unwind_src_list) |unwind_src, i| {
var cflags = std.ArrayList([]const u8).init(arena);
@@ -150,3 +139,16 @@ pub fn buildStaticLib(comp: *Compilation) !void {
.lock = sub_compilation.bin_file.toOwnedLock(),
};
}
+
+const unwind_src_list = [_][]const u8{
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "libunwind.cpp",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-EHABI.cpp",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-seh.cpp",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1.c",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1-gcc-ext.c",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-sjlj.c",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind_AIXExtras.cpp",
+ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c",
+};