From 09fa2236cec70a6c2efe2a71f7dc2c851e20fbf0 Mon Sep 17 00:00:00 2001 From: Lubos Dolezel Date: Thu, 30 Apr 2020 16:19:24 +0200 Subject: [PATCH] At least the basic stuff in LLDB works again --- src/dyld/src/dyldAPIs.cpp | 2 - src/external/lkm | 2 +- .../linux/bsdthread/bsdthread_create.c | 4 +- .../linux/bsdthread/bsdthread_register.c | 14 + .../linux/bsdthread/bsdthread_register.h | 4 + .../linux/bsdthread/workq_kernreturn.c | 2 +- src/kernel/emulation/linux/misc/ptrace.c | 47 +-- src/kernel/emulation/linux/process/execve.c | 4 +- src/kernel/emulation/linux/signal/sigaction.c | 120 +++++- src/kernel/emulation/linux/signal/sigexc.c | 361 ++++++++++++++++-- src/kernel/emulation/linux/signal/sigexc.h | 18 +- 11 files changed, 496 insertions(+), 82 deletions(-) diff --git a/src/dyld/src/dyldAPIs.cpp b/src/dyld/src/dyldAPIs.cpp index 258d18bac..48e2d9fce 100644 --- a/src/dyld/src/dyldAPIs.cpp +++ b/src/dyld/src/dyldAPIs.cpp @@ -125,7 +125,6 @@ static int sLastErrorNo; #ifdef DARLING extern "C" int mach_driver_get_fd(void); -extern "C" bool darling_am_i_ptraced(void); #endif // In 10.3.x and earlier all the NSObjectFileImage API's were implemeneted in libSystem.dylib @@ -261,7 +260,6 @@ static const struct dyld_func dyld_funcs[] = { #endif #ifdef DARLING {"__dyld_get_mach_driver_fd", (void*)mach_driver_get_fd }, - {"__dyld_am_i_ptraced", (void*)darling_am_i_ptraced }, #endif #pragma clang diagnostic pop #endif //DEPRECATED_APIS_SUPPORTED diff --git a/src/external/lkm b/src/external/lkm index de22e7bc1..cc3478c80 160000 --- a/src/external/lkm +++ b/src/external/lkm @@ -1 +1 @@ -Subproject commit de22e7bc15bbf888b64522e9b07df788e1224c33 +Subproject commit cc3478c80e8e2d29ddfb1054020bf63054c729fd diff --git a/src/kernel/emulation/linux/bsdthread/bsdthread_create.c b/src/kernel/emulation/linux/bsdthread/bsdthread_create.c index fd674e37b..06f09b65c 100644 --- a/src/kernel/emulation/linux/bsdthread/bsdthread_create.c +++ b/src/kernel/emulation/linux/bsdthread/bsdthread_create.c @@ -42,14 +42,14 @@ long sys_bsdthread_create(void* thread_start, void* arg, pthread = stack = thread_stack_allocate(stacksize); } - ret = darling_thread_create((void**) stack, pthread_entry_point, thread_start, + ret = darling_thread_create((void**) stack, pthread_entry_point_wrapper, thread_start, arg, stacksize, flags); #else // Implemented in libdyld extern int thread_self_trap(void); return __darling_thread_create(((uintptr_t)stack), pthread_obj_size, - pthread_entry_point, thread_start, arg, (uintptr_t) stack, flags, + pthread_entry_point_wrapper, thread_start, arg, (uintptr_t) stack, flags, thread_self_trap); #endif diff --git a/src/kernel/emulation/linux/bsdthread/bsdthread_register.c b/src/kernel/emulation/linux/bsdthread/bsdthread_register.c index 616d6dfe5..86a7f19e7 100644 --- a/src/kernel/emulation/linux/bsdthread/bsdthread_register.c +++ b/src/kernel/emulation/linux/bsdthread/bsdthread_register.c @@ -2,6 +2,7 @@ #include "../base.h" #include "../errno.h" #include "../../../../../platform-include/sys/errno.h" +#include "../signal/sigexc.h" #include int pthread_obj_size; @@ -24,3 +25,16 @@ long sys_bsdthread_register(void* thread_start, void* wqthread, int pthsize, | PTHREAD_FEATURE_DISPATCHFUNC | PTHREAD_FEATURE_QOS_DEFAULT */ 0; } +void pthread_entry_point_wrapper(void* self, int thread_port, void* funptr, + void* funarg, unsigned long stacksize, unsigned int flags) +{ + sigexc_thread_setup(); + pthread_entry_point(self, thread_port, funptr, funarg, stacksize, flags); +} + +void wqueue_entry_point_wrapper(void* self, int thread_port, void* stackaddr, + void* item, int reuse, int nevents) +{ + sigexc_thread_setup(); + wqueue_entry_point(self, thread_port, stackaddr, item, reuse, nevents); +} diff --git a/src/kernel/emulation/linux/bsdthread/bsdthread_register.h b/src/kernel/emulation/linux/bsdthread/bsdthread_register.h index 409386929..61054a949 100644 --- a/src/kernel/emulation/linux/bsdthread/bsdthread_register.h +++ b/src/kernel/emulation/linux/bsdthread/bsdthread_register.h @@ -11,6 +11,10 @@ extern bsdwqthread_entry_t wqueue_entry_point; long sys_bsdthread_register(void* thread_start, void* wqthread, int pthsize, void* dummy, void* targetconc, unsigned long long dpq_offset); +void pthread_entry_point_wrapper(void* self, int thread_port, void* funptr, + void* funarg, unsigned long stacksize, unsigned int flags); +void wqueue_entry_point_wrapper(void* self, int thread_port, void* stackaddr, + void* item, int reuse, int nevents); #endif diff --git a/src/kernel/emulation/linux/bsdthread/workq_kernreturn.c b/src/kernel/emulation/linux/bsdthread/workq_kernreturn.c index 6395d57bc..a0c8d40e2 100644 --- a/src/kernel/emulation/linux/bsdthread/workq_kernreturn.c +++ b/src/kernel/emulation/linux/bsdthread/workq_kernreturn.c @@ -246,7 +246,7 @@ wakeup: // __simple_printf("Spawning a new thread, nevents=%d\n", (wq_event != NULL) ? wq_event->nevents : -1); wq_event_pending = wq_event; - __darling_thread_create(512*1024, pthread_obj_size, wqueue_entry_point, 0, + __darling_thread_create(512*1024, pthread_obj_size, wqueue_entry_point_wrapper, 0, (wq_event != NULL) ? wq_event->events : NULL, flags, (wq_event != NULL) ? wq_event->nevents : 0, thread_self_trap); diff --git a/src/kernel/emulation/linux/misc/ptrace.c b/src/kernel/emulation/linux/misc/ptrace.c index c9a9d63f0..4b6446d6c 100644 --- a/src/kernel/emulation/linux/misc/ptrace.c +++ b/src/kernel/emulation/linux/misc/ptrace.c @@ -63,20 +63,14 @@ long sys_ptrace(int request, int pid, void* addr, int data) ret = lkm_call(NR_set_tracer, &args); if (ret < 0) ret = errno_linux_to_bsd(ret); - else - { - // This triggers darling_sigexc_self() in the remote process. - ret = linux_sigqueue(pid, SIGNAL_SIGEXC_TOGGLE, SIGRT_MAGIC_ENABLE_SIGEXC); - - if (ret < 0) - ret = errno_linux_to_bsd(ret); - // This doesn't work if the process is stopped, e.g. when spawning a stopped - // process via posix_spawn(). So now we have to resume the process so that - // it gets the RT signal above and triggers a fake SIGSTOP on its own. - // int pstate = lkm_call(NR_pid_get_state, (void*)(long) pid); - // if (pstate & 4 /* __TASK_STOPPED */) - // sys_kill(pid, SIGCONT, 1); - } + + sys_kill(pid, SIGSTOP, 1); + + struct ptrace_sigexc_args args2; + args2.pid = pid; + args2.sigexc = 1; + + ret = lkm_call(NR_ptrace_sigexc, &args2); cmd = "PT_ATTACHEXC"; break; @@ -105,9 +99,14 @@ long sys_ptrace(int request, int pid, void* addr, int data) case PT_DETACH: { // Tell the tracee to restore original application signal handlers. - linux_sigqueue(pid, SIGNAL_SIGEXC_TOGGLE, SIGRT_MAGIC_DISABLE_SIGEXC); + //linux_sigqueue(pid, SIGNAL_SIGEXC_TOGGLE, SIGRT_MAGIC_DISABLE_SIGEXC); - ret = 0; //LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_DETACH, pid, addr, data); + //ret = 0; //LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_DETACH, pid, addr, data); + struct ptrace_sigexc_args args; + args.pid = pid; + args.sigexc = 0; + + ret = lkm_call(NR_ptrace_sigexc, &args); // if (ret < 0) // ret = errno_linux_to_bsd(ret); @@ -118,8 +117,12 @@ long sys_ptrace(int request, int pid, void* addr, int data) case PT_SIGEXC: { lkm_call(0x1028, "sigexc: self via ptrace\n"); - darling_sigexc_self(); - ret = 0; + + struct ptrace_sigexc_args args; + args.pid = getpid(); + args.sigexc = 1; + + ret = lkm_call(NR_ptrace_sigexc, &args); // return ret; cmd = "PT_SIGEXC"; break; @@ -148,11 +151,11 @@ long sys_ptrace(int request, int pid, void* addr, int data) if (tid < 0) return -ESRCH; - int signal = 0; - if (data != -1) - signal = signum_bsd_to_linux(data); + struct ptrace_thupdate_args args; + args.tid = tid; + args.signum = data; - ret = linux_sigqueue_thread(pid, tid, SIGNAL_SIGEXC_THUPDATE, signal); + ret = lkm_call(NR_ptrace_thupdate, &args); if (ret < 0) ret = errno_linux_to_bsd(ret); diff --git a/src/kernel/emulation/linux/process/execve.c b/src/kernel/emulation/linux/process/execve.c index 8b4c80d3d..c90340647 100644 --- a/src/kernel/emulation/linux/process/execve.c +++ b/src/kernel/emulation/linux/process/execve.c @@ -119,8 +119,8 @@ long sys_execve(char* fname, char** argvp, char** envp) } linux_sigset_t set; - set = (1ull << (SIGNAL_SIGEXC_TOGGLE-1)); - set |= (1ull << (SIGNAL_SIGEXC_THUPDATE-1)); + set = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); + //set |= (1ull << (SIGNAL_SIGEXC_THUPDATE-1)); LINUX_SYSCALL(__NR_rt_sigprocmask, 0 /* LINUX_SIG_BLOCK */, &set, NULL, sizeof(linux_sigset_t)); diff --git a/src/kernel/emulation/linux/signal/sigaction.c b/src/kernel/emulation/linux/signal/sigaction.c index 7827503bc..4eb49a5d8 100644 --- a/src/kernel/emulation/linux/signal/sigaction.c +++ b/src/kernel/emulation/linux/signal/sigaction.c @@ -17,7 +17,11 @@ extern void* memset(void* dest, int v, __SIZE_TYPE__ len); // Libc uses only one trampoline void (*sa_tramp)(void*, int, int, struct bsd_siginfo*, void*) = 0; -bsd_sig_handler* sig_handlers[32]; +bsd_sig_handler* sig_handlers[32] = { + [LINUX_SIGWINCH] = (bsd_sig_handler*) SIG_IGN, + [LINUX_SIGCHLD] = (bsd_sig_handler*) SIG_IGN, + [LINUX_SIGURG] = (bsd_sig_handler*) SIG_IGN, +}; int sig_flags[32]; unsigned int sig_masks[32]; @@ -41,33 +45,129 @@ long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sig return 0; } - ret = 0; + if (nsa != NULL && linux_signum == LINUX_SIGCHLD) + { + sa_tramp = nsa->sa_tramp; + if (nsa->sa_sigaction != SIG_DFL && nsa->sa_sigaction != SIG_IGN + && nsa->sa_sigaction != SIG_ERR) + { + sa.sa_sigaction = &handler_linux_to_bsd; + } + else + sa.sa_sigaction = (linux_sig_handler*) nsa->sa_sigaction; + + sigset_bsd_to_linux(&nsa->sa_mask, &sa.sa_mask); + sa.sa_flags = sigflags_bsd_to_linux(nsa->sa_flags) | LINUX_SA_RESTORER; + sa.sa_restorer = sig_restorer; + + ret = LINUX_SYSCALL(__NR_rt_sigaction, linux_signum, + (nsa != NULL) ? &sa : NULL, &olsa, + sizeof(sa.sa_mask)); + + if (ret < 0) + return errno_linux_to_bsd(ret); + + if (osa != NULL) + { + if (olsa.sa_sigaction == handler_linux_to_bsd) + osa->sa_sigaction = sig_handlers[linux_signum]; + else // values such as SIG_DFL + osa->sa_sigaction = (bsd_sig_handler*) olsa.sa_sigaction; + sigset_linux_to_bsd(&olsa.sa_mask, &osa->sa_mask); + osa->sa_flags = sigflags_linux_to_bsd(olsa.sa_flags); + } + } + else + { + ret = 0; + + if (osa != NULL) + { + osa->sa_sigaction = sig_handlers[linux_signum]; + osa->sa_flags = sig_flags[linux_signum]; + osa->sa_mask = sig_masks[linux_signum]; + } + } + + if (nsa != NULL && ret >= 0) + { + // __simple_printf("Saving handler for signal %d: %p\n", linux_signum, nsa->sa_sigaction); + sig_handlers[linux_signum] = nsa->sa_sigaction; + sig_flags[linux_signum] = nsa->sa_flags; + sig_masks[linux_signum] = nsa->sa_mask; + } + + return 0; +} + +#if 0 +long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sigaction* osa) +{ + int ret, linux_signum; + struct linux_sigaction sa, olsa; + + linux_signum = signum_bsd_to_linux(signum); + if (linux_signum == 0) + { + // Some software (e.g. Node.js) tries to set up handlers for all signals by + // walking through all signal numbers incrementally. They end up hitting + // signals that don't exist on Linux and then bail out if they receive + // an error. + // Fake that everyting is all right. + + if (osa != NULL) + memset(osa, 0, sizeof(*osa)); + + return 0; + } + + if (nsa != NULL) + { + sa_tramp = nsa->sa_tramp; + /*if (darling_am_i_ptraced()) + { + sa.sa_sigaction = &sigexc_handler; + } + else*/ if (nsa->sa_sigaction != SIG_DFL && nsa->sa_sigaction != SIG_IGN + && nsa->sa_sigaction != SIG_ERR) + { + sa.sa_sigaction = &handler_linux_to_bsd; + } + else + sa.sa_sigaction = (linux_sig_handler*) nsa->sa_sigaction; + + sigset_bsd_to_linux(&nsa->sa_mask, &sa.sa_mask); + sa.sa_flags = sigflags_bsd_to_linux(nsa->sa_flags) | LINUX_SA_RESTORER; + sa.sa_restorer = sig_restorer; + } + + ret = LINUX_SYSCALL(__NR_rt_sigaction, linux_signum, + (nsa != NULL) ? &sa : NULL, &olsa, + sizeof(sa.sa_mask)); + if (ret < 0) + return errno_linux_to_bsd(ret); if (osa != NULL) { - /* if (olsa.sa_sigaction == handler_linux_to_bsd) osa->sa_sigaction = sig_handlers[linux_signum]; else // values such as SIG_DFL osa->sa_sigaction = (bsd_sig_handler*) olsa.sa_sigaction; sigset_linux_to_bsd(&olsa.sa_mask, &osa->sa_mask); osa->sa_flags = sigflags_linux_to_bsd(olsa.sa_flags); - */ - osa->sa_sigaction = sig_handlers[linux_signum]; - osa->sa_flags = sig_flags[linux_signum]; - osa->sa_mask = sig_masks[linux_signum]; } if (nsa != NULL && ret >= 0) { - // __simple_printf("Saving handler for signal %d: %p\n", linux_signum, nsa->sa_sigaction); + // __simple_printf("Saving handler for signal %d: %d\n", linux_signum, nsa->sa_sigaction); sig_handlers[linux_signum] = nsa->sa_sigaction; - sig_flags[linux_signum] = nsa->sa_flags; - sig_masks[linux_signum] = nsa->sa_mask; + sig_flags[linux_signum] = sa.sa_flags; + sig_masks[linux_signum] = sa.sa_mask; } return 0; } +#endif static void ucontext_linux_to_bsd(const struct linux_ucontext* lc, struct bsd_ucontext* bc, struct bsd_mcontext* bm) { diff --git a/src/kernel/emulation/linux/signal/sigexc.c b/src/kernel/emulation/linux/signal/sigexc.c index 46cb4fd7b..65b81784f 100644 --- a/src/kernel/emulation/linux/signal/sigexc.c +++ b/src/kernel/emulation/linux/signal/sigexc.c @@ -6,12 +6,12 @@ #include #include #include -#include "signal/mach_exc.h" -#include "signal/exc.h" #include "sigaltstack.h" #include "../mach/lkm.h" #include "../../../../external/lkm/api.h" #include "../../../libsyscall/wrappers/_libkernel_init.h" +#include "../../../../../platform-include/sys/mman.h" +#include "../mman/mman.h" #include "kill.h" #include "../simple.h" @@ -32,8 +32,7 @@ void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt); #define SIGEXC_TSD_KEY 102 #define SIGEXC_CONTEXT_TSD_KEY 103 -static char sigexc_altstack[16*1024]; -static struct bsd_stack orig_stack; +static char sigexc_altstack[8*1024]; #if defined(__x86_64__) static void mcontext_to_thread_state(const struct linux_gregset* regs, x86_thread_state64_t* s); @@ -47,7 +46,8 @@ static void thread_state_to_mcontext(const x86_thread_state32_t* s, struct linux static void float_state_to_mcontext(const x86_float_state32_t* s, linux_fpregset_t fx); #endif -static void state_to_kernel(struct linux_ucontext* ctxt, thread_t thread); +static void state_from_kernel(struct linux_ucontext* ctxt, const struct thread_state* kernel_state); +static void state_to_kernel(struct linux_ucontext* ctxt, struct thread_state* kernel_state); #define DEBUG_SIGEXC #ifdef DEBUG_SIGEXC @@ -58,28 +58,91 @@ static void state_to_kernel(struct linux_ucontext* ctxt, thread_t thread); void sigexc_setup1(void) { - + handle_rt_signal(SIGNAL_SIGEXC_SUSPEND); } void sigexc_setup2(void) { - + linux_sigset_t set; + set = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); + //set |= (1ull << (SIGNAL_SIGEXC_THUPDATE-1)); + + LINUX_SYSCALL(__NR_rt_sigprocmask, 1 /* LINUX_SIG_UNBLOCK */, + &set, NULL, sizeof(linux_sigset_t)); +} + +static void dump_gregs(const struct linux_gregset* regs) +{ + unsigned long long* p = (unsigned long long*) regs; + for (int i = 0; i < 23; i++) + { + kern_printf("sigexc: gregs 0x%x\n", p[i]); + } +} + +static void handle_rt_signal(int signum) +{ + int rv; + struct linux_sigaction sa; + + sa.sa_sigaction = sigrt_handler; + sa.sa_mask = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); + sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART | LINUX_SA_ONSTACK; + sa.sa_restorer = sig_restorer; + + rv = LINUX_SYSCALL(__NR_rt_sigaction, signum, + &sa, NULL, + sizeof(sa.sa_mask)); + + //char buf[128]; + //__simple_sprintf(xyzbuf, "Setting handler for RT signal %d: %d", signum, rv); + //external/lkm_call(0x1028, buf); } void sigexc_setup(void) { darling_sigexc_self(); + sigexc_setup1(); + sigexc_setup2(); #ifdef VARIANT_DYLD - + if (lkm_call(NR_started_suspended, 0)) + { + kern_printf("sigexc: start_suspended -> suspending (ret to %p)\n", __builtin_return_address(0)); + task_suspend(mach_task_self()); + kern_printf("sigexc: start_suspended -> wokenup (ret to %p)\n", __builtin_return_address(0)); + } + else if (lkm_call(NR_get_tracer, NULL) != 0) + { + kern_printf("sigexc: already traced -> SIGTRAP\n"); + sys_kill(0, SIGTRAP, 0); + } #else #endif } - -bool darling_am_i_ptraced(void) +void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt) { - return am_i_ptraced; +#if defined(__x86_64__) + x86_thread_state64_t tstate; + x86_float_state64_t fstate; +#elif defined(__i386__) + x86_thread_state32_t tstate; + x86_float_state32_t fstate; +#endif + + struct thread_suspended_args args; + args.state.tstate = &tstate; + args.state.fstate = &fstate; + + kern_printf("sigexc: sigrt_handler SUSPEND\n"); + + thread_t thread = mach_thread_self(); + state_to_kernel(ctxt, &args.state); + + lkm_call(NR_thread_suspended, &args); + + state_from_kernel(ctxt, &args.state); } @@ -91,12 +154,13 @@ void darling_sigexc_self(void) // Make sigexc_handler the handler for all signals in the process for (int i = 1; i <= 31; i++) { - if (i == LINUX_SIGSTOP || i == LINUX_SIGKILL) + if (i == LINUX_SIGSTOP || i == LINUX_SIGKILL || i == LINUX_SIGCHLD) continue; struct linux_sigaction sa; sa.sa_sigaction = (linux_sig_handler*) sigexc_handler; sa.sa_mask = 0x7fffffff; // all other standard Unix signals should be blocked while the handler is run + sa.sa_mask |= (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART | LINUX_SA_ONSTACK; sa.sa_restorer = sig_restorer; @@ -110,19 +174,39 @@ void darling_sigexc_self(void) .ss_size = sizeof(sigexc_altstack), .ss_flags = 0 }; - sys_sigaltstack(&newstack, &orig_stack); + sys_sigaltstack(&newstack, NULL); +} + + +static void state_to_kernel(struct linux_ucontext* ctxt, struct thread_state* kernel_state) +{ +#if defined(__x86_64__) + + dump_gregs(&ctxt->uc_mcontext.gregs); + mcontext_to_thread_state(&ctxt->uc_mcontext.gregs, (x86_thread_state64_t*) kernel_state->tstate); + mcontext_to_float_state(ctxt->uc_mcontext.fpregs, (x86_float_state64_t*) kernel_state->fstate); + +#elif defined(__i386__) + mcontext_to_thread_state(&ctxt->uc_mcontext.gregs, (x86_thread_state32_t*) kernel_state->tstate); + mcontext_to_float_state(ctxt->uc_mcontext.fpregs, (x86_float_state32_t*) kernel_state->fstate); +#endif + } -// syscall tracking -#define LINUX_TRAP_BRKPT 1 -// single-stepping -#define LINUX_TRAP_TRACE 2 -// ??? -#define LINUX_TRAP_BRANCH 3 -// memory watchpoint -#define LINUX_TRAP_HWBKPT 4 -// int3 (on x86, other platforms probably use TRAP_BRKPT) -#define LINUX_SI_KERNEL 0x80 +static void state_from_kernel(struct linux_ucontext* ctxt, const struct thread_state* kernel_state) +{ +#if defined(__x86_64__) + + thread_state_to_mcontext((x86_thread_state64_t*) kernel_state->tstate, &ctxt->uc_mcontext.gregs); + float_state_to_mcontext((x86_float_state64_t*) kernel_state->fstate, ctxt->uc_mcontext.fpregs); + + dump_gregs(&ctxt->uc_mcontext.gregs); + +#elif defined(__i386__) + thread_state_to_mcontext((x86_thread_state32_t*) kernel_state->tstate, &ctxt->uc_mcontext.gregs); + float_state_to_mcontext((x86_float_state32_t*) kernel_state->fstate, ctxt->uc_mcontext.fpregs); +#endif +} void sigexc_handler(int linux_signum, struct linux_siginfo* info, struct linux_ucontext* ctxt) { @@ -143,9 +227,27 @@ void sigexc_handler(int linux_signum, struct linux_siginfo* info, struct linux_u sigprocess.signum = bsd_signum; memcpy(&sigprocess.linux_siginfo, info, sizeof(*info)); - memcpy(&sigprocess.linux_ucontext, ctxt, sizeof(*ctxt)); +#ifdef __x86_64__ + kern_printf("sigexc: have RIP 0x%x\n", ctxt->uc_mcontext.gregs.rip); +#endif + + thread_t thread = mach_thread_self(); + +#if defined(__x86_64__) + x86_thread_state64_t tstate; + x86_float_state64_t fstate; +#elif defined(__i386__) + x86_thread_state32_t tstate; + x86_float_state32_t fstate; +#endif + + sigprocess.state.tstate = &tstate; + sigprocess.state.fstate = &fstate; + + state_to_kernel(ctxt, &sigprocess.state); lkm_call(NR_sigprocess, &sigprocess); + state_from_kernel(ctxt, &sigprocess.state); if (!sigprocess.signum) { @@ -153,9 +255,6 @@ void sigexc_handler(int linux_signum, struct linux_siginfo* info, struct linux_u return; } - memcpy(info, &sigprocess.linux_siginfo, sizeof(*info)); - memcpy(ctxt, &sigprocess.linux_ucontext, sizeof(*ctxt)); - linux_signum = signum_bsd_to_linux(sigprocess.signum); if (sig_handlers[linux_signum] != SIG_IGN) @@ -195,3 +294,211 @@ void sigexc_handler(int linux_signum, struct linux_siginfo* info, struct linux_u kern_printf("sigexc: handler (%d) returning\n", linux_signum); } +#define DUMPREG(regname) kern_printf("sigexc: " #regname ": 0x%x\n", regs->regname); + +#if defined(__x86_64__) +void mcontext_to_thread_state(const struct linux_gregset* regs, x86_thread_state64_t* s) +{ + s->__rax = regs->rax; + s->__rbx = regs->rbx; + s->__rcx = regs->rcx; + s->__rdx = regs->rdx; + s->__rdi = regs->rdi; + s->__rsi = regs->rsi; + s->__rbp = regs->rbp; + s->__rsp = regs->rsp; + s->__r8 = regs->r8; + s->__r9 = regs->r9; + s->__r10 = regs->r10; + s->__r11 = regs->r11; + s->__r12 = regs->r12; + s->__r13 = regs->r13; + s->__r14 = regs->r14; + s->__r15 = regs->r15; + s->__rip = regs->rip; + s->__rflags = regs->efl; + s->__cs = regs->cs; + s->__fs = regs->fs; + s->__gs = regs->gs; + + kern_printf("sigexc: saving to kernel:\n"); + DUMPREG(rip); + DUMPREG(efl); + DUMPREG(rax); + DUMPREG(rbx); + DUMPREG(rcx); + DUMPREG(rdx); + DUMPREG(rdi); + DUMPREG(rsi); + DUMPREG(rbp); + DUMPREG(rsp); +} + +void mcontext_to_float_state(const linux_fpregset_t fx, x86_float_state64_t* s) +{ + kern_printf("sigexc: fcw out: 0x%x", fx->cwd); + kern_printf("sigexc: xmm0 out: 0x%x", fx->_xmm[0].element[0]); + *((uint16_t*)&s->__fpu_fcw) = fx->cwd; + *((uint16_t*)&s->__fpu_fsw) = fx->swd; + s->__fpu_ftw = fx->ftw; + s->__fpu_fop = fx->fop; + s->__fpu_ip = fx->rip; + s->__fpu_cs = 0; + s->__fpu_dp = fx->rdp; + s->__fpu_ds = 0; + s->__fpu_mxcsr = fx->mxcsr; + s->__fpu_mxcsrmask = fx->mxcr_mask; + + memcpy(&s->__fpu_stmm0, fx->_st, 128); + memcpy(&s->__fpu_xmm0, fx->_xmm, 256); +} + +void thread_state_to_mcontext(const x86_thread_state64_t* s, struct linux_gregset* regs) +{ + regs->rax = s->__rax; + regs->rbx = s->__rbx; + regs->rcx = s->__rcx; + regs->rdx = s->__rdx; + regs->rdi = s->__rdi; + regs->rsi = s->__rsi; + regs->rbp = s->__rbp; + regs->rsp = s->__rsp; + regs->r8 = s->__r8; + regs->r9 = s->__r9; + regs->r10 = s->__r10; + regs->r11 = s->__r11; + regs->r12 = s->__r12; + regs->r13 = s->__r13; + regs->r14 = s->__r14; + regs->r15 = s->__r15; + regs->rip = s->__rip; + regs->efl = s->__rflags; + regs->cs = s->__cs; + regs->fs = s->__fs; + regs->gs = s->__gs; + + kern_printf("sigexc: restored from kernel:\n"); + DUMPREG(rip); + DUMPREG(efl); + DUMPREG(rax); + DUMPREG(rbx); + DUMPREG(rcx); + DUMPREG(rdx); + DUMPREG(rdi); + DUMPREG(rsi); + DUMPREG(rbp); + DUMPREG(rsp); +} + +void float_state_to_mcontext(const x86_float_state64_t* s, linux_fpregset_t fx) +{ + fx->cwd = *((uint16_t*)&s->__fpu_fcw); + fx->swd = *((uint16_t*)&s->__fpu_fsw); + fx->ftw = s->__fpu_ftw; + fx->fop = s->__fpu_fop; + fx->rip = s->__fpu_ip; + fx->rdp = s->__fpu_dp; + fx->mxcsr = s->__fpu_mxcsr; + fx->mxcr_mask = s->__fpu_mxcsrmask; + + memcpy(fx->_st, &s->__fpu_stmm0, 128); + memcpy(fx->_xmm, &s->__fpu_xmm0, 256); + kern_printf("sigexc: fcw in: 0x%x", fx->cwd); + kern_printf("sigexc: xmm0 in: 0x%x", fx->_xmm[0].element[0]); +} + +#elif defined(__i386__) +void mcontext_to_thread_state(const struct linux_gregset* regs, x86_thread_state32_t* s) +{ + s->__eax = regs->eax; + s->__ebx = regs->ebx; + s->__ecx = regs->ecx; + s->__edx = regs->edx; + s->__edi = regs->edi; + s->__esi = regs->esi; + s->__ebp = regs->ebp; + s->__esp = regs->esp; + s->__ss = regs->ss; + s->__eflags = regs->efl; + s->__eip = regs->eip; + s->__cs = regs->cs; + s->__ds = regs->ds; + s->__es = regs->es; + s->__fs = regs->fs; + s->__gs = regs->gs; +} + +void mcontext_to_float_state(const linux_fpregset_t fx, x86_float_state32_t* s) +{ + *((uint16_t*)&s->__fpu_fcw) = fx->cw; + *((uint16_t*)&s->__fpu_fsw) = fx->sw; + s->__fpu_ftw = fx->tag; + s->__fpu_fop = 0; + s->__fpu_ip = fx->ipoff; + s->__fpu_cs = fx->cssel; + s->__fpu_dp = fx->dataoff; + s->__fpu_ds = fx->datasel; + s->__fpu_mxcsr = fx->mxcsr; + s->__fpu_mxcsrmask = 0; + + memcpy(&s->__fpu_stmm0, fx->_st, 128); + memcpy(&s->__fpu_xmm0, fx->_xmm, 128); + memset(((char*) &s->__fpu_xmm0) + 128, 0, 128); +} + +void thread_state_to_mcontext(const x86_thread_state32_t* s, struct linux_gregset* regs) +{ + regs->eax = s->__eax; + regs->ebx = s->__ebx; + regs->ecx = s->__ecx; + regs->edx = s->__edx; + regs->edi = s->__edi; + regs->esi = s->__esi; + regs->ebp = s->__ebp; + regs->esp = s->__esp; + regs->ss = s->__ss; + regs->efl = s->__eflags; + regs->eip = s->__eip; + regs->cs = s->__cs; + regs->ds = s->__ds; + regs->es = s->__es; + regs->fs = s->__fs; + regs->gs = s->__gs; +} + +void float_state_to_mcontext(const x86_float_state32_t* s, linux_fpregset_t fx) +{ + fx->cw = *((uint16_t*)&s->__fpu_fcw); + fx->sw = *((uint16_t*)&s->__fpu_fsw); + fx->tag = s->__fpu_ftw; + fx->ipoff = s->__fpu_ip; + fx->cssel = s->__fpu_cs; + fx->dataoff = s->__fpu_dp; + fx->datasel = s->__fpu_ds; + fx->mxcsr = s->__fpu_mxcsr; + + memcpy(fx->_st, &s->__fpu_stmm0, 128); + memcpy(fx->_xmm, &s->__fpu_xmm0, 128); +} +#endif + +void sigexc_thread_setup(void) +{ + struct bsd_stack newstack = { + .ss_size = sizeof(sigexc_altstack), + .ss_flags = 0 + }; + + newstack.ss_sp = (void*) sys_mmap(NULL, sizeof(sigexc_altstack), PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + sys_sigaltstack(&newstack, NULL); +} + +void sigexc_thread_exit(void) +{ + struct bsd_stack oldstack; + sys_sigaltstack(NULL, &oldstack); + + sys_munmap(oldstack.ss_sp, oldstack.ss_flags); +} + diff --git a/src/kernel/emulation/linux/signal/sigexc.h b/src/kernel/emulation/linux/signal/sigexc.h index 72afedb28..1c1034828 100644 --- a/src/kernel/emulation/linux/signal/sigexc.h +++ b/src/kernel/emulation/linux/signal/sigexc.h @@ -6,28 +6,16 @@ // NOTE: Keep these definitions up to date with lkm/darling/binfmt.c! // Uses one of the below magic values to toggle the debugging state -#define SIGNAL_SIGEXC_TOGGLE LINUX_SIGRTMIN - -// A BSD signal number is passed as value -#define SIGNAL_SIGEXC_THUPDATE (LINUX_SIGRTMIN + 1) - -#define SIGNAL_THREAD_SUSPEND -100 -#define SIGNAL_THREAD_RESUME -101 - -#define SIGRT_MAGIC_ENABLE_SIGEXC 0xdebdeb01 -#define SIGRT_MAGIC_DISABLE_SIGEXC 0xdebdeb00 +#define SIGNAL_SIGEXC_SUSPEND LINUX_SIGRTMIN void sigexc_setup(void); -// Is this process currently traced by a debugger? -bool darling_am_i_ptraced(void); - // for PT_SIGEXC to handle this operation synchronously void darling_sigexc_self(void); void sigexc_handler(int linux_signum, struct linux_siginfo* info, struct linux_ucontext* ctxt); -int linux_sigqueue(int pid, int rtsig, int value); -int linux_sigqueue_thread(int pid, int tid, int rtsig, int value); +void sigexc_thread_setup(void); +void sigexc_thread_exit(void); #endif -- 2.51.2