Skip to content

Commit c660b1c

Browse files
trungnt2910svkeerthy
authored andcommitted
[libunwind][Haiku] Fix signal frame unwinding (#135367)
The current unwinding implementation on Haiku is messy and broken. 1. It searches weird paths for private headers, which is breaking builds in consuming projects, such as dotnet/runtime. 2. It does not even work, due to relying on incorrect private offsets. This commit strips all references to private headers and ports a working signal frame implementation. It has been tested against `tests/signal_unwind.pass.cpp` and can go pass the signal frame.
1 parent 2f285cf commit c660b1c

File tree

2 files changed

+100
-77
lines changed

2 files changed

+100
-77
lines changed

libunwind/src/CMakeLists.txt

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -118,22 +118,6 @@ if (HAIKU)
118118

119119
add_compile_flags("-D_DEFAULT_SOURCE")
120120
add_compile_flags("-DPT_GNU_EH_FRAME=PT_EH_FRAME")
121-
122-
find_path(LIBUNWIND_HAIKU_PRIVATE_HEADERS
123-
"commpage_defs.h"
124-
PATHS ${CMAKE_SYSTEM_INCLUDE_PATH}
125-
PATH_SUFFIXES "/private/system"
126-
NO_DEFAULT_PATH
127-
REQUIRED)
128-
129-
include_directories(SYSTEM "${LIBUNWIND_HAIKU_PRIVATE_HEADERS}")
130-
if (LIBUNWIND_TARGET_TRIPLE)
131-
if (${LIBUNWIND_TARGET_TRIPLE} MATCHES "^x86_64")
132-
include_directories(SYSTEM "${LIBUNWIND_HAIKU_PRIVATE_HEADERS}/arch/x86_64")
133-
endif()
134-
else()
135-
include_directories(SYSTEM "${LIBUNWIND_HAIKU_PRIVATE_HEADERS}/arch/${CMAKE_SYSTEM_PROCESSOR}")
136-
endif()
137121
endif ()
138122

139123
string(REPLACE ";" " " LIBUNWIND_COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}")

libunwind/src/UnwindCursor.hpp

Lines changed: 100 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
#define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
4242
#endif
4343

44+
#if defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64)
45+
#include <OS.h>
46+
#include <signal.h>
47+
#define _LIBUNWIND_CHECK_HAIKU_SIGRETURN 1
48+
#endif
49+
4450
#include "AddressSpace.hpp"
4551
#include "CompactUnwinder.hpp"
4652
#include "config.h"
@@ -1031,7 +1037,7 @@ class UnwindCursor : public AbstractUnwindCursor{
10311037
template <typename Registers> int stepThroughSigReturn(Registers &) {
10321038
return UNW_STEP_END;
10331039
}
1034-
#elif defined(_LIBUNWIND_TARGET_HAIKU)
1040+
#elif defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
10351041
bool setInfoForSigReturn();
10361042
int stepThroughSigReturn();
10371043
#endif
@@ -2630,7 +2636,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
26302636
template <typename A, typename R>
26312637
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
26322638
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
2633-
defined(_LIBUNWIND_TARGET_HAIKU)
2639+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
26342640
_isSigReturn = false;
26352641
#endif
26362642

@@ -2755,7 +2761,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
27552761
#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
27562762

27572763
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
2758-
defined(_LIBUNWIND_TARGET_HAIKU)
2764+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
27592765
if (setInfoForSigReturn())
27602766
return;
27612767
#endif
@@ -2831,63 +2837,6 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
28312837
_isSignalFrame = true;
28322838
return UNW_STEP_SUCCESS;
28332839
}
2834-
2835-
#elif defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64)
2836-
#include <commpage_defs.h>
2837-
#include <signal.h>
2838-
2839-
extern "C" {
2840-
extern void *__gCommPageAddress;
2841-
}
2842-
2843-
template <typename A, typename R>
2844-
bool UnwindCursor<A, R>::setInfoForSigReturn() {
2845-
#if defined(_LIBUNWIND_TARGET_X86_64)
2846-
addr_t signal_handler =
2847-
(((addr_t *)__gCommPageAddress)[COMMPAGE_ENTRY_X86_SIGNAL_HANDLER] +
2848-
(addr_t)__gCommPageAddress);
2849-
addr_t signal_handler_ret = signal_handler + 45;
2850-
#endif
2851-
pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
2852-
if (pc == signal_handler_ret) {
2853-
_info = {};
2854-
_info.start_ip = signal_handler;
2855-
_info.end_ip = signal_handler_ret;
2856-
_isSigReturn = true;
2857-
return true;
2858-
}
2859-
return false;
2860-
}
2861-
2862-
template <typename A, typename R>
2863-
int UnwindCursor<A, R>::stepThroughSigReturn() {
2864-
_isSignalFrame = true;
2865-
pint_t sp = _registers.getSP();
2866-
#if defined(_LIBUNWIND_TARGET_X86_64)
2867-
vregs *regs = (vregs *)(sp + 0x70);
2868-
2869-
_registers.setRegister(UNW_REG_IP, regs->rip);
2870-
_registers.setRegister(UNW_REG_SP, regs->rsp);
2871-
_registers.setRegister(UNW_X86_64_RAX, regs->rax);
2872-
_registers.setRegister(UNW_X86_64_RDX, regs->rdx);
2873-
_registers.setRegister(UNW_X86_64_RCX, regs->rcx);
2874-
_registers.setRegister(UNW_X86_64_RBX, regs->rbx);
2875-
_registers.setRegister(UNW_X86_64_RSI, regs->rsi);
2876-
_registers.setRegister(UNW_X86_64_RDI, regs->rdi);
2877-
_registers.setRegister(UNW_X86_64_RBP, regs->rbp);
2878-
_registers.setRegister(UNW_X86_64_R8, regs->r8);
2879-
_registers.setRegister(UNW_X86_64_R9, regs->r9);
2880-
_registers.setRegister(UNW_X86_64_R10, regs->r10);
2881-
_registers.setRegister(UNW_X86_64_R11, regs->r11);
2882-
_registers.setRegister(UNW_X86_64_R12, regs->r12);
2883-
_registers.setRegister(UNW_X86_64_R13, regs->r13);
2884-
_registers.setRegister(UNW_X86_64_R14, regs->r14);
2885-
_registers.setRegister(UNW_X86_64_R15, regs->r15);
2886-
// TODO: XMM
2887-
#endif
2888-
2889-
return UNW_STEP_SUCCESS;
2890-
}
28912840
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
28922841
// defined(_LIBUNWIND_TARGET_AARCH64)
28932842

@@ -3103,6 +3052,96 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
31033052
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
31043053
// defined(_LIBUNWIND_TARGET_S390X)
31053054

3055+
#if defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
3056+
template <typename A, typename R>
3057+
bool UnwindCursor<A, R>::setInfoForSigReturn() {
3058+
Dl_info dlinfo;
3059+
const auto isSignalHandler = [&](pint_t addr) {
3060+
if (!dladdr(reinterpret_cast<void *>(addr), &dlinfo))
3061+
return false;
3062+
if (strcmp(dlinfo.dli_fname, "commpage"))
3063+
return false;
3064+
if (dlinfo.dli_sname == NULL ||
3065+
strcmp(dlinfo.dli_sname, "commpage_signal_handler"))
3066+
return false;
3067+
return true;
3068+
};
3069+
3070+
pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
3071+
if (!isSignalHandler(pc))
3072+
return false;
3073+
3074+
pint_t start = reinterpret_cast<pint_t>(dlinfo.dli_saddr);
3075+
3076+
static size_t signalHandlerSize = 0;
3077+
if (signalHandlerSize == 0) {
3078+
size_t boundLow = 0;
3079+
size_t boundHigh = static_cast<size_t>(-1);
3080+
3081+
area_info areaInfo;
3082+
if (get_area_info(area_for(dlinfo.dli_saddr), &areaInfo) == B_OK)
3083+
boundHigh = areaInfo.size;
3084+
3085+
while (boundLow < boundHigh) {
3086+
size_t boundMid = boundLow + ((boundHigh - boundLow) / 2);
3087+
pint_t test = start + boundMid;
3088+
if (test >= start && isSignalHandler(test))
3089+
boundLow = boundMid + 1;
3090+
else
3091+
boundHigh = boundMid;
3092+
}
3093+
3094+
signalHandlerSize = boundHigh;
3095+
}
3096+
3097+
_info = {};
3098+
_info.start_ip = start;
3099+
_info.end_ip = start + signalHandlerSize;
3100+
_isSigReturn = true;
3101+
3102+
return true;
3103+
}
3104+
3105+
template <typename A, typename R>
3106+
int UnwindCursor<A, R>::stepThroughSigReturn() {
3107+
_isSignalFrame = true;
3108+
3109+
#if defined(_LIBUNWIND_TARGET_X86_64)
3110+
// Layout of the stack before function call:
3111+
// - signal_frame_data
3112+
// + siginfo_t (public struct, fairly stable)
3113+
// + ucontext_t (public struct, fairly stable)
3114+
// - mcontext_t -> Offset 0x70, this is what we want.
3115+
// - frame->ip (8 bytes)
3116+
// - frame->bp (8 bytes). Not written by the kernel,
3117+
// but the signal handler has a "push %rbp" instruction.
3118+
pint_t bp = this->getReg(UNW_X86_64_RBP);
3119+
vregs *regs = (vregs *)(bp + 0x70);
3120+
3121+
_registers.setRegister(UNW_REG_IP, regs->rip);
3122+
_registers.setRegister(UNW_REG_SP, regs->rsp);
3123+
_registers.setRegister(UNW_X86_64_RAX, regs->rax);
3124+
_registers.setRegister(UNW_X86_64_RDX, regs->rdx);
3125+
_registers.setRegister(UNW_X86_64_RCX, regs->rcx);
3126+
_registers.setRegister(UNW_X86_64_RBX, regs->rbx);
3127+
_registers.setRegister(UNW_X86_64_RSI, regs->rsi);
3128+
_registers.setRegister(UNW_X86_64_RDI, regs->rdi);
3129+
_registers.setRegister(UNW_X86_64_RBP, regs->rbp);
3130+
_registers.setRegister(UNW_X86_64_R8, regs->r8);
3131+
_registers.setRegister(UNW_X86_64_R9, regs->r9);
3132+
_registers.setRegister(UNW_X86_64_R10, regs->r10);
3133+
_registers.setRegister(UNW_X86_64_R11, regs->r11);
3134+
_registers.setRegister(UNW_X86_64_R12, regs->r12);
3135+
_registers.setRegister(UNW_X86_64_R13, regs->r13);
3136+
_registers.setRegister(UNW_X86_64_R14, regs->r14);
3137+
_registers.setRegister(UNW_X86_64_R15, regs->r15);
3138+
// TODO: XMM
3139+
#endif // defined(_LIBUNWIND_TARGET_X86_64)
3140+
3141+
return UNW_STEP_SUCCESS;
3142+
}
3143+
#endif // defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
3144+
31063145
template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
31073146
(void)stage2;
31083147
// Bottom of stack is defined is when unwind info cannot be found.
@@ -3112,7 +3151,7 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
31123151
// Use unwinding info to modify register set as if function returned.
31133152
int result;
31143153
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
3115-
defined(_LIBUNWIND_TARGET_HAIKU)
3154+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
31163155
if (_isSigReturn) {
31173156
result = this->stepThroughSigReturn();
31183157
} else

0 commit comments

Comments
 (0)