|
41 | 41 | #define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
|
42 | 42 | #endif
|
43 | 43 |
|
| 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 | + |
44 | 52 | #include "AddressSpace.hpp"
|
45 | 53 | #include "CompactUnwinder.hpp"
|
46 | 54 | #include "config.h"
|
@@ -1015,7 +1023,7 @@ class UnwindCursor : public AbstractUnwindCursor{
|
1015 | 1023 | template <typename Registers> int stepThroughSigReturn(Registers &) {
|
1016 | 1024 | return UNW_STEP_END;
|
1017 | 1025 | }
|
1018 |
| -#elif defined(_LIBUNWIND_TARGET_HAIKU) |
| 1026 | +#elif defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) |
1019 | 1027 | bool setInfoForSigReturn();
|
1020 | 1028 | int stepThroughSigReturn();
|
1021 | 1029 | #endif
|
@@ -2559,7 +2567,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
|
2559 | 2567 | template <typename A, typename R>
|
2560 | 2568 | void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
2561 | 2569 | #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
|
2562 |
| - defined(_LIBUNWIND_TARGET_HAIKU) |
| 2570 | + defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) |
2563 | 2571 | _isSigReturn = false;
|
2564 | 2572 | #endif
|
2565 | 2573 |
|
@@ -2684,7 +2692,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
2684 | 2692 | #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
2685 | 2693 |
|
2686 | 2694 | #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
|
2687 |
| - defined(_LIBUNWIND_TARGET_HAIKU) |
| 2695 | + defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) |
2688 | 2696 | if (setInfoForSigReturn())
|
2689 | 2697 | return;
|
2690 | 2698 | #endif
|
@@ -2760,63 +2768,6 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
|
2760 | 2768 | _isSignalFrame = true;
|
2761 | 2769 | return UNW_STEP_SUCCESS;
|
2762 | 2770 | }
|
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 |
| -} |
2820 | 2771 | #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
|
2821 | 2772 | // defined(_LIBUNWIND_TARGET_AARCH64)
|
2822 | 2773 |
|
@@ -3032,6 +2983,162 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
|
3032 | 2983 | #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
|
3033 | 2984 | // defined(_LIBUNWIND_TARGET_S390X)
|
3034 | 2985 |
|
| 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 | + |
3035 | 3142 | template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
|
3036 | 3143 | (void)stage2;
|
3037 | 3144 | // Bottom of stack is defined is when unwind info cannot be found.
|
|
0 commit comments