Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Introduce PTRACE_LWP_{CREATE, EXIT} in ptrace(2) and TRAP_LWP...



details:   https://anonhg.NetBSD.org/src/rev/786de7eddc44
branches:  trunk
changeset: 820741:786de7eddc44
user:      kamil <kamil%NetBSD.org@localhost>
date:      Sat Jan 14 06:36:52 2017 +0000

description:
Introduce PTRACE_LWP_{CREATE,EXIT} in ptrace(2) and TRAP_LWP in siginfo(5)

Add interface in ptrace(2) to track thread (LWP) events:
 - birth,
 - termination.

The purpose of this thread is to keep track of the current thread state in
a tracee and apply e.g. per-thread designed hardware assisted watchpoints.

This interface reuses the EVENT_MASK and PROCESS_STATE interface, and
shares it with PTRACE_FORK, PTRACE_VFORK and PTRACE_VFORK_DONE.

Change the following structure:

typedef struct ptrace_state {
        int     pe_report_event;
        pid_t   pe_other_pid;
} ptrace_state_t;

to

typedef struct ptrace_state {
        int     pe_report_event;
        union {
                pid_t   _pe_other_pid;
                lwpid_t _pe_lwp;
        } _option;
} ptrace_state_t;

#define pe_other_pid    _option._pe_other_pid
#define pe_lwp          _option._pe_lwp

This keeps size of ptrace_state_t unchanged as both pid_t and lwpid_t are
defined as int32_t-like integer. This change does not break existing
prebuilt software and has minimal effect on necessity for source-code
changes. In summary, this change should be binary compatible and shouldn't
break build of existing software.


Introduce new siginfo(5) type for LWP events under the SIGTRAP signal:
TRAP_LWP. This change will help debuggers to distinguish exact source of
SIGTRAP.


Add two basic t_ptrace_wait* tests:
lwp_create1:
    Verify that 1 LWP creation is intercepted by ptrace(2) with
    EVENT_MASK set to PTRACE_LWP_CREATE

lwp_exit1:
    Verify that 1 LWP creation is intercepted by ptrace(2) with
    EVENT_MASK set to PTRACE_LWP_EXIT

All tests are passing.


Surfing the previous kernel ABI bump to 7.99.59 for PTRACE_VFORK{,_DONE}.

Sponsored by <The NetBSD Foundation>

diffstat:

 sys/kern/kern_lwp.c          |   40 +++++-
 sys/kern/sys_ptrace_common.c |   24 ++-
 sys/sys/proc.h               |    9 +-
 sys/sys/ptrace.h             |   12 +-
 sys/sys/siginfo.h            |    3 +-
 tests/kernel/t_ptrace_wait.c |  318 ++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 396 insertions(+), 10 deletions(-)

diffs (truncated from 578 to 300 lines):

diff -r a31245b52c3f -r 786de7eddc44 sys/kern/kern_lwp.c
--- a/sys/kern/kern_lwp.c       Sat Jan 14 04:54:42 2017 +0000
+++ b/sys/kern/kern_lwp.c       Sat Jan 14 06:36:52 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_lwp.c,v 1.185 2016/07/03 14:24:58 christos Exp $  */
+/*     $NetBSD: kern_lwp.c,v 1.186 2017/01/14 06:36:52 kamil Exp $     */
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -211,7 +211,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.185 2016/07/03 14:24:58 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.186 2017/01/14 06:36:52 kamil Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -967,6 +967,24 @@
        if (p2->p_emul->e_lwp_fork)
                (*p2->p_emul->e_lwp_fork)(l1, l2);
 
+       /* If the process is traced, report lwp creation to a debugger */
+       if ((p2->p_slflag & (PSL_TRACED|PSL_TRACELWP_CREATE|PSL_SYSCALL)) ==
+           (PSL_TRACED|PSL_TRACELWP_CREATE)) {
+               ksiginfo_t ksi;
+
+               /* Tracing */
+               KASSERT((l2->l_flag & LW_SYSTEM) == 0);
+
+               p2->p_lwp_created = l2->l_lid;
+
+               KSI_INIT_EMPTY(&ksi);
+               ksi.ksi_signo = SIGTRAP;
+               ksi.ksi_code = TRAP_LWP;
+               mutex_enter(proc_lock);
+               kpsignal(p2, &ksi, NULL);
+               mutex_exit(proc_lock);
+       }
+
        return (0);
 }
 
@@ -1030,6 +1048,24 @@
         */
        LOCKDEBUG_BARRIER(&kernel_lock, 0);
 
+       /* If the process is traced, report lwp termination to a debugger */
+       if ((p->p_slflag & (PSL_TRACED|PSL_TRACELWP_EXIT|PSL_SYSCALL)) ==
+           (PSL_TRACED|PSL_TRACELWP_EXIT)) {
+               ksiginfo_t ksi;
+
+               /* Tracing */
+               KASSERT((l->l_flag & LW_SYSTEM) == 0);
+
+               p->p_lwp_created = l->l_lid;
+
+               KSI_INIT_EMPTY(&ksi);
+               ksi.ksi_signo = SIGTRAP;
+               ksi.ksi_code = TRAP_LWP;
+               mutex_enter(proc_lock);
+               kpsignal(p, &ksi, NULL);
+               mutex_exit(proc_lock);
+       }
+
        /*
         * If we are the last live LWP in a process, we need to exit the
         * entire process.  We do so with an exit status of zero, because
diff -r a31245b52c3f -r 786de7eddc44 sys/kern/sys_ptrace_common.c
--- a/sys/kern/sys_ptrace_common.c      Sat Jan 14 04:54:42 2017 +0000
+++ b/sys/kern/sys_ptrace_common.c      Sat Jan 14 06:36:52 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sys_ptrace_common.c,v 1.9 2017/01/13 23:00:35 kamil Exp $      */
+/*     $NetBSD: sys_ptrace_common.c,v 1.10 2017/01/14 06:36:52 kamil Exp $     */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.9 2017/01/13 23:00:35 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.10 2017/01/14 06:36:52 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
@@ -792,6 +792,8 @@
                t->p_fpid = 0;
                t->p_vfpid = 0;
                t->p_vfpid_done = 0;
+               t->p_lwp_created = 0;
+               t->p_lwp_exited = 0;
                /* Finally, deliver the requested signal (or none). */
                if (t->p_stat == SSTOP) {
                        /*
@@ -861,6 +863,10 @@
                    PTRACE_VFORK : 0;
                pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEVFORK_DONE) ?
                    PTRACE_VFORK_DONE : 0;
+               pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_CREATE) ?
+                   PTRACE_LWP_CREATE : 0;
+               pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_EXIT) ?
+                   PTRACE_LWP_EXIT : 0;
                error = copyout(&pe, addr, sizeof(pe));
                break;
 
@@ -892,6 +898,14 @@
                        SET(t->p_slflag, PSL_TRACEVFORK_DONE);
                else
                        CLR(t->p_slflag, PSL_TRACEVFORK_DONE);
+               if (pe.pe_set_event & PTRACE_LWP_CREATE)
+                       SET(t->p_slflag, PSL_TRACELWP_CREATE);
+               else
+                       CLR(t->p_slflag, PSL_TRACELWP_CREATE);
+               if (pe.pe_set_event & PTRACE_LWP_EXIT)
+                       SET(t->p_slflag, PSL_TRACELWP_EXIT);
+               else
+                       CLR(t->p_slflag, PSL_TRACELWP_EXIT);
                break;
 
        case  PT_GET_PROCESS_STATE:
@@ -911,6 +925,12 @@
                } else if (t->p_vfpid_done) {
                        ps.pe_report_event = PTRACE_VFORK_DONE;
                        ps.pe_other_pid = t->p_vfpid_done;
+               } else if (t->p_lwp_created) {
+                       ps.pe_report_event = PTRACE_LWP_CREATE;
+                       ps.pe_lwp = t->p_lwp_created;
+               } else if (t->p_lwp_exited) {
+                       ps.pe_report_event = PTRACE_LWP_EXIT;
+                       ps.pe_lwp = t->p_lwp_exited;
                }
                error = copyout(&ps, addr, sizeof(ps));
                break;
diff -r a31245b52c3f -r 786de7eddc44 sys/sys/proc.h
--- a/sys/sys/proc.h    Sat Jan 14 04:54:42 2017 +0000
+++ b/sys/sys/proc.h    Sat Jan 14 06:36:52 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: proc.h,v 1.336 2017/01/13 23:00:35 kamil Exp $ */
+/*     $NetBSD: proc.h,v 1.337 2017/01/14 06:36:52 kamil Exp $ */
 
 /*-
  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -312,6 +312,8 @@
        pid_t           p_fpid;         /* :: forked pid */
        pid_t           p_vfpid;        /* :: vforked pid */
        pid_t           p_vfpid_done;   /* :: vforked done pid */
+       lwpid_t         p_lwp_created;  /* :: lwp created */
+       lwpid_t         p_lwp_exited;   /* :: lwp exited */
        u_int           p_nsems;        /* Count of semaphores */
 
 /*
@@ -403,6 +405,11 @@
 #define        PSL_TRACEVFORK  0x00000002 /* traced process wants vfork events */
 #define        PSL_TRACEVFORK_DONE     \
                        0x00000004 /* traced process wants vfork done events */
+#define        PSL_TRACELWP_CREATE     \
+                       0x00000008 /* traced process wants LWP create events */
+#define        PSL_TRACELWP_EXIT       \
+                       0x00000010 /* traced process wants LWP exit events */
+
 #define        PSL_TRACED      0x00000800 /* Debugged process being traced */
 #define        PSL_FSTRACE     0x00010000 /* Debugger process being traced by procfs */
 #define        PSL_CHTRACED    0x00400000 /* Child has been traced & reparented */
diff -r a31245b52c3f -r 786de7eddc44 sys/sys/ptrace.h
--- a/sys/sys/ptrace.h  Sat Jan 14 04:54:42 2017 +0000
+++ b/sys/sys/ptrace.h  Sat Jan 14 06:36:52 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ptrace.h,v 1.53 2017/01/13 23:00:35 kamil Exp $        */
+/*     $NetBSD: ptrace.h,v 1.54 2017/01/14 06:36:52 kamil Exp $        */
 
 /*-
  * Copyright (c) 1984, 1993
@@ -90,12 +90,20 @@
 /* PT_GET_PROCESS_STATE */
 typedef struct ptrace_state {
        int     pe_report_event;
-       pid_t   pe_other_pid;
+       union {
+               pid_t   _pe_other_pid;
+               lwpid_t _pe_lwp;
+       } _option;
 } ptrace_state_t;
 
+#define        pe_other_pid    _option._pe_other_pid
+#define        pe_lwp          _option._pe_lwp
+
 #define        PTRACE_FORK             0x0001  /* Report forks */
 #define        PTRACE_VFORK            0x0002  /* Report vforks */
 #define        PTRACE_VFORK_DONE       0x0004  /* Report parent resumed from vforks */
+#define        PTRACE_LWP_CREATE       0x0008  /* Report LWP creation */
+#define        PTRACE_LWP_EXIT         0x0010  /* Report LWP termination */
 
 /*
  * Argument structure for PT_IO.
diff -r a31245b52c3f -r 786de7eddc44 sys/sys/siginfo.h
--- a/sys/sys/siginfo.h Sat Jan 14 04:54:42 2017 +0000
+++ b/sys/sys/siginfo.h Sat Jan 14 06:36:52 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: siginfo.h,v 1.28 2017/01/10 00:48:37 kamil Exp $        */
+/*     $NetBSD: siginfo.h,v 1.29 2017/01/14 06:36:52 kamil Exp $        */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -212,6 +212,7 @@
 #define        TRAP_TRACE      2       /* Process trace trap                   */
 #define        TRAP_EXEC       3       /* Process exec trap                    */
 #define        TRAP_CHLD       4       /* Process child trap                   */
+#define        TRAP_LWP        5       /* Process lwp trap                     */
 
 /* SIGCHLD */
 #define        CLD_EXITED      1       /* Child has exited                     */
diff -r a31245b52c3f -r 786de7eddc44 tests/kernel/t_ptrace_wait.c
--- a/tests/kernel/t_ptrace_wait.c      Sat Jan 14 04:54:42 2017 +0000
+++ b/tests/kernel/t_ptrace_wait.c      Sat Jan 14 06:36:52 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: t_ptrace_wait.c,v 1.58 2017/01/14 04:37:55 kamil Exp $ */
+/*     $NetBSD: t_ptrace_wait.c,v 1.59 2017/01/14 06:36:52 kamil Exp $ */
 
 /*-
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.58 2017/01/14 04:37:55 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.59 2017/01/14 06:36:52 kamil Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -39,6 +39,7 @@
 #include <machine/reg.h>
 #include <err.h>
 #include <errno.h>
+#include <lwp.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -1184,6 +1185,116 @@
        TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
 }
 
+ATF_TC(eventmask5);
+ATF_TC_HEAD(eventmask5, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Verify that PTRACE_LWP_CREATE in EVENT_MASK is preserved");
+}
+
+ATF_TC_BODY(eventmask5, tc)
+{
+       const int exitval = 5;
+       const int sigval = SIGSTOP;
+       pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+       int status;
+#endif
+       ptrace_event_t set_event, get_event;
+       const int len = sizeof(ptrace_event_t);
+
+       printf("Before forking process PID=%d\n", getpid());
+       ATF_REQUIRE((child = fork()) != -1);
+       if (child == 0) {
+               printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+               FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+               printf("Before raising %s from child\n", strsignal(sigval));
+               FORKEE_ASSERT(raise(sigval) == 0);
+
+               printf("Before exiting of the child process\n");
+               _exit(exitval);
+       }
+       printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+       validate_status_stopped(status, sigval);
+
+       set_event.pe_set_event = PTRACE_LWP_CREATE;
+       ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
+       ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
+       ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
+
+       printf("Before resuming the child process where it left off and "
+           "without signal to be sent\n");
+       ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+       validate_status_exited(status, exitval);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(eventmask6);
+ATF_TC_HEAD(eventmask6, tc)
+{



Home | Main Index | Thread Index | Old Index