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/0b3f7c43c7d4
branches: trunk
changeset: 350599:0b3f7c43c7d4
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 035c2588af2a -r 0b3f7c43c7d4 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 035c2588af2a -r 0b3f7c43c7d4 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 035c2588af2a -r 0b3f7c43c7d4 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 035c2588af2a -r 0b3f7c43c7d4 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 035c2588af2a -r 0b3f7c43c7d4 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 035c2588af2a -r 0b3f7c43c7d4 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