Skip to content

Commit 06e16ff

Browse files
committed
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 06e16ff

File tree

2 files changed

+167
-76
lines changed

2 files changed

+167
-76
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: 167 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@
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 <elf.h>
47+
#include <image.h>
48+
#include <signal.h>
49+
#define _LIBUNWIND_CHECK_HAIKU_SIGRETURN 1
50+
#endif
51+
4452
#include "AddressSpace.hpp"
4553
#include "CompactUnwinder.hpp"
4654
#include "config.h"
@@ -1015,7 +1023,7 @@ class UnwindCursor : public AbstractUnwindCursor{
10151023
template <typename Registers> int stepThroughSigReturn(Registers &) {
10161024
return UNW_STEP_END;
10171025
}
1018-
#elif defined(_LIBUNWIND_TARGET_HAIKU)
1026+
#elif defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
10191027
bool setInfoForSigReturn();
10201028
int stepThroughSigReturn();
10211029
#endif
@@ -2559,7 +2567,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
25592567
template <typename A, typename R>
25602568
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
25612569
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
2562-
defined(_LIBUNWIND_TARGET_HAIKU)
2570+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
25632571
_isSigReturn = false;
25642572
#endif
25652573

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

26862694
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
2687-
defined(_LIBUNWIND_TARGET_HAIKU)
2695+
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
26882696
if (setInfoForSigReturn())
26892697
return;
26902698
#endif
@@ -2760,63 +2768,6 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
27602768
_isSignalFrame = true;
27612769
return UNW_STEP_SUCCESS;
27622770
}
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-
}
28202771
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
28212772
// defined(_LIBUNWIND_TARGET_AARCH64)
28222773

@@ -3032,6 +2983,162 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
30322983
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
30332984
// defined(_LIBUNWIND_TARGET_S390X)
30342985

2986+
#if defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
2987+
2988+
#if defined(B_HAIKU_32_BIT)
2989+
typedef Elf32_Sym elf_sym;
2990+
#define ELF_ST_TYPE ELF32_ST_TYPE
2991+
#elif defined(B_HAIKU_64_BIT)
2992+
typedef Elf64_Sym elf_sym;
2993+
#define ELF_ST_TYPE ELF64_ST_TYPE
2994+
#endif
2995+
2996+
// Private syscall declared as a weak symbol to prevent ABI breaks.
2997+
extern "C" status_t __attribute__((weak))
2998+
_kern_read_kernel_image_symbols(image_id id, elf_sym *symbolTable,
2999+
int32 *_symbolCount, char *stringTable,
3000+
size_t *_stringTableSize, addr_t *_imageDelta);
3001+
3002+
static addr_t signalHandlerBegin = 0;
3003+
static addr_t signalHandlerEnd = 0;
3004+
3005+
template <typename A, typename R>
3006+
bool UnwindCursor<A, R>::setInfoForSigReturn() {
3007+
if (signalHandlerBegin == 0) {
3008+
// If we do not have the addresses yet, find them now.
3009+
3010+
// Determine if the private function is there and usable.
3011+
if (_kern_read_kernel_image_symbols == nullptr) {
3012+
signalHandlerBegin = (addr_t)-1;
3013+
return false;
3014+
}
3015+
3016+
// Get the system commpage and enumerate its symbols.
3017+
image_id commpageImage = -1;
3018+
image_info info;
3019+
int32 cookie = 0;
3020+
while (get_next_image_info(B_SYSTEM_TEAM, &cookie, &info) == B_OK) {
3021+
if (strcmp(info.name, "commpage") == 0) {
3022+
commpageImage = info.id;
3023+
break;
3024+
}
3025+
}
3026+
if (commpageImage == -1) {
3027+
signalHandlerBegin = (addr_t)-1;
3028+
return false;
3029+
}
3030+
3031+
// Separate loop to get the process commpage,
3032+
// which is in a different address from the system commpage.
3033+
addr_t commpageAddress = -1;
3034+
cookie = 0;
3035+
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
3036+
if (strcmp(info.name, "commpage") == 0) {
3037+
commpageAddress = (addr_t)info.text;
3038+
break;
3039+
}
3040+
}
3041+
3042+
// The signal handler function address is
3043+
// defined in the system commpage symbols.
3044+
3045+
// First call to get the memory required.
3046+
int32 symbolCount = 0;
3047+
size_t stringTableSize = 0;
3048+
if (_kern_read_kernel_image_symbols(commpageImage, nullptr, &symbolCount,
3049+
nullptr, &stringTableSize,
3050+
nullptr) < B_OK) {
3051+
signalHandlerBegin = (addr_t)-1;
3052+
return false;
3053+
}
3054+
3055+
size_t memorySize = symbolCount * sizeof(elf_sym) + stringTableSize + 1;
3056+
void *buffer = malloc(memorySize);
3057+
if (buffer == nullptr) {
3058+
// No more memory. This is a temporary failure, we can try again later.
3059+
return false;
3060+
}
3061+
memset(buffer, 0, memorySize);
3062+
3063+
elf_sym *symbols = (elf_sym *)buffer;
3064+
char *stringTable = (char *)buffer + symbolCount * sizeof(elf_sym);
3065+
if (_kern_read_kernel_image_symbols(commpageImage, symbols, &symbolCount,
3066+
stringTable, &stringTableSize,
3067+
nullptr) < B_OK) {
3068+
free(buffer);
3069+
signalHandlerBegin = (addr_t)-1;
3070+
return false;
3071+
}
3072+
3073+
for (int32 i = 0; i < symbolCount; ++i) {
3074+
char *name = stringTable + symbols[i].st_name;
3075+
if (strcmp(name, "commpage_signal_handler") == 0) {
3076+
signalHandlerBegin = commpageAddress + symbols[i].st_value;
3077+
signalHandlerEnd = signalHandlerBegin + symbols[i].st_size;
3078+
break;
3079+
}
3080+
}
3081+
free(buffer);
3082+
3083+
if (signalHandlerBegin == 0) {
3084+
signalHandlerBegin = (addr_t)-1;
3085+
return false;
3086+
}
3087+
} else if (signalHandlerBegin == (addr_t)-1) {
3088+
// We have found, and failed.
3089+
return false;
3090+
}
3091+
pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
3092+
if (pc >= (pint_t)signalHandlerBegin && pc < (pint_t)signalHandlerEnd) {
3093+
_info = {};
3094+
_info.start_ip = signalHandlerBegin;
3095+
_info.end_ip = signalHandlerEnd;
3096+
_isSigReturn = true;
3097+
return true;
3098+
}
3099+
return false;
3100+
}
3101+
3102+
template <typename A, typename R>
3103+
int UnwindCursor<A, R>::stepThroughSigReturn() {
3104+
_isSignalFrame = true;
3105+
3106+
#if defined(_LIBUNWIND_TARGET_X86_64)
3107+
// Layout of the stack before function call:
3108+
// - signal_frame_data
3109+
// + siginfo_t (public struct, fairly stable)
3110+
// + ucontext_t (public struct, fairly stable)
3111+
// - mcontext_t -> Offset 0x70, this is what we want.
3112+
// - frame->ip (8 bytes)
3113+
// - frame->bp (8 bytes). Not written by the kernel,
3114+
// but the signal handler has a "push %rbp" instruction.
3115+
pint_t bp = this->getReg(UNW_X86_64_RBP);
3116+
vregs *regs = (vregs *)(bp + 0x70);
3117+
3118+
_registers.setRegister(UNW_REG_IP, regs->rip);
3119+
_registers.setRegister(UNW_REG_SP, regs->rsp);
3120+
_registers.setRegister(UNW_X86_64_RAX, regs->rax);
3121+
_registers.setRegister(UNW_X86_64_RDX, regs->rdx);
3122+
_registers.setRegister(UNW_X86_64_RCX, regs->rcx);
3123+
_registers.setRegister(UNW_X86_64_RBX, regs->rbx);
3124+
_registers.setRegister(UNW_X86_64_RSI, regs->rsi);
3125+
_registers.setRegister(UNW_X86_64_RDI, regs->rdi);
3126+
_registers.setRegister(UNW_X86_64_RBP, regs->rbp);
3127+
_registers.setRegister(UNW_X86_64_R8, regs->r8);
3128+
_registers.setRegister(UNW_X86_64_R9, regs->r9);
3129+
_registers.setRegister(UNW_X86_64_R10, regs->r10);
3130+
_registers.setRegister(UNW_X86_64_R11, regs->r11);
3131+
_registers.setRegister(UNW_X86_64_R12, regs->r12);
3132+
_registers.setRegister(UNW_X86_64_R13, regs->r13);
3133+
_registers.setRegister(UNW_X86_64_R14, regs->r14);
3134+
_registers.setRegister(UNW_X86_64_R15, regs->r15);
3135+
// TODO: XMM
3136+
#endif // defined(_LIBUNWIND_TARGET_X86_64)
3137+
3138+
return UNW_STEP_SUCCESS;
3139+
}
3140+
#endif // defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
3141+
30353142
template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
30363143
(void)stage2;
30373144
// Bottom of stack is defined is when unwind info cannot be found.

0 commit comments

Comments
 (0)