···88#include <sys/signal.h>
99#include "../signal/kill.h"
1010#include "../signal/duct_signals.h"
1111+#include "../signal/sigexc.h"
1212+#include "../process/wait4.h"
1313+#include "../mach/lkm.h"
1414+#include "../../../../lkm/api.h"
11151216#define LINUX_PTRACE_TRACEME 0
1317#define LINUX_PTRACE_ATTACH 16
1418#define LINUX_PTRACE_DETACH 17
1519#define LINUX_PTRACE_CONT 7
2020+#define LINUX_PTRACE_KILL 8
16211722long sys_ptrace(int request, int pid, void* addr, int data)
1823{
1924 const char* cmd = NULL;
2525+ int ret;
20262127 switch (request)
2228 {
2329 case PT_PTRACE_ME:
2430 {
2525- int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_TRACEME, pid, addr, data);
3131+ ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_TRACEME, pid, addr, data);
26322733 if (ret < 0)
2834 ret = errno_linux_to_bsd(ret);
29353030- return ret;
3131- //cmd = "PT_PTRACE_ME"; break;
3636+ //return ret;
3737+ cmd = "PT_PTRACE_ME"; break;
3238 }
3339 case PT_KILL:
3434- return sys_kill(pid, SIGKILL, 1);
3535- // cmd = "PT_KILL"; break;
3636- case PT_ATTACH: // PT_ATTACH
3737- case PT_ATTACHEXC: // PT_ATTACHEXC
3840 {
3939- //do_attach:
4040- int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_ATTACH, pid, addr, data);
4141+ //return sys_kill(pid, SIGKILL, 1);
4242+ ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_KILL, pid, addr, data);
4343+ if (ret < 0)
4444+ ret = errno_linux_to_bsd(ret);
4545+4646+ // return ret;
4747+ cmd = "PT_KILL"; break;
4848+ }
4949+ case PT_ATTACHEXC:
5050+ // This triggers darling_sigexc_self() in the remote process.
5151+ linux_sigqueue(pid, SIGNAL_SIGEXC_TOGGLE, SIGRT_MAGIC_ENABLE_SIGEXC);
5252+5353+ // fall through to PT_ATTACH
5454+ case PT_ATTACH:
5555+ {
5656+ ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_ATTACH, pid, addr, data);
41574258 if (ret < 0)
5959+ {
4360 ret = errno_linux_to_bsd(ret);
6161+ }
6262+ else
6363+ {
6464+ // Call wait4 to process the SIGSTOP that is sent by kernel on PTRACE_ATTACH
6565+ // and make sure it is passed to the tracee (to get it sent back to us as a Mach message).
6666+ sys_wait4(pid, NULL, DARLING_WAIT_NORESTART | BSD_WSTOPPED, NULL);
6767+ }
44684545- return ret;
4646- // cmd = "PT_ATTACH"; break;
6969+ //return ret;
7070+ cmd = "PT_ATTACH"; break;
4771 }
4872 case PT_DETACH:
4973 {
5050- int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_DETACH, pid, addr, data);
7474+ // Tell the tracee to restore original application signal handlers.
7575+ linux_sigqueue(pid, SIGNAL_SIGEXC_TOGGLE, SIGRT_MAGIC_DISABLE_SIGEXC);
7676+7777+ ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_DETACH, pid, addr, data);
51785279 if (ret < 0)
5380 ret = errno_linux_to_bsd(ret);
54815555- return ret;
5656- // cmd = "PT_DETACH"; break;
8282+ //return ret;
8383+ cmd = "PT_DETACH"; break;
5784 }
5885 case PT_SIGEXC:
8686+ {
8787+ darling_sigexc_self();
8888+ ret = 0;
8989+9090+ // return ret;
5991 cmd = "PT_SIGEXC"; break;
9292+ }
6093 case PT_CONTINUE:
6161- // case PT_THUPDATE:
6294 {
6395 int signal = 0;
6496 if (data != -1)
6597 signal = signum_bsd_to_linux(data);
6666- int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_CONT, pid, NULL, signal);
9898+ ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_CONT, pid, NULL, signal);
679968100 if (ret < 0)
69101 ret = errno_linux_to_bsd(ret);
701027171- return ret;
7272- // cmd = "PT_THUPDATE"; break;
103103+ // return ret;
104104+ cmd = "PT_CONTINUE"; break;
105105+ }
106106+ case PT_THUPDATE:
107107+ {
108108+ // Convert thread_t to process ID
109109+ int tid = lkm_call(NR_tid_for_thread, addr);
110110+ if (tid < 0)
111111+ return -ESRCH;
112112+113113+ int signal = 0;
114114+ if (data != -1)
115115+ signal = signum_bsd_to_linux(data);
116116+117117+ ret = linux_sigqueue_thread(pid, tid, SIGNAL_SIGEXC_THUPDATE, signal);
118118+ if (ret < 0)
119119+ ret = errno_linux_to_bsd(ret);
120120+121121+ // return ret;
122122+ cmd = "PT_THUPDATE"; break;
73123 }
7474- //case 14:
7575- //{
7676- // goto do_attach;
7777- // cmd = "PT_ATTACHEXC"; break;
7878- //}
79124 }
8012581126 if (cmd != NULL)
8282- __simple_printf("ptrace() req=%s\n", cmd);
127127+ __simple_printf("ptrace() req=%s, ret=%d\n", cmd, ret);
83128 else
84129 __simple_printf("ptrace() req=%d\n", request);
851308686- return -ENOSYS;
131131+ return ret;
87132}
88133
+11-2
src/kernel/emulation/linux/process/wait4.c
···22#include "../base.h"
33#include "../errno.h"
44#include "../signal/duct_signals.h"
55+#include "../signal/sigexc.h"
56#include "../misc/ptrace.h"
67#include "../mach/lkm.h"
78#include "../../../../lkm/api.h"
89#include <sys/signal.h>
910#include <stddef.h>
1011#include <linux-syscalls/linux.h>
1212+1313+extern int getpid(void);
11141215long sys_wait4(int pid, int* status, int options, void* rusage)
1316{
···4649 // We are ptracing the target process.
4750 // Allow the execution to continue so that the ptraced process can translate
4851 // the signal into a Mach message.
5252+4953 if (signal == SIGSTOP)
5054 {
5151- // TODO: notify target process it has been SIGSTOP'ed via sigqueue
5555+ // Notify target process it has been SIGSTOP'ed via sigqueue
5656+ // because we're just about to resume it and we need it
5757+ // to pass the signal back to us through a Mach message.
5858+ linux_sigqueue(ret, SIGNAL_SIGEXC_THUPDATE, -SIGSTOP);
5259 }
53605461 sys_ptrace(PT_CONTINUE, ret, NULL, signal);
5555- goto restart;
6262+6363+ if (!(options & DARLING_WAIT_NORESTART))
6464+ goto restart;
5665 }
5766 }
5867
···11#include "sigexc.h"
22#include "../base.h"
33+#include "../unistd/exit.h"
34#include <stddef.h>
55+#include <sys/signal.h>
46#include <linux-syscalls/linux.h>
77+#include <pthread/tsd_private.h>
88+#include "signal/mach_exc.h"
59610// Support for Darwin debugging.
711// Unlike other Unix-like systems, macOS doesn't use wait() to handle events in the debugged process.
1212+// wait() only receives termination events.
81399-static bool am_i_ptraced = false;
1414+static volatile bool am_i_ptraced = false;
1015static void handle_rt_signal(int signum);
1116extern void sig_restorer(void);
1717+extern int getpid(void);
1818+1219void darling_sigexc_uninstall(void);
1320void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt);
2121+2222+#define SIGEXC_TSD_KEY 102
14231524void sigexc_setup(void)
1625{
···5463 }
5564 else if (signum == SIGNAL_SIGEXC_THUPDATE)
5665 {
5757- // TODO: Change how a pending signal is handled
5858- // Use TLS?
5966 if (!am_i_ptraced)
6067 return;
6868+6969+ // Examine info->si_value
7070+ // If 0, drop the signal
7171+ // If >0, process the signal
7272+ // If <0, introduce a new signal
7373+ int sig = info->si_value;
7474+ if (sig < 0)
7575+ {
7676+ // This is only used to pass a SIGSTOP to the traced process (from the debugger)
7777+ // and have it passed back through the sigexc mechanism.
7878+ // See sys_wait4().
7979+ sigexc_handler(-sig, NULL, NULL);
8080+ }
8181+ else
8282+ {
8383+ // This is the debugger telling us how to deal with the signal.
8484+ _pthread_setspecific_direct(SIGEXC_TSD_KEY, sig);
8585+ }
6186 }
6287}
6388···6893 {
6994 struct linux_sigaction sa;
7095 sa.sa_sigaction = sigrt_handler;
7171- sa.sa_mask = sig_masks[i];
9696+ sa.sa_mask = 0xffffffff; // all other standard Unix signals should be blocked while the handler is run
7297 sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART;
7398 sa.sa_restorer = sig_restorer;
7499···101126 }
102127}
103128129129+static mach_port_t get_exc_port(int type)
130130+{
131131+ mach_msg_type_number_t count = 0;
132132+ exception_mask_t masks[EXC_TYPES_COUNT];
133133+ mach_port_t ports[EXC_TYPES_COUNT];
134134+ exception_behavior_t behaviors[EXC_TYPES_COUNT];
135135+ thread_state_flavor_t flavors[EXC_TYPES_COUNT];
136136+137137+ kern_return_t result = task_get_exception_ports(mach_task_self(), 1 << type,
138138+ masks, &count, ports, behaviors, flavors);
139139+140140+ if (result == KERN_SUCCESS)
141141+ return ports[type];
142142+143143+ return 0;
144144+}
145145+104146void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt)
105147{
148148+ if (!darling_am_i_ptraced())
149149+ return;
150150+151151+ // Send a Mach message to the debugger.
152152+ // The debugger may use ptrace(PT_THUPDATE) to change how the signal is processed.
153153+154154+ int mach_exception;
155155+ long long codes[EXCEPTION_CODE_MAX] = { 0 };
156156+ mach_port_t port;
157157+158158+ int bsd_signum = signum_linux_to_bsd(linux_signum);
159159+ if (bsd_signum <= 0)
160160+ return;
161161+106162 // SIGSEGV + SIGBUS -> EXC_BAD_ACCESS
107163 // SIGTRAP -> EXC_BREAKPOINT
108108- // * -> EXC_SOFTWARE with EXC_SOFT_SIGNAL (e.g. SIGSTOP
109109- if (darling_am_i_ptraced())
164164+ // SIGILL -> EXC_BAD_INSTRUCTION
165165+ // SIGFPE -> EXC_ARITHMETIC
166166+ // * -> EXC_SOFTWARE with EXC_SOFT_SIGNAL (e.g. SIGSTOP)
167167+168168+ switch (bsd_signum)
169169+ {
170170+ case SIGSEGV:
171171+ mach_exception = EXC_BAD_ACCESS;
172172+ codes[0] = EXC_I386_GPFLT;
173173+ break;
174174+ case SIGBUS:
175175+ mach_exception = EXC_BAD_ACCESS;
176176+ codes[0] = EXC_I386_ALIGNFLT;
177177+ break;
178178+ case SIGTRAP:
179179+ mach_exception = EXC_BREAKPOINT;
180180+ codes[0] = EXC_I386_BPT;
181181+ break;
182182+ case SIGILL:
183183+ mach_exception = EXC_BAD_INSTRUCTION;
184184+ codes[0] = EXC_I386_INVOP;
185185+ break;
186186+ case SIGFPE:
187187+ mach_exception = EXC_ARITHMETIC;
188188+ codes[0] = info->si_code;
189189+ break;
190190+ default:
191191+ mach_exception = EXC_SOFTWARE;
192192+ codes[0] = EXC_SOFT_SIGNAL;
193193+ codes[1] = bsd_signum;
194194+ }
195195+196196+ port = get_exc_port(mach_exception);
197197+198198+ if (port != 0)
110199 {
200200+ _pthread_setspecific_direct(SIGEXC_TSD_KEY, bsd_signum);
201201+202202+ mach_exception_raise(port, mach_thread_self(), mach_task_self(), mach_exception, codes, sizeof(codes) / sizeof(codes[0]));
203203+204204+ bsd_signum = _pthread_getspecific_direct(SIGEXC_TSD_KEY);
111205 }
206206+207207+ // Pass the signal to the application handler or emulate the effects of the signal if SIG_DFL is set.
208208+ if (bsd_signum)
209209+ {
210210+ bsd_sig_handler* handler = sig_handlers[bsd_signum];
211211+ if (handler == SIG_DFL || handler == SIG_ERR)
212212+ {
213213+ switch (bsd_signum)
214214+ {
215215+ // We have to stop the process manually
216216+ case SIGSTOP:
217217+ case SIGTSTP:
218218+ task_suspend(mach_task_self());
219219+ break;
220220+221221+ // These signals do nothing by default
222222+ case SIGCHLD:
223223+ case SIGWINCH:
224224+ case SIGURG:
225225+ break;
226226+227227+ // Other signals cause termination or core dump.
228228+ default:
229229+ {
230230+ int linux_signum = signum_bsd_to_linux(bsd_signum);
231231+ sys_exit(linux_signum);
232232+ }
233233+ }
234234+ }
235235+ else if (handler != SIG_IGN)
236236+ {
237237+ handler_linux_to_bsd(signum_bsd_to_linux(bsd_signum), info, ctxt);
238238+ }
239239+ }
240240+}
241241+242242+#define LINUX_SI_QUEUE (-1)
243243+int linux_sigqueue(int pid, int rtsig, int value)
244244+{
245245+ struct linux_siginfo si;
246246+247247+ memset(&si, 0, sizeof(si));
248248+ si.si_signo = rtsig;
249249+ si.si_code = LINUX_SI_QUEUE;
250250+ si.si_pid = getpid();
251251+ si.si_uid = LINUX_SYSCALL(__NR_getuid);
252252+ si.si_value = value;
253253+254254+ return LINUX_SYSCALL(__NR_rt_sigqueueinfo, pid, rtsig, &si);
255255+}
256256+257257+int linux_sigqueue_thread(int pid, int tid, int rtsig, int value)
258258+{
259259+ struct linux_siginfo si;
260260+261261+ memset(&si, 0, sizeof(si));
262262+ si.si_signo = rtsig;
263263+ si.si_code = LINUX_SI_QUEUE;
264264+ si.si_pid = getpid();
265265+ si.si_uid = LINUX_SYSCALL(__NR_getuid);
266266+ si.si_value = value;
267267+268268+ return LINUX_SYSCALL(__NR_rt_tgsigqueueinfo, pid, tid, rtsig, &si);
112269}
113270
+6-1
src/kernel/emulation/linux/signal/sigexc.h
···44#include "rtsig.h"
55#include "sigaction.h"
6677+// Uses one of the below magic values to toggle the debugging state
78#define SIGNAL_SIGEXC_TOGGLE LINUX_SIGRTMIN
99+1010+// A BSD signal number is passed as value
811#define SIGNAL_SIGEXC_THUPDATE (LINUX_SIGRTMIN + 1)
9121013#define SIGRT_MAGIC_ENABLE_SIGEXC 0xdebdeb01
1114#define SIGRT_MAGIC_DISABLE_SIGEXC 0xdebdeb00
1212-#define SIGRT_
13151416// Initializes this module
1517void sigexc_setup(void);
···2022// for PT_SIGEXC to handle this operation synchronously
2123void darling_sigexc_self(void);
2224void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt);
2525+2626+int linux_sigqueue(int pid, int rtsig, int value);
2727+int linux_sigqueue_thread(int pid, int tid, int rtsig, int value);
23282429#endif
2530