Adjust ptrace interface to properly suport single threaded continue.
authorclaudio <claudio@openbsd.org>
Tue, 1 Oct 2024 08:28:34 +0000 (08:28 +0000)
committerclaudio <claudio@openbsd.org>
Tue, 1 Oct 2024 08:28:34 +0000 (08:28 +0000)
Introduce P_TRACESINGLE flag to instruct the trapped thread to not
wakeup the other threads (via single_thread_clear). This must be done
like this since ptrace must wake just the single thread to ensure it
runs first and gets the ps_xsig value from ptrace.

Modern gdb depends on this for multi-threaded processes, when a breakpoint
is hit gdb fixes up the trapping instruction and then single steps over
it with only that thread. After that single step gdb continues with all
threads. If all threads are run like now it is possible that one of the
other threads hits a breakpoint before the single step is done which results
in an assertion in gdb (because that is not expected).
OK mpi@

sys/kern/kern_sig.c
sys/kern/sys_process.c
sys/sys/proc.h

index 809b07c..8f8ab64 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_sig.c,v 1.338 2024/08/10 09:18:09 jsg Exp $      */
+/*     $OpenBSD: kern_sig.c,v 1.339 2024/10/01 08:28:34 claudio Exp $  */
 /*     $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $   */
 
 /*
@@ -840,7 +840,9 @@ trapsignal(struct proc *p, int signum, u_long trapno, int code,
                        SCHED_UNLOCK();
 
                        signum = pr->ps_xsig;
-                       single_thread_clear(p, 0);
+                       if ((p->p_flag & P_TRACESINGLE) == 0)
+                               single_thread_clear(p, 0);
+                       atomic_clearbits_int(&p->p_flag, P_TRACESINGLE);
 
                        /*
                         * If we are no longer being traced, or the parent
@@ -1359,7 +1361,9 @@ cursig(struct proc *p, struct sigctx *sctx)
                                atomic_clearbits_int(&pr->ps_siglist, mask);
                        }
 
-                       single_thread_clear(p, 0);
+                       if ((p->p_flag & P_TRACESINGLE) == 0)
+                               single_thread_clear(p, 0);
+                       atomic_clearbits_int(&p->p_flag, P_TRACESINGLE);
 
                        /*
                         * If we are no longer being traced, or the parent
index 9520d0d..8d9daeb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sys_process.c,v 1.99 2024/09/30 12:32:26 claudio Exp $        */
+/*     $OpenBSD: sys_process.c,v 1.100 2024/10/01 08:28:34 claudio Exp $       */
 /*     $NetBSD: sys_process.c,v 1.55 1996/05/15 06:17:47 tls Exp $     */
 
 /*-
@@ -441,6 +441,13 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
 
                if (pid < THREAD_PID_OFFSET && tr->ps_single)
                        t = tr->ps_single;
+               else if (t == tr->ps_single)
+                       atomic_setbits_int(&t->p_flag, P_TRACESINGLE);
+               else {
+                       error = EINVAL;
+                       goto fail;
+               }
+                       
 
                /* If the address parameter is not (int *)1, set the pc. */
                if ((int *)addr != (int *)1)
index def830f..1472a16 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: proc.h,v 1.371 2024/09/01 03:09:00 jsg Exp $  */
+/*     $OpenBSD: proc.h,v 1.372 2024/10/01 08:28:34 claudio Exp $      */
 /*     $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $       */
 
 /*-
@@ -436,6 +436,7 @@ struct proc {
 #define        P_SINTR         0x00000080      /* Sleep is interruptible. */
 #define        P_SYSTEM        0x00000200      /* No sigs, stats or swapping. */
 #define        P_TIMEOUT       0x00000400      /* Timing out during sleep. */
+#define        P_TRACESINGLE   0x00001000      /* Ptrace: keep single threaded. */
 #define        P_WEXIT         0x00002000      /* Working on exiting. */
 #define        P_OWEUPC        0x00008000      /* Owe proc an addupc() at next ast. */
 #define        P_SUSPSINGLE    0x00080000      /* Need to stop for single threading. */
@@ -446,8 +447,8 @@ struct proc {
 #define        P_BITS \
     ("\20" "\01INKTR" "\02PROFPEND" "\03ALRMPEND" "\04SIGSUSPEND" \
      "\05CANTSLEEP" "\06WSLEEP" "\010SINTR" "\012SYSTEM" "\013TIMEOUT" \
-     "\016WEXIT" "\020OWEUPC" "\024SUSPSINGLE" "\033THREAD" \
-     "\034SUSPSIG" "\037CPUPEG")
+     "\015TRACESINGLE" "\016WEXIT" "\020OWEUPC" "\024SUSPSINGLE" \
+     "\033THREAD" "\034SUSPSIG" "\037CPUPEG")
 
 #define        THREAD_PID_OFFSET       100000