mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
libunwind: update to LLVM 18
release/18.x branch, commit 78b99c73ee4b96fe9ce0e294d4632326afb2db42
This commit is contained in:
parent
a6856ef6d2
commit
6295415da7
5
lib/libunwind/include/__libunwind_config.h
vendored
5
lib/libunwind/include/__libunwind_config.h
vendored
@ -36,6 +36,9 @@
|
||||
# if defined(__linux__)
|
||||
# define _LIBUNWIND_TARGET_LINUX 1
|
||||
# endif
|
||||
# if defined(__HAIKU__)
|
||||
# define _LIBUNWIND_TARGET_HAIKU 1
|
||||
# endif
|
||||
# if defined(__i386__)
|
||||
# define _LIBUNWIND_TARGET_I386
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 8
|
||||
@ -196,7 +199,7 @@
|
||||
# define _LIBUNWIND_TARGET_RISCV 1
|
||||
# define _LIBUNWIND_TARGET_VE 1
|
||||
# define _LIBUNWIND_TARGET_S390X 1
|
||||
#define _LIBUNWIND_TARGET_LOONGARCH 1
|
||||
# define _LIBUNWIND_TARGET_LOONGARCH 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 167
|
||||
# define _LIBUNWIND_CURSOR_SIZE 204
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
|
||||
|
||||
3
lib/libunwind/include/libunwind.h
vendored
3
lib/libunwind/include/libunwind.h
vendored
@ -876,6 +876,9 @@ enum {
|
||||
UNW_MIPS_F29 = 61,
|
||||
UNW_MIPS_F30 = 62,
|
||||
UNW_MIPS_F31 = 63,
|
||||
// HI,LO have been dropped since r6, we keep them here.
|
||||
// So, when we add DSP/MSA etc, we can use the same register indexes
|
||||
// for r6 and pre-r6.
|
||||
UNW_MIPS_HI = 64,
|
||||
UNW_MIPS_LO = 65,
|
||||
};
|
||||
|
||||
@ -108,7 +108,7 @@ enum {
|
||||
// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||
// Each entry contains which register to restore.
|
||||
// UNWIND_X86_MODE_STACK_IMMD:
|
||||
// A "frameless" (EBP not used as frame pointer) function with a small
|
||||
// A "frameless" (EBP not used as frame pointer) function with a small
|
||||
// constant stack size. To return, a constant (encoded in the compact
|
||||
// unwind encoding) is added to the ESP. Then the return is done by
|
||||
// popping the stack into the pc.
|
||||
@ -119,16 +119,16 @@ enum {
|
||||
// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION contains which registers were
|
||||
// saved and their order.
|
||||
// UNWIND_X86_MODE_STACK_IND:
|
||||
// A "frameless" (EBP not used as frame pointer) function large constant
|
||||
// A "frameless" (EBP not used as frame pointer) function large constant
|
||||
// stack size. This case is like the previous, except the stack size is too
|
||||
// large to encode in the compact unwind encoding. Instead it requires that
|
||||
// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact
|
||||
// large to encode in the compact unwind encoding. Instead it requires that
|
||||
// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact
|
||||
// encoding contains the offset to the nnnnnnnn value in the function in
|
||||
// UNWIND_X86_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
@ -233,36 +233,36 @@ enum {
|
||||
// For x86_64 there are four modes for the compact unwind encoding:
|
||||
// UNWIND_X86_64_MODE_RBP_FRAME:
|
||||
// RBP based frame where RBP is push on stack immediately after return address,
|
||||
// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
|
||||
// EPB value, then RBP is restored by popping off the stack, and the return
|
||||
// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
|
||||
// EPB value, then RBP is restored by popping off the stack, and the return
|
||||
// is done by popping the stack once more into the pc.
|
||||
// All non-volatile registers that need to be restored must have been saved
|
||||
// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8
|
||||
// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8
|
||||
// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved
|
||||
// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||
// Each entry contains which register to restore.
|
||||
// Each entry contains which register to restore.
|
||||
// UNWIND_X86_64_MODE_STACK_IMMD:
|
||||
// A "frameless" (RBP not used as frame pointer) function with a small
|
||||
// constant stack size. To return, a constant (encoded in the compact
|
||||
// unwind encoding) is added to the RSP. Then the return is done by
|
||||
// A "frameless" (RBP not used as frame pointer) function with a small
|
||||
// constant stack size. To return, a constant (encoded in the compact
|
||||
// unwind encoding) is added to the RSP. Then the return is done by
|
||||
// popping the stack into the pc.
|
||||
// All non-volatile registers that need to be restored must have been saved
|
||||
// on the stack immediately after the return address. The stack_size/8 is
|
||||
// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048).
|
||||
// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
|
||||
// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION contains which registers were
|
||||
// saved and their order.
|
||||
// saved and their order.
|
||||
// UNWIND_X86_64_MODE_STACK_IND:
|
||||
// A "frameless" (RBP not used as frame pointer) function large constant
|
||||
// A "frameless" (RBP not used as frame pointer) function large constant
|
||||
// stack size. This case is like the previous, except the stack size is too
|
||||
// large to encode in the compact unwind encoding. Instead it requires that
|
||||
// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
|
||||
// large to encode in the compact unwind encoding. Instead it requires that
|
||||
// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
|
||||
// encoding contains the offset to the nnnnnnnn value in the function in
|
||||
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_64_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
@ -307,20 +307,20 @@ enum {
|
||||
// This is a standard arm64 prolog where FP/LR are immediately pushed on the
|
||||
// stack, then SP is copied to FP. If there are any non-volatile registers
|
||||
// saved, then are copied into the stack frame in pairs in a contiguous
|
||||
// range right below the saved FP/LR pair. Any subset of the five X pairs
|
||||
// range right below the saved FP/LR pair. Any subset of the five X pairs
|
||||
// and four D pairs can be saved, but the memory layout must be in register
|
||||
// number order.
|
||||
// number order.
|
||||
// UNWIND_ARM64_MODE_FRAMELESS:
|
||||
// A "frameless" leaf function, where FP/LR are not saved. The return address
|
||||
// A "frameless" leaf function, where FP/LR are not saved. The return address
|
||||
// remains in LR throughout the function. If any non-volatile registers
|
||||
// are saved, they must be pushed onto the stack before any stack space is
|
||||
// allocated for local variables. The stack sized (including any saved
|
||||
// non-volatile registers) divided by 16 is encoded in the bits
|
||||
// non-volatile registers) divided by 16 is encoded in the bits
|
||||
// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
|
||||
// UNWIND_ARM64_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
@ -337,19 +337,19 @@ enum {
|
||||
|
||||
//
|
||||
// A compiler can generated compact unwind information for a function by adding
|
||||
// a "row" to the __LD,__compact_unwind section. This section has the
|
||||
// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers.
|
||||
// It is removed by the new linker, so never ends up in final executables.
|
||||
// This section is a table, initially with one row per function (that needs
|
||||
// a "row" to the __LD,__compact_unwind section. This section has the
|
||||
// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers.
|
||||
// It is removed by the new linker, so never ends up in final executables.
|
||||
// This section is a table, initially with one row per function (that needs
|
||||
// unwind info). The table columns and some conceptual entries are:
|
||||
//
|
||||
// range-start pointer to start of function/range
|
||||
// range-length
|
||||
// compact-unwind-encoding 32-bit encoding
|
||||
// range-length
|
||||
// compact-unwind-encoding 32-bit encoding
|
||||
// personality-function or zero if no personality function
|
||||
// lsda or zero if no LSDA data
|
||||
//
|
||||
// The length and encoding fields are 32-bits. The other are all pointer sized.
|
||||
// The length and encoding fields are 32-bits. The other are all pointer sized.
|
||||
//
|
||||
// In x86_64 assembly, these entry would look like:
|
||||
//
|
||||
@ -372,23 +372,23 @@ enum {
|
||||
// .quad except_tab1
|
||||
//
|
||||
//
|
||||
// Notes: There is no need for any labels in the the __compact_unwind section.
|
||||
// The use of the .set directive is to force the evaluation of the
|
||||
// Notes: There is no need for any labels in the __compact_unwind section.
|
||||
// The use of the .set directive is to force the evaluation of the
|
||||
// range-length at assembly time, instead of generating relocations.
|
||||
//
|
||||
// To support future compiler optimizations where which non-volatile registers
|
||||
// To support future compiler optimizations where which non-volatile registers
|
||||
// are saved changes within a function (e.g. delay saving non-volatiles until
|
||||
// necessary), there can by multiple lines in the __compact_unwind table for one
|
||||
// function, each with a different (non-overlapping) range and each with
|
||||
// different compact unwind encodings that correspond to the non-volatiles
|
||||
// function, each with a different (non-overlapping) range and each with
|
||||
// different compact unwind encodings that correspond to the non-volatiles
|
||||
// saved at that range of the function.
|
||||
//
|
||||
// If a particular function is so wacky that there is no compact unwind way
|
||||
// to encode it, then the compiler can emit traditional DWARF unwind info.
|
||||
// to encode it, then the compiler can emit traditional DWARF unwind info.
|
||||
// The runtime will use which ever is available.
|
||||
//
|
||||
// Runtime support for compact unwind encodings are only available on 10.6
|
||||
// and later. So, the compiler should not generate it when targeting pre-10.6.
|
||||
// Runtime support for compact unwind encodings are only available on 10.6
|
||||
// and later. So, the compiler should not generate it when targeting pre-10.6.
|
||||
|
||||
|
||||
|
||||
@ -402,7 +402,7 @@ enum {
|
||||
//
|
||||
// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
|
||||
// The header of the section contains a coarse index that maps function address
|
||||
// to the page (4096 byte block) containing the unwind info for that function.
|
||||
// to the page (4096 byte block) containing the unwind info for that function.
|
||||
//
|
||||
|
||||
#define UNWIND_SECTION_VERSION 1
|
||||
|
||||
7
lib/libunwind/src/AddressSpace.hpp
vendored
7
lib/libunwind/src/AddressSpace.hpp
vendored
@ -414,8 +414,8 @@ static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
|
||||
cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
|
||||
cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
|
||||
if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
||||
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
|
||||
hdrInfo)) {
|
||||
*cbdata->addressSpace, eh_frame_hdr_start,
|
||||
eh_frame_hdr_start + phdr->p_memsz, hdrInfo)) {
|
||||
// .eh_frame_hdr records the start of .eh_frame, but not its size.
|
||||
// Rely on a zero terminator to find the end of the section.
|
||||
cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
|
||||
@ -638,7 +638,8 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||
info.dwarf_index_section_length = SIZE_MAX;
|
||||
EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
|
||||
if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
||||
*this, info.dwarf_index_section, info.dwarf_index_section_length,
|
||||
*this, info.dwarf_index_section,
|
||||
info.dwarf_index_section + info.dwarf_index_section_length,
|
||||
hdrInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
2
lib/libunwind/src/DwarfInstructions.hpp
vendored
2
lib/libunwind/src/DwarfInstructions.hpp
vendored
@ -68,7 +68,7 @@ private:
|
||||
return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
|
||||
prolog.cfaRegisterOffset);
|
||||
if (prolog.cfaExpression != 0)
|
||||
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
|
||||
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
|
||||
registers, 0);
|
||||
assert(0 && "getCFA(): unknown location");
|
||||
__builtin_unreachable();
|
||||
|
||||
13
lib/libunwind/src/EHHeaderParser.hpp
vendored
13
lib/libunwind/src/EHHeaderParser.hpp
vendored
@ -55,6 +55,19 @@ template <typename A>
|
||||
bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
|
||||
pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
|
||||
pint_t p = ehHdrStart;
|
||||
|
||||
// Ensure that we don't read data beyond the end of .eh_frame_hdr
|
||||
if (ehHdrEnd - ehHdrStart < 4) {
|
||||
// Don't print a message for an empty .eh_frame_hdr (this can happen if
|
||||
// the linker script defines symbols for it even in the empty case).
|
||||
if (ehHdrEnd == ehHdrStart)
|
||||
return false;
|
||||
_LIBUNWIND_LOG("unsupported .eh_frame_hdr at %" PRIx64
|
||||
": need at least 4 bytes of data but only got %zd",
|
||||
static_cast<uint64_t>(ehHdrStart),
|
||||
static_cast<size_t>(ehHdrEnd - ehHdrStart));
|
||||
return false;
|
||||
}
|
||||
uint8_t version = addressSpace.get8(p++);
|
||||
if (version != 1) {
|
||||
_LIBUNWIND_LOG("unsupported .eh_frame_hdr version: %" PRIu8 " at %" PRIx64,
|
||||
|
||||
6
lib/libunwind/src/FrameHeaderCache.hpp
vendored
6
lib/libunwind/src/FrameHeaderCache.hpp
vendored
@ -31,8 +31,8 @@
|
||||
|
||||
class _LIBUNWIND_HIDDEN FrameHeaderCache {
|
||||
struct CacheEntry {
|
||||
uintptr_t LowPC() { return Info.dso_base; };
|
||||
uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; };
|
||||
uintptr_t LowPC() { return Info.dso_base; }
|
||||
uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; }
|
||||
UnwindInfoSections Info;
|
||||
CacheEntry *Next;
|
||||
};
|
||||
@ -41,7 +41,7 @@ class _LIBUNWIND_HIDDEN FrameHeaderCache {
|
||||
|
||||
// Can't depend on the C++ standard library in libunwind, so use an array to
|
||||
// allocate the entries, and two linked lists for ordering unused and recently
|
||||
// used entries. FIXME: Would the the extra memory for a doubly-linked list
|
||||
// used entries. FIXME: Would the extra memory for a doubly-linked list
|
||||
// be better than the runtime cost of traversing a very short singly-linked
|
||||
// list on a cache miss? The entries themselves are all small and consecutive,
|
||||
// so unlikely to cause page faults when following the pointers. The memory
|
||||
|
||||
20
lib/libunwind/src/Registers.hpp
vendored
20
lib/libunwind/src/Registers.hpp
vendored
@ -619,6 +619,8 @@ public:
|
||||
void setIP(uint32_t value) { _registers.__srr0 = value; }
|
||||
uint64_t getCR() const { return _registers.__cr; }
|
||||
void setCR(uint32_t value) { _registers.__cr = value; }
|
||||
uint64_t getLR() const { return _registers.__lr; }
|
||||
void setLR(uint32_t value) { _registers.__lr = value; }
|
||||
|
||||
private:
|
||||
struct ppc_thread_state_t {
|
||||
@ -1189,6 +1191,8 @@ public:
|
||||
void setIP(uint64_t value) { _registers.__srr0 = value; }
|
||||
uint64_t getCR() const { return _registers.__cr; }
|
||||
void setCR(uint64_t value) { _registers.__cr = value; }
|
||||
uint64_t getLR() const { return _registers.__lr; }
|
||||
void setLR(uint64_t value) { _registers.__lr = value; }
|
||||
|
||||
private:
|
||||
struct ppc64_thread_state_t {
|
||||
@ -2869,7 +2873,7 @@ inline bool Registers_mips_o32::validRegister(int regNum) const {
|
||||
return false;
|
||||
if (regNum <= UNW_MIPS_R31)
|
||||
return true;
|
||||
#if __mips_isa_rev != 6
|
||||
#if __mips_isa_rev < 6
|
||||
if (regNum == UNW_MIPS_HI)
|
||||
return true;
|
||||
if (regNum == UNW_MIPS_LO)
|
||||
@ -2903,10 +2907,12 @@ inline uint32_t Registers_mips_o32::getRegister(int regNum) const {
|
||||
return _registers.__pc;
|
||||
case UNW_REG_SP:
|
||||
return _registers.__r[29];
|
||||
#if __mips_isa_rev < 6
|
||||
case UNW_MIPS_HI:
|
||||
return _registers.__hi;
|
||||
case UNW_MIPS_LO:
|
||||
return _registers.__lo;
|
||||
#endif
|
||||
}
|
||||
_LIBUNWIND_ABORT("unsupported mips_o32 register");
|
||||
}
|
||||
@ -2936,11 +2942,13 @@ inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) {
|
||||
case UNW_REG_SP:
|
||||
_registers.__r[29] = value;
|
||||
return;
|
||||
#if __mips_isa_rev < 6
|
||||
case UNW_MIPS_HI:
|
||||
_registers.__hi = value;
|
||||
return;
|
||||
case UNW_MIPS_LO:
|
||||
_registers.__lo = value;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
_LIBUNWIND_ABORT("unsupported mips_o32 register");
|
||||
@ -3120,10 +3128,12 @@ inline const char *Registers_mips_o32::getRegisterName(int regNum) {
|
||||
return "$f30";
|
||||
case UNW_MIPS_F31:
|
||||
return "$f31";
|
||||
#if __mips_isa_rev < 6
|
||||
case UNW_MIPS_HI:
|
||||
return "$hi";
|
||||
case UNW_MIPS_LO:
|
||||
return "$lo";
|
||||
#endif
|
||||
default:
|
||||
return "unknown register";
|
||||
}
|
||||
@ -3193,7 +3203,7 @@ inline bool Registers_mips_newabi::validRegister(int regNum) const {
|
||||
return false;
|
||||
if (regNum <= UNW_MIPS_R31)
|
||||
return true;
|
||||
#if __mips_isa_rev != 6
|
||||
#if __mips_isa_rev < 6
|
||||
if (regNum == UNW_MIPS_HI)
|
||||
return true;
|
||||
if (regNum == UNW_MIPS_LO)
|
||||
@ -3212,10 +3222,12 @@ inline uint64_t Registers_mips_newabi::getRegister(int regNum) const {
|
||||
return _registers.__pc;
|
||||
case UNW_REG_SP:
|
||||
return _registers.__r[29];
|
||||
#if __mips_isa_rev < 6
|
||||
case UNW_MIPS_HI:
|
||||
return _registers.__hi;
|
||||
case UNW_MIPS_LO:
|
||||
return _registers.__lo;
|
||||
#endif
|
||||
}
|
||||
_LIBUNWIND_ABORT("unsupported mips_newabi register");
|
||||
}
|
||||
@ -3233,12 +3245,14 @@ inline void Registers_mips_newabi::setRegister(int regNum, uint64_t value) {
|
||||
case UNW_REG_SP:
|
||||
_registers.__r[29] = value;
|
||||
return;
|
||||
#if __mips_isa_rev < 6
|
||||
case UNW_MIPS_HI:
|
||||
_registers.__hi = value;
|
||||
return;
|
||||
case UNW_MIPS_LO:
|
||||
_registers.__lo = value;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
_LIBUNWIND_ABORT("unsupported mips_newabi register");
|
||||
}
|
||||
@ -3417,10 +3431,12 @@ inline const char *Registers_mips_newabi::getRegisterName(int regNum) {
|
||||
return "$f30";
|
||||
case UNW_MIPS_F31:
|
||||
return "$f31";
|
||||
#if __mips_isa_rev < 6
|
||||
case UNW_MIPS_HI:
|
||||
return "$hi";
|
||||
case UNW_MIPS_LO:
|
||||
return "$lo";
|
||||
#endif
|
||||
default:
|
||||
return "unknown register";
|
||||
}
|
||||
|
||||
11
lib/libunwind/src/Unwind-sjlj.c
vendored
11
lib/libunwind/src/Unwind-sjlj.c
vendored
@ -82,7 +82,8 @@ struct _Unwind_FunctionContext {
|
||||
static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;
|
||||
#endif
|
||||
|
||||
static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
|
||||
static struct _Unwind_FunctionContext *
|
||||
__Unwind_SjLj_GetTopOfFunctionStack(void) {
|
||||
#if defined(__APPLE__)
|
||||
return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
|
||||
#else
|
||||
@ -426,7 +427,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
|
||||
/// Called by personality handler during phase 2 to alter register values.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
uintptr_t new_value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIuPTR
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIxPTR
|
||||
")",
|
||||
(void *)context, index, new_value);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
@ -437,7 +438,7 @@ _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIu32,
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
|
||||
(void *)context, ufc->resumeLocation + 1);
|
||||
return ufc->resumeLocation + 1;
|
||||
}
|
||||
@ -450,7 +451,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||
int *ipBefore) {
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
*ipBefore = 0;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIu32,
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIxPTR,
|
||||
(void *)context, (void *)ipBefore,
|
||||
ufc->resumeLocation + 1);
|
||||
return ufc->resumeLocation + 1;
|
||||
@ -460,7 +461,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||
/// Called by personality handler during phase 2 to alter instruction pointer.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
|
||||
uintptr_t new_value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIuPTR ")",
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIxPTR ")",
|
||||
(void *)context, new_value);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
ufc->resumeLocation = new_value - 1;
|
||||
|
||||
123
lib/libunwind/src/Unwind-wasm.c
vendored
Normal file
123
lib/libunwind/src/Unwind-wasm.c
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//
|
||||
// Implements Wasm exception handling proposal
|
||||
// (https://github.com/WebAssembly/exception-handling) based C++ exceptions
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __USING_WASM_EXCEPTIONS__
|
||||
|
||||
#include "unwind.h"
|
||||
#include <threads.h>
|
||||
|
||||
_Unwind_Reason_Code __gxx_personality_wasm0(int version, _Unwind_Action actions,
|
||||
uint64_t exceptionClass,
|
||||
_Unwind_Exception *unwind_exception,
|
||||
_Unwind_Context *context);
|
||||
|
||||
struct _Unwind_LandingPadContext {
|
||||
// Input information to personality function
|
||||
uintptr_t lpad_index; // landing pad index
|
||||
uintptr_t lsda; // LSDA address
|
||||
|
||||
// Output information computed by personality function
|
||||
uintptr_t selector; // selector value
|
||||
};
|
||||
|
||||
// Communication channel between compiler-generated user code and personality
|
||||
// function
|
||||
thread_local struct _Unwind_LandingPadContext __wasm_lpad_context;
|
||||
|
||||
/// Calls to this function is in landing pads in compiler-generated user code.
|
||||
/// In other EH schemes, stack unwinding is done by libunwind library, which
|
||||
/// calls the personality function for each each frame it lands. On the other
|
||||
/// hand, WebAssembly stack unwinding process is performed by a VM, and the
|
||||
/// personality function cannot be called from there. So the compiler inserts
|
||||
/// a call to this function in landing pads in the user code, which in turn
|
||||
/// calls the personality function.
|
||||
_Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) {
|
||||
struct _Unwind_Exception *exception_object =
|
||||
(struct _Unwind_Exception *)exception_ptr;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_CallPersonality(exception_object=%p)",
|
||||
(void *)exception_object);
|
||||
|
||||
// Reset the selector.
|
||||
__wasm_lpad_context.selector = 0;
|
||||
|
||||
// Call personality function. Wasm does not have two-phase unwinding, so we
|
||||
// only do the cleanup phase.
|
||||
return __gxx_personality_wasm0(
|
||||
1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)&__wasm_lpad_context);
|
||||
}
|
||||
|
||||
/// Called by __cxa_throw.
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_RaiseException(_Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_RaiseException(exception_object=%p)",
|
||||
(void *)exception_object);
|
||||
// Use Wasm EH's 'throw' instruction.
|
||||
__builtin_wasm_throw(0, exception_object);
|
||||
}
|
||||
|
||||
/// Called by __cxa_end_catch.
|
||||
_LIBUNWIND_EXPORT void
|
||||
_Unwind_DeleteException(_Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
|
||||
(void *)(exception_object));
|
||||
if (exception_object->exception_cleanup != NULL)
|
||||
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
|
||||
exception_object);
|
||||
}
|
||||
|
||||
/// Called by personality handler to alter register values.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
uintptr_t value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, index=%d, value=%lu)",
|
||||
(void *)context, index, value);
|
||||
// We only use this function to set __wasm_lpad_context.selector field, which
|
||||
// is index 1 in the personality function.
|
||||
if (index == 1)
|
||||
((struct _Unwind_LandingPadContext *)context)->selector = value;
|
||||
}
|
||||
|
||||
/// Called by personality handler to get instruction pointer.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||
// The result will be used as an 1-based index after decrementing 1, so we
|
||||
// increment 2 here
|
||||
uintptr_t result =
|
||||
((struct _Unwind_LandingPadContext *)context)->lpad_index + 2;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => %lu", (void *)context,
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Not used in Wasm.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
|
||||
uintptr_t value) {}
|
||||
|
||||
/// Called by personality handler to get LSDA for current frame.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
|
||||
uintptr_t result = ((struct _Unwind_LandingPadContext *)context)->lsda;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lx",
|
||||
(void *)context, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Not used in Wasm.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // defined(__USING_WASM_EXCEPTIONS__)
|
||||
181
lib/libunwind/src/UnwindCursor.hpp
vendored
181
lib/libunwind/src/UnwindCursor.hpp
vendored
@ -33,6 +33,8 @@
|
||||
#if defined(_LIBUNWIND_TARGET_LINUX) && \
|
||||
(defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || \
|
||||
defined(_LIBUNWIND_TARGET_S390X))
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
@ -990,6 +992,7 @@ private:
|
||||
R dummy;
|
||||
return stepThroughSigReturn(dummy);
|
||||
}
|
||||
bool isReadableAddr(const pint_t addr) const;
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
bool setInfoForSigReturn(Registers_arm64 &);
|
||||
int stepThroughSigReturn(Registers_arm64 &);
|
||||
@ -2301,27 +2304,39 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
|
||||
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));
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"%s: Look up traceback table of func=%s at %p, pc=%p, "
|
||||
"SP=%p, saves_lr=%d, stores_bc=%d",
|
||||
__func__, functionName, reinterpret_cast<void *>(TBTable),
|
||||
reinterpret_cast<void *>(pc),
|
||||
reinterpret_cast<void *>(registers.getSP()), TBTable->tb.saves_lr,
|
||||
TBTable->tb.stores_bc);
|
||||
}
|
||||
|
||||
#if defined(__powerpc64__)
|
||||
// Instruction to reload TOC register "l r2,40(r1)"
|
||||
// Instruction to reload TOC register "ld 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)"
|
||||
// Instruction to reload TOC register "lwz r2,20(r1)"
|
||||
const uint32_t loadTOCRegInst = 0x80410014;
|
||||
const int32_t unwPPCF0Index = UNW_PPC_F0;
|
||||
const int32_t unwPPCV0Index = UNW_PPC_V0;
|
||||
#endif
|
||||
|
||||
// lastStack points to the stack frame of the next routine up.
|
||||
pint_t curStack = static_cast<pint_t>(registers.getSP());
|
||||
pint_t lastStack = *reinterpret_cast<pint_t *>(curStack);
|
||||
|
||||
if (lastStack == 0)
|
||||
return UNW_STEP_END;
|
||||
|
||||
R newRegisters = registers;
|
||||
|
||||
// lastStack points to the stack frame of the next routine up.
|
||||
pint_t lastStack = *(reinterpret_cast<pint_t *>(registers.getSP()));
|
||||
// If backchain is not stored, use the current stack frame.
|
||||
if (!TBTable->tb.stores_bc)
|
||||
lastStack = curStack;
|
||||
|
||||
// Return address is the address after call site instruction.
|
||||
pint_t returnAddress;
|
||||
@ -2331,33 +2346,41 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
|
||||
reinterpret_cast<void *>(lastStack));
|
||||
|
||||
sigcontext *sigContext = reinterpret_cast<sigcontext *>(
|
||||
reinterpret_cast<char *>(lastStack) + STKMIN);
|
||||
reinterpret_cast<char *>(lastStack) + STKMINALIGN);
|
||||
returnAddress = sigContext->sc_jmpbuf.jmp_context.iar;
|
||||
|
||||
_LIBUNWIND_TRACE_UNWINDING("From sigContext=%p, returnAddress=%p\n",
|
||||
bool useSTKMIN = false;
|
||||
if (returnAddress < 0x10000000) {
|
||||
// Try again using STKMIN.
|
||||
sigContext = reinterpret_cast<sigcontext *>(
|
||||
reinterpret_cast<char *>(lastStack) + STKMIN);
|
||||
returnAddress = sigContext->sc_jmpbuf.jmp_context.iar;
|
||||
if (returnAddress < 0x10000000) {
|
||||
_LIBUNWIND_TRACE_UNWINDING("Bad returnAddress=%p from sigcontext=%p",
|
||||
reinterpret_cast<void *>(returnAddress),
|
||||
reinterpret_cast<void *>(sigContext));
|
||||
return UNW_EBADFRAME;
|
||||
}
|
||||
useSTKMIN = true;
|
||||
}
|
||||
_LIBUNWIND_TRACE_UNWINDING("Returning from a signal handler %s: "
|
||||
"sigContext=%p, returnAddress=%p. "
|
||||
"Seems to be a valid address",
|
||||
useSTKMIN ? "STKMIN" : "STKMINALIGN",
|
||||
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);
|
||||
|
||||
// Save the LR in sigcontext for stepping up when the function that
|
||||
// raised the signal is a leaf function. This LR has the return address
|
||||
// to the caller of the leaf function.
|
||||
newRegisters.setLR(sigContext->sc_jmpbuf.jmp_context.lr);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"Save LR=%p from sigcontext",
|
||||
reinterpret_cast<void *>(sigContext->sc_jmpbuf.jmp_context.lr));
|
||||
|
||||
// Restore GPRs from sigcontext.
|
||||
for (int i = 0; i < 32; ++i)
|
||||
newRegisters.setRegister(i, sigContext->sc_jmpbuf.jmp_context.gpr[i]);
|
||||
@ -2380,13 +2403,26 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
|
||||
}
|
||||
} 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",
|
||||
if (!TBTable->tb.saves_lr && registers.getLR()) {
|
||||
// This case should only occur if we were called from a signal handler
|
||||
// and the signal occurred in a function that doesn't save the LR.
|
||||
returnAddress = static_cast<pint_t>(registers.getLR());
|
||||
_LIBUNWIND_TRACE_UNWINDING("Use saved LR=%p",
|
||||
reinterpret_cast<void *>(returnAddress));
|
||||
} else {
|
||||
// Otherwise, use the LR value in the stack link area.
|
||||
returnAddress = reinterpret_cast<pint_t *>(lastStack)[2];
|
||||
}
|
||||
|
||||
// Reset LR in the current context.
|
||||
newRegisters.setLR(NULL);
|
||||
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"Extract info from lastStack=%p, returnAddress=%p",
|
||||
reinterpret_cast<void *>(lastStack),
|
||||
reinterpret_cast<void *>(returnAddress));
|
||||
_LIBUNWIND_TRACE_UNWINDING("fpr_regs=%d, gpr_regs=%d, saves_cr=%d",
|
||||
TBTable->tb.fpr_saved, TBTable->tb.gpr_saved,
|
||||
TBTable->tb.saves_cr);
|
||||
|
||||
@ -2450,7 +2486,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
|
||||
|
||||
struct vec_ext *vec_ext = reinterpret_cast<struct vec_ext *>(charPtr);
|
||||
|
||||
_LIBUNWIND_TRACE_UNWINDING("vr_saved=%d\n", vec_ext->vr_saved);
|
||||
_LIBUNWIND_TRACE_UNWINDING("vr_saved=%d", vec_ext->vr_saved);
|
||||
|
||||
// Restore vector register(s) if saved on the stack.
|
||||
if (vec_ext->vr_saved) {
|
||||
@ -2480,11 +2516,11 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
|
||||
|
||||
// Do we need to set the TOC register?
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"Current gpr2=%p\n",
|
||||
"Current gpr2=%p",
|
||||
reinterpret_cast<void *>(newRegisters.getRegister(2)));
|
||||
if (firstInstruction == loadTOCRegInst) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"Set gpr2=%p from frame\n",
|
||||
"Set gpr2=%p from frame",
|
||||
reinterpret_cast<void *>(reinterpret_cast<pint_t *>(lastStack)[5]));
|
||||
newRegisters.setRegister(2, reinterpret_cast<pint_t *>(lastStack)[5]);
|
||||
}
|
||||
@ -2516,7 +2552,6 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
|
||||
} else {
|
||||
isSignalFrame = false;
|
||||
}
|
||||
|
||||
return UNW_STEP_SUCCESS;
|
||||
}
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
|
||||
@ -2668,20 +2703,12 @@ 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);
|
||||
// directly accessing it could cause a SIGSEGV.
|
||||
if (!isReadableAddr(pc))
|
||||
return false;
|
||||
auto *instructions = reinterpret_cast<const uint32_t *>(pc);
|
||||
// Look for instructions: mov x8, #0x8b; svc #0x0
|
||||
if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
|
||||
instructions[1] != 0xd4000001)
|
||||
if (instructions[0] != 0xd2801168 || instructions[1] != 0xd4000001)
|
||||
return false;
|
||||
|
||||
_info = {};
|
||||
@ -2730,18 +2757,17 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
|
||||
template <typename A, typename R>
|
||||
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_riscv &) {
|
||||
const pint_t pc = static_cast<pint_t>(getReg(UNW_REG_IP));
|
||||
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);
|
||||
// The PC might contain an invalid address if the unwind info is bad, so
|
||||
// directly accessing it could cause a SIGSEGV.
|
||||
if (!isReadableAddr(pc))
|
||||
return false;
|
||||
const auto *instructions = reinterpret_cast<const uint32_t *>(pc);
|
||||
// Look for the two instructions used in the sigreturn trampoline
|
||||
// __vdso_rt_sigreturn:
|
||||
//
|
||||
// 0x08b00893 li a7,0x8b
|
||||
// 0x00000073 ecall
|
||||
if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
|
||||
instructions[1] != 0x00000073)
|
||||
if (instructions[0] != 0x08b00893 || instructions[1] != 0x00000073)
|
||||
return false;
|
||||
|
||||
_info = {};
|
||||
@ -2790,13 +2816,11 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_s390x &) {
|
||||
// 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)) {
|
||||
// directly accessing it could cause a SIGSEGV.
|
||||
if (!isReadableAddr(pc))
|
||||
return false;
|
||||
const auto inst = *reinterpret_cast<const uint16_t *>(pc);
|
||||
if (inst == 0x0a77 || inst == 0x0aad) {
|
||||
_info = {};
|
||||
_info.start_ip = pc;
|
||||
_info.end_ip = pc + 2;
|
||||
@ -2942,6 +2966,37 @@ bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
|
||||
buf, bufLen, offset);
|
||||
}
|
||||
|
||||
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
|
||||
template <typename A, typename R>
|
||||
bool UnwindCursor<A, R>::isReadableAddr(const pint_t addr) const {
|
||||
// We use SYS_rt_sigprocmask, inspired by Abseil's AddressIsReadable.
|
||||
|
||||
const auto sigsetAddr = reinterpret_cast<sigset_t *>(addr);
|
||||
// We have to check that addr is nullptr because sigprocmask allows that
|
||||
// as an argument without failure.
|
||||
if (!sigsetAddr)
|
||||
return false;
|
||||
const auto saveErrno = errno;
|
||||
// We MUST use a raw syscall here, as wrappers may try to access
|
||||
// sigsetAddr which may cause a SIGSEGV. A raw syscall however is
|
||||
// safe. Additionally, we need to pass the kernel_sigset_size, which is
|
||||
// different from libc sizeof(sigset_t). For the majority of architectures,
|
||||
// it's 64 bits (_NSIG), and libc NSIG is _NSIG + 1.
|
||||
const auto kernelSigsetSize = NSIG / 8;
|
||||
[[maybe_unused]] const int Result = syscall(
|
||||
SYS_rt_sigprocmask, /*how=*/~0, sigsetAddr, nullptr, kernelSigsetSize);
|
||||
// Because our "how" is invalid, this syscall should always fail, and our
|
||||
// errno should always be EINVAL or an EFAULT. This relies on the Linux
|
||||
// kernel to check copy_from_user before checking if the "how" argument is
|
||||
// invalid.
|
||||
assert(Result == -1);
|
||||
assert(errno == EFAULT || errno == EINVAL);
|
||||
const auto readable = errno != EFAULT;
|
||||
errno = saveErrno;
|
||||
return readable;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_USE_CET)
|
||||
extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) {
|
||||
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||
|
||||
2
lib/libunwind/src/UnwindLevel1-gcc-ext.c
vendored
2
lib/libunwind/src/UnwindLevel1-gcc-ext.c
vendored
@ -143,7 +143,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||
// Create a mock exception object for force unwinding.
|
||||
_Unwind_Exception ex;
|
||||
memset(&ex, '\0', sizeof(ex));
|
||||
strcpy((char *)&ex.exception_class, "CLNGUNW");
|
||||
memcpy(&ex.exception_class, "CLNGUNW", sizeof(ex.exception_class));
|
||||
#endif
|
||||
|
||||
// walk each frame
|
||||
|
||||
6
lib/libunwind/src/UnwindRegistersRestore.S
vendored
6
lib/libunwind/src/UnwindRegistersRestore.S
vendored
@ -673,7 +673,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
|
||||
ldr d30, [x0, #0x200]
|
||||
ldr d31, [x0, #0x208]
|
||||
|
||||
// Finally, restore sp. This must be done after the the last read from the
|
||||
// Finally, restore sp. This must be done after the last read from the
|
||||
// context struct, because it is allocated on the stack, and an exception
|
||||
// could clobber the de-allocated portion of the stack after sp has been
|
||||
// restored.
|
||||
@ -993,11 +993,13 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
|
||||
ldc1 $f31, (4 * 36 + 8 * 31)($4)
|
||||
#endif
|
||||
#endif
|
||||
#if __mips_isa_rev < 6
|
||||
// restore hi and lo
|
||||
lw $8, (4 * 33)($4)
|
||||
mthi $8
|
||||
lw $8, (4 * 34)($4)
|
||||
mtlo $8
|
||||
#endif
|
||||
// r0 is zero
|
||||
lw $1, (4 * 1)($4)
|
||||
lw $2, (4 * 2)($4)
|
||||
@ -1054,11 +1056,13 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
|
||||
ldc1 $f\i, (280+8*\i)($4)
|
||||
.endr
|
||||
#endif
|
||||
#if __mips_isa_rev < 6
|
||||
// restore hi and lo
|
||||
ld $8, (8 * 33)($4)
|
||||
mthi $8
|
||||
ld $8, (8 * 34)($4)
|
||||
mtlo $8
|
||||
#endif
|
||||
// r0 is zero
|
||||
ld $1, (8 * 1)($4)
|
||||
ld $2, (8 * 2)($4)
|
||||
|
||||
44
lib/libunwind/src/UnwindRegistersSave.S
vendored
44
lib/libunwind/src/UnwindRegistersSave.S
vendored
@ -174,11 +174,13 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||
sw $31, (4 * 31)($4)
|
||||
# Store return address to pc
|
||||
sw $31, (4 * 32)($4)
|
||||
#if __mips_isa_rev < 6
|
||||
# hi and lo
|
||||
mfhi $8
|
||||
sw $8, (4 * 33)($4)
|
||||
mflo $8
|
||||
sw $8, (4 * 34)($4)
|
||||
#endif
|
||||
#ifdef __mips_hard_float
|
||||
#if __mips_fpr != 64
|
||||
sdc1 $f0, (4 * 36 + 8 * 0)($4)
|
||||
@ -255,11 +257,13 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||
.endr
|
||||
# Store return address to pc
|
||||
sd $31, (8 * 32)($4)
|
||||
#if __mips_isa_rev < 6
|
||||
# hi and lo
|
||||
mfhi $8
|
||||
sd $8, (8 * 33)($4)
|
||||
mflo $8
|
||||
sd $8, (8 * 34)($4)
|
||||
#endif
|
||||
#ifdef __mips_hard_float
|
||||
.irp i,FROM_0_TO_31
|
||||
sdc1 $f\i, (280+8*\i)($4)
|
||||
@ -301,9 +305,21 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||
mflr 0
|
||||
std 0, PPC64_OFFS_SRR0(3) // store lr as ssr0
|
||||
PPC64_STR(1)
|
||||
PPC64_STR(4) // Save r4 first since it will be used for fixing r2.
|
||||
#if defined(_AIX)
|
||||
// The TOC register (r2) was changed by the glue code if unw_getcontext
|
||||
// is called from a different module. Save the original TOC register
|
||||
// in the context if this is the case.
|
||||
mflr 4
|
||||
lwz 4, 0(4) // Get the first instruction at the return address.
|
||||
xoris 0, 4, 0xe841 // Is it reloading the TOC register "ld 2,40(1)"?
|
||||
cmplwi 0, 0x28
|
||||
bne 0, LnoR2Fix // No need to fix up r2 if it is not.
|
||||
ld 2, 40(1) // Use the saved TOC register in the stack.
|
||||
LnoR2Fix:
|
||||
#endif
|
||||
PPC64_STR(2)
|
||||
PPC64_STR(3)
|
||||
PPC64_STR(4)
|
||||
PPC64_STR(5)
|
||||
PPC64_STR(6)
|
||||
PPC64_STR(7)
|
||||
@ -336,7 +352,12 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||
std 0, PPC64_OFFS_CR(3)
|
||||
mfxer 0
|
||||
std 0, PPC64_OFFS_XER(3)
|
||||
#if defined(_AIX)
|
||||
// LR value saved from the register is not used, initialize it to 0.
|
||||
li 0, 0
|
||||
#else
|
||||
mflr 0
|
||||
#endif
|
||||
std 0, PPC64_OFFS_LR(3)
|
||||
mfctr 0
|
||||
std 0, PPC64_OFFS_CTR(3)
|
||||
@ -543,9 +564,21 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||
mflr 0
|
||||
stw 0, 0(3) // store lr as ssr0
|
||||
stw 1, 12(3)
|
||||
stw 4, 24(3) // Save r4 first since it will be used for fixing r2.
|
||||
#if defined(_AIX)
|
||||
// The TOC register (r2) was changed by the glue code if unw_getcontext
|
||||
// is called from a different module. Save the original TOC register
|
||||
// in the context if this is the case.
|
||||
mflr 4
|
||||
lwz 4, 0(4) // Get the instruction at the return address.
|
||||
xoris 0, 4, 0x8041 // Is it reloading the TOC register "lwz 2,20(1)"?
|
||||
cmplwi 0, 0x14
|
||||
bne 0, LnoR2Fix // No need to fix up r2 if it is not.
|
||||
lwz 2, 20(1) // Use the saved TOC register in the stack.
|
||||
LnoR2Fix:
|
||||
#endif
|
||||
stw 2, 16(3)
|
||||
stw 3, 20(3)
|
||||
stw 4, 24(3)
|
||||
stw 5, 28(3)
|
||||
stw 6, 32(3)
|
||||
stw 7, 36(3)
|
||||
@ -582,6 +615,11 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||
// save CR registers
|
||||
mfcr 0
|
||||
stw 0, 136(3)
|
||||
#if defined(_AIX)
|
||||
// LR value from the register is not used, initialize it to 0.
|
||||
li 0, 0
|
||||
stw 0, 144(3)
|
||||
#endif
|
||||
// save CTR register
|
||||
mfctr 0
|
||||
stw 0, 148(3)
|
||||
@ -742,7 +780,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||
@
|
||||
@ On entry:
|
||||
@ thread_state pointer is in r0
|
||||
@
|
||||
@
|
||||
@ Per EHABI #4.7 this only saves the core integer registers.
|
||||
@ EHABI #7.4.5 notes that in general all VRS registers should be restored
|
||||
@ however this is very hard to do for VFP registers because it is unknown
|
||||
|
||||
14
lib/libunwind/src/config.h
vendored
14
lib/libunwind/src/config.h
vendored
@ -46,6 +46,12 @@
|
||||
#elif defined(_AIX)
|
||||
// The traceback table at the end of each function is used for unwinding.
|
||||
#define _LIBUNWIND_SUPPORT_TBTAB_UNWIND 1
|
||||
#elif defined(__HAIKU__)
|
||||
#if defined(_LIBUNWIND_USE_HAIKU_BSD_LIB)
|
||||
#define _LIBUNWIND_USE_DL_ITERATE_PHDR 1
|
||||
#endif
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
|
||||
#else
|
||||
// Assume an ELF system with a dl_iterate_phdr function.
|
||||
#define _LIBUNWIND_USE_DL_ITERATE_PHDR 1
|
||||
@ -83,7 +89,7 @@
|
||||
__asm__(".globl " SYMBOL_NAME(aliasname)); \
|
||||
__asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \
|
||||
_LIBUNWIND_ALIAS_VISIBILITY(SYMBOL_NAME(aliasname))
|
||||
#elif defined(__ELF__) || defined(_AIX)
|
||||
#elif defined(__ELF__) || defined(_AIX) || defined(__wasm__)
|
||||
#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \
|
||||
extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \
|
||||
__attribute__((weak, alias(#name)));
|
||||
@ -108,10 +114,6 @@
|
||||
#define _LIBUNWIND_BUILD_SJLJ_APIS
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
|
||||
#define _LIBUNWIND_SUPPORT_FRAME_APIS
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \
|
||||
(!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) || \
|
||||
defined(__mips__) || defined(__riscv) || defined(__hexagon__) || \
|
||||
@ -125,7 +127,7 @@
|
||||
#if defined(_LIBUNWIND_REMEMBER_STACK_ALLOC) || defined(__APPLE__) || \
|
||||
defined(__linux__) || defined(__ANDROID__) || defined(__MINGW32__) || \
|
||||
defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
#define _LIBUNWIND_REMEMBER_ALLOC(_size) alloca(_size)
|
||||
#define _LIBUNWIND_REMEMBER_ALLOC(_size) __builtin_alloca(_size)
|
||||
#define _LIBUNWIND_REMEMBER_FREE(_ptr) \
|
||||
do { \
|
||||
} while (0)
|
||||
|
||||
7
lib/libunwind/src/libunwind.cpp
vendored
7
lib/libunwind/src/libunwind.cpp
vendored
@ -26,7 +26,7 @@
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
|
||||
#include "AddressSpace.hpp"
|
||||
#include "UnwindCursor.hpp"
|
||||
|
||||
@ -324,7 +324,7 @@ void __unw_add_dynamic_eh_frame_section(unw_word_t eh_frame_start) {
|
||||
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
|
||||
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
|
||||
auto p = (LocalAddressSpace::pint_t)eh_frame_start;
|
||||
while (true) {
|
||||
while (LocalAddressSpace::sThisAddressSpace.get32(p)) {
|
||||
if (CFI_Parser<LocalAddressSpace>::decodeFDE(
|
||||
LocalAddressSpace::sThisAddressSpace, p, &fdeInfo, &cieInfo,
|
||||
true) == NULL) {
|
||||
@ -347,7 +347,8 @@ void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) {
|
||||
}
|
||||
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#endif // !defined(__USING_SJLJ_EXCEPTIONS__) &&
|
||||
// !defined(__USING_WASM_EXCEPTIONS__)
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
|
||||
@ -164,6 +164,7 @@ const unwind_src_list = [_][]const u8{
|
||||
"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 ++ "Unwind-wasm.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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user