Skip to content

Commit 7d36309

Browse files
committed
[libunwind][Haiku] Fix signal frame unwinding
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 5b384c3 commit 7d36309

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"
@@ -1015,7 +1021,7 @@ class UnwindCursor : public AbstractUnwindCursor{
10151021
template <typename Registers> int stepThroughSigReturn(Registers &) {
10161022
return UNW_STEP_END;
10171023
}
1018-
#elif defined(_LIBUNWIND_TARGET_HAIKU)
1024+
#elif defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
10191025
bool setInfoForSigReturn();
10201026
int stepThroughSigReturn();
10211027
#endif
@@ -2559,7 +2565,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
25592565
template <typename A, typename R>
25602566
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
25612567
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
2562-
defined(_LIBUNWIND_TARGET_HAIKU)
2568+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
25632569
_isSigReturn = false;
25642570
#endif
25652571

@@ -2684,7 +2690,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
26842690
#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
26852691

26862692
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
2687-
defined(_LIBUNWIND_TARGET_HAIKU)
2693+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
26882694
if (setInfoForSigReturn())
26892695
return;
26902696
#endif
@@ -2760,63 +2766,6 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
27602766
_isSignalFrame = true;
27612767
return UNW_STEP_SUCCESS;
27622768
}
2763-
2764-
#elif defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64)
2765-
#include <commpage_defs.h>
2766-
#include <signal.h>
2767-
2768-
extern "C" {
2769-
extern void *__gCommPageAddress;
2770-
}
2771-
2772-
template <typename A, typename R>
2773-
bool UnwindCursor<A, R>::setInfoForSigReturn() {
2774-
#if defined(_LIBUNWIND_TARGET_X86_64)
2775-
addr_t signal_handler =
2776-
(((addr_t *)__gCommPageAddress)[COMMPAGE_ENTRY_X86_SIGNAL_HANDLER] +
2777-
(addr_t)__gCommPageAddress);
2778-
addr_t signal_handler_ret = signal_handler + 45;
2779-
#endif
2780-
pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
2781-
if (pc == signal_handler_ret) {
2782-
_info = {};
2783-
_info.start_ip = signal_handler;
2784-
_info.end_ip = signal_handler_ret;
2785-
_isSigReturn = true;
2786-
return true;
2787-
}
2788-
return false;
2789-
}
2790-
2791-
template <typename A, typename R>
2792-
int UnwindCursor<A, R>::stepThroughSigReturn() {
2793-
_isSignalFrame = true;
2794-
pint_t sp = _registers.getSP();
2795-
#if defined(_LIBUNWIND_TARGET_X86_64)
2796-
vregs *regs = (vregs *)(sp + 0x70);
2797-
2798-
_registers.setRegister(UNW_REG_IP, regs->rip);
2799-
_registers.setRegister(UNW_REG_SP, regs->rsp);
2800-
_registers.setRegister(UNW_X86_64_RAX, regs->rax);
2801-
_registers.setRegister(UNW_X86_64_RDX, regs->rdx);
2802-
_registers.setRegister(UNW_X86_64_RCX, regs->rcx);
2803-
_registers.setRegister(UNW_X86_64_RBX, regs->rbx);
2804-
_registers.setRegister(UNW_X86_64_RSI, regs->rsi);
2805-
_registers.setRegister(UNW_X86_64_RDI, regs->rdi);
2806-
_registers.setRegister(UNW_X86_64_RBP, regs->rbp);
2807-
_registers.setRegister(UNW_X86_64_R8, regs->r8);
2808-
_registers.setRegister(UNW_X86_64_R9, regs->r9);
2809-
_registers.setRegister(UNW_X86_64_R10, regs->r10);
2810-
_registers.setRegister(UNW_X86_64_R11, regs->r11);
2811-
_registers.setRegister(UNW_X86_64_R12, regs->r12);
2812-
_registers.setRegister(UNW_X86_64_R13, regs->r13);
2813-
_registers.setRegister(UNW_X86_64_R14, regs->r14);
2814-
_registers.setRegister(UNW_X86_64_R15, regs->r15);
2815-
// TODO: XMM
2816-
#endif
2817-
2818-
return UNW_STEP_SUCCESS;
2819-
}
28202769
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
28212770
// defined(_LIBUNWIND_TARGET_AARCH64)
28222771

@@ -3032,6 +2981,96 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
30322981
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
30332982
// defined(_LIBUNWIND_TARGET_S390X)
30342983

2984+
#if defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
2985+
template <typename A, typename R>
2986+
bool UnwindCursor<A, R>::setInfoForSigReturn() {
2987+
Dl_info dlinfo;
2988+
const auto isSignalHandler = [&](pint_t addr) {
2989+
if (!dladdr(reinterpret_cast<void *>(addr), &dlinfo))
2990+
return false;
2991+
if (strcmp(dlinfo.dli_fname, "commpage"))
2992+
return false;
2993+
if (dlinfo.dli_sname == NULL ||
2994+
strcmp(dlinfo.dli_sname, "commpage_signal_handler"))
2995+
return false;
2996+
return true;
2997+
};
2998+
2999+
pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
3000+
if (!isSignalHandler(pc))
3001+
return false;
3002+
3003+
pint_t start = reinterpret_cast<pint_t>(dlinfo.dli_saddr);
3004+
3005+
static size_t signalHandlerSize = 0;
3006+
if (signalHandlerSize == 0) {
3007+
size_t boundLow = 0;
3008+
size_t boundHigh = static_cast<size_t>(-1);
3009+
3010+
area_info areaInfo;
3011+
if (get_area_info(area_for(dlinfo.dli_saddr), &areaInfo) == B_OK)
3012+
boundHigh = areaInfo.size;
3013+
3014+
while (boundLow < boundHigh) {
3015+
size_t boundMid = boundLow + ((boundHigh - boundLow) / 2);
3016+
pint_t test = start + boundMid;
3017+
if (test >= start && isSignalHandler(test))
3018+
boundLow = boundMid + 1;
3019+
else
3020+
boundHigh = boundMid;
3021+
}
3022+
3023+
signalHandlerSize = boundHigh;
3024+
}
3025+
3026+
_info = {};
3027+
_info.start_ip = start;
3028+
_info.end_ip = start + signalHandlerSize;
3029+
_isSigReturn = true;
3030+
3031+
return true;
3032+
}
3033+
3034+
template <typename A, typename R>
3035+
int UnwindCursor<A, R>::stepThroughSigReturn() {
3036+
_isSignalFrame = true;
3037+
3038+
#if defined(_LIBUNWIND_TARGET_X86_64)
3039+
// Layout of the stack before function call:
3040+
// - signal_frame_data
3041+
// + siginfo_t (public struct, fairly stable)
3042+
// + ucontext_t (public struct, fairly stable)
3043+
// - mcontext_t -> Offset 0x70, this is what we want.
3044+
// - frame->ip (8 bytes)
3045+
// - frame->bp (8 bytes). Not written by the kernel,
3046+
// but the signal handler has a "push %rbp" instruction.
3047+
pint_t bp = this->getReg(UNW_X86_64_RBP);
3048+
vregs *regs = (vregs *)(bp + 0x70);
3049+
3050+
_registers.setRegister(UNW_REG_IP, regs->rip);
3051+
_registers.setRegister(UNW_REG_SP, regs->rsp);
3052+
_registers.setRegister(UNW_X86_64_RAX, regs->rax);
3053+
_registers.setRegister(UNW_X86_64_RDX, regs->rdx);
3054+
_registers.setRegister(UNW_X86_64_RCX, regs->rcx);
3055+
_registers.setRegister(UNW_X86_64_RBX, regs->rbx);
3056+
_registers.setRegister(UNW_X86_64_RSI, regs->rsi);
3057+
_registers.setRegister(UNW_X86_64_RDI, regs->rdi);
3058+
_registers.setRegister(UNW_X86_64_RBP, regs->rbp);
3059+
_registers.setRegister(UNW_X86_64_R8, regs->r8);
3060+
_registers.setRegister(UNW_X86_64_R9, regs->r9);
3061+
_registers.setRegister(UNW_X86_64_R10, regs->r10);
3062+
_registers.setRegister(UNW_X86_64_R11, regs->r11);
3063+
_registers.setRegister(UNW_X86_64_R12, regs->r12);
3064+
_registers.setRegister(UNW_X86_64_R13, regs->r13);
3065+
_registers.setRegister(UNW_X86_64_R14, regs->r14);
3066+
_registers.setRegister(UNW_X86_64_R15, regs->r15);
3067+
// TODO: XMM
3068+
#endif // defined(_LIBUNWIND_TARGET_X86_64)
3069+
3070+
return UNW_STEP_SUCCESS;
3071+
}
3072+
#endif // defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
3073+
30353074
template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
30363075
(void)stage2;
30373076
// Bottom of stack is defined is when unwind info cannot be found.
@@ -3041,7 +3080,7 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
30413080
// Use unwinding info to modify register set as if function returned.
30423081
int result;
30433082
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
3044-
defined(_LIBUNWIND_TARGET_HAIKU)
3083+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
30453084
if (_isSigReturn) {
30463085
result = this->stepThroughSigReturn();
30473086
} else

0 commit comments

Comments
 (0)