mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
update libunwind to LLVM 15
release/15.x commit 134fd359a5d884f16662a9edd22ab24feeb1498c
This commit is contained in:
parent
c0d9578a84
commit
2f635c3ce9
21 changed files with 1515 additions and 134 deletions
11
lib/libunwind/include/__libunwind_config.h
vendored
11
lib/libunwind/include/__libunwind_config.h
vendored
|
|
@ -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
|
||||
|
|
|
|||
47
lib/libunwind/include/libunwind.h
vendored
47
lib/libunwind/include/libunwind.h
vendored
|
|
@ -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
|
||||
|
|
|
|||
2
lib/libunwind/include/unwind.h
vendored
2
lib/libunwind/include/unwind.h
vendored
|
|
@ -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)
|
||||
|
|
|
|||
23
lib/libunwind/src/AddressSpace.hpp
vendored
23
lib/libunwind/src/AddressSpace.hpp
vendored
|
|
@ -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;
|
||||
|
|
|
|||
28
lib/libunwind/src/DwarfInstructions.hpp
vendored
28
lib/libunwind/src/DwarfInstructions.hpp
vendored
|
|
@ -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;
|
||||
|
|
|
|||
3
lib/libunwind/src/EHHeaderParser.hpp
vendored
3
lib/libunwind/src/EHHeaderParser.hpp
vendored
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
348
lib/libunwind/src/Registers.hpp
vendored
348
lib/libunwind/src/Registers.hpp
vendored
|
|
@ -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__
|
||||
|
|
|
|||
9
lib/libunwind/src/Unwind-EHABI.cpp
vendored
9
lib/libunwind/src/Unwind-EHABI.cpp
vendored
|
|
@ -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:
|
||||
|
|
|
|||
6
lib/libunwind/src/Unwind-seh.cpp
vendored
6
lib/libunwind/src/Unwind-seh.cpp
vendored
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
733
lib/libunwind/src/UnwindCursor.hpp
vendored
733
lib/libunwind/src/UnwindCursor.hpp
vendored
|
|
@ -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)
|
||||
|
|
|
|||
7
lib/libunwind/src/UnwindLevel1-gcc-ext.c
vendored
7
lib/libunwind/src/UnwindLevel1-gcc-ext.c
vendored
|
|
@ -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
|
||||
|
|
|
|||
8
lib/libunwind/src/UnwindLevel1.c
vendored
8
lib/libunwind/src/UnwindLevel1.c
vendored
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
199
lib/libunwind/src/UnwindRegistersRestore.S
vendored
199
lib/libunwind/src/UnwindRegistersRestore.S
vendored
|
|
@ -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:
|
||||
|
||||
#define PPC64_CLVSh(n) \
|
||||
andi. 0, 5, (1 PPC_LEFT_SHIFT(63-n)) ;\
|
||||
PPC64_CLVS_BOTTOM(n)
|
||||
#else
|
||||
|
||||
#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,33 +331,45 @@ 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
|
||||
|
||||
#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_UNALIGNEDh(n) \
|
||||
andi. 0, 5, (1 PPC_LEFT_SHIFT(31-n)) ;\
|
||||
beq Ldone##n ;\
|
||||
PPC64_CLV_UNALIGNED_RESTORE(n) ;\
|
||||
Ldone ## n:
|
||||
|
||||
#else
|
||||
|
||||
#define PPC64_CLV_UNALIGNEDl(n) PPC64_CLV_UNALIGNED_RESTORE(n)
|
||||
#define PPC64_CLV_UNALIGNEDh(n) PPC64_CLV_UNALIGNED_RESTORE(n)
|
||||
|
||||
#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
|
||||
|
||||
#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 ;\
|
||||
Ldone ## n:
|
||||
|
||||
#define PPC64_CLV_UNALIGNEDl(n) \
|
||||
andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n)) ;\
|
||||
PPC64_CLV_UNALIGNED_BOTTOM(n)
|
||||
|
||||
#define PPC64_CLV_UNALIGNEDh(n) \
|
||||
andi. 0, 5, (1 PPC_LEFT_SHIFT(31-n)) ;\
|
||||
PPC64_CLV_UNALIGNED_BOTTOM(n)
|
||||
|
||||
PPC64_CLV_UNALIGNEDl(0)
|
||||
PPC64_CLV_UNALIGNEDl(1)
|
||||
PPC64_CLV_UNALIGNEDl(2)
|
||||
|
|
@ -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,46 +512,49 @@ 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
|
||||
|
||||
#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 \
|
||||
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
|
||||
|
||||
|
||||
#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 \
|
||||
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 \
|
||||
Ldone ## _index:
|
||||
|
||||
|
||||
LOAD_VECTOR_UNALIGNEDl(0)
|
||||
LOAD_VECTOR_UNALIGNEDl(1)
|
||||
LOAD_VECTOR_UNALIGNEDl(2)
|
||||
|
|
@ -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__) */
|
||||
|
|
|
|||
56
lib/libunwind/src/UnwindRegistersSave.S
vendored
56
lib/libunwind/src/UnwindRegistersSave.S
vendored
|
|
@ -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)
|
||||
|
|
|
|||
63
lib/libunwind/src/Unwind_AIXExtras.cpp
vendored
Normal file
63
lib/libunwind/src/Unwind_AIXExtras.cpp
vendored
Normal file
|
|
@ -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)
|
||||
49
lib/libunwind/src/assembly.h
vendored
49
lib/libunwind/src/assembly.h
vendored
|
|
@ -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)
|
||||
|
|
|
|||
2
lib/libunwind/src/cet_unwind.h
vendored
2
lib/libunwind/src/cet_unwind.h
vendored
|
|
@ -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
|
||||
|
|
|
|||
15
lib/libunwind/src/config.h
vendored
15
lib/libunwind/src/config.h
vendored
|
|
@ -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
|
||||
|
|
|
|||
12
lib/libunwind/src/libunwind.cpp
vendored
12
lib/libunwind/src/libunwind.cpp
vendored
|
|
@ -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) {
|
||||
|
|
|
|||
4
lib/libunwind/src/libunwind_ext.h
vendored
4
lib/libunwind/src/libunwind_ext.h
vendored
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue