libunwind: update to LLVM 18

release/18.x branch, commit 78b99c73ee4b96fe9ce0e294d4632326afb2db42
This commit is contained in:
Andrew Kelley 2024-04-26 14:40:08 -07:00
parent a6856ef6d2
commit 6295415da7
17 changed files with 393 additions and 132 deletions

View File

@ -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

View File

@ -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,
};

View File

@ -372,7 +372,7 @@ enum {
// .quad except_tab1
//
//
// Notes: There is no need for any labels in the the __compact_unwind section.
// 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.
//

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -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";
}

View File

@ -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
View 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__)

View File

@ -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);
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;
bool useSTKMIN = false;
if (returnAddress < 0x10000000) {
_LIBUNWIND_TRACE_UNWINDING("Bad returnAddress=%p\n",
reinterpret_cast<void *>(returnAddress));
// 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;
} else {
_LIBUNWIND_TRACE_UNWINDING("Tried again using STKMINALIGN: "
}
useSTKMIN = true;
}
_LIBUNWIND_TRACE_UNWINDING("Returning from a signal handler %s: "
"sigContext=%p, returnAddress=%p. "
"Seems to be a valid address\n",
"Seems to be a valid address",
useSTKMIN ? "STKMIN" : "STKMINALIGN",
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",
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\n",
_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;

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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__

View File

@ -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",