summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/sys/ptrace.225
-rw-r--r--sys/kern/kern_fork.c21
-rw-r--r--sys/kern/kern_thr.c2
-rw-r--r--sys/kern/subr_syscall.c11
-rw-r--r--sys/kern/sys_process.c11
-rw-r--r--sys/sys/proc.h4
-rw-r--r--sys/sys/ptrace.h2
-rw-r--r--tests/sys/kern/Makefile1
-rw-r--r--tests/sys/kern/ptrace_test.c259
9 files changed, 314 insertions, 22 deletions
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
index 71b432f..5c93438 100644
--- a/lib/libc/sys/ptrace.2
+++ b/lib/libc/sys/ptrace.2
@@ -2,7 +2,7 @@
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
.\"
.\" This file is in the public domain.
-.Dd July 3, 2015
+.Dd October 6, 2015
.Dt PTRACE 2
.Os
.Sh NAME
@@ -307,6 +307,8 @@ struct ptrace_lwpinfo {
siginfo_t pl_siginfo;
char pl_tdname[MAXCOMLEN + 1];
int pl_child_pid;
+ u_int pl_syscall_code;
+ u_int pl_syscall_narg;
};
.Ed
.Pp
@@ -395,6 +397,27 @@ stop when
.Dv PL_FLAG_FORKED
is set in
.Va pl_flags .
+.It pl_syscall_code
+The ABI-specific identifier of the current system call.
+Note that for indirect system calls this field reports the indirected
+system call.
+Only valid when
+.Dv PL_FLAG_SCE
+or
+.Dv PL_FLAG_SCX
+is set in
+.Va pl_flags.
+.It pl_syscall_narg
+The number of arguments passed to the current system call not counting
+the system call identifier.
+Note that for indirect system calls this field reports the arguments
+passed to the indirected system call.
+Only valid when
+.Dv PL_FLAG_SCE
+or
+.Dv PL_FLAG_SCX
+is set in
+.Va pl_flags.
.El
.It PT_GETNUMLWPS
This request returns the number of kernel threads associated with the
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 10b2339..99451c0 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/procdesc.h>
#include <sys/pioctl.h>
+#include <sys/ptrace.h>
#include <sys/racct.h>
#include <sys/resourcevar.h>
#include <sys/sched.h>
@@ -478,6 +479,8 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
td2->td_sigstk = td->td_sigstk;
td2->td_flags = TDF_INMEM;
td2->td_lend_user_pri = PRI_MAX;
+ td2->td_dbg_sc_code = td->td_dbg_sc_code;
+ td2->td_dbg_sc_narg = td->td_dbg_sc_narg;
#ifdef VIMAGE
td2->td_vnet = NULL;
@@ -1049,8 +1052,8 @@ fork_return(struct thread *td, struct trapframe *frame)
{
struct proc *p, *dbg;
+ p = td->td_proc;
if (td->td_dbgflags & TDB_STOPATFORK) {
- p = td->td_proc;
sx_xlock(&proctree_lock);
PROC_LOCK(p);
if ((p->p_pptr->p_flag & (P_TRACED | P_FOLLOWFORK)) ==
@@ -1067,9 +1070,9 @@ fork_return(struct thread *td, struct trapframe *frame)
p->p_pid, p->p_oppid);
proc_reparent(p, dbg);
sx_xunlock(&proctree_lock);
- td->td_dbgflags |= TDB_CHILD;
+ td->td_dbgflags |= TDB_CHILD | TDB_SCX;
ptracestop(td, SIGSTOP);
- td->td_dbgflags &= ~TDB_CHILD;
+ td->td_dbgflags &= ~(TDB_CHILD | TDB_SCX);
} else {
/*
* ... otherwise clear the request.
@@ -1079,6 +1082,18 @@ fork_return(struct thread *td, struct trapframe *frame)
cv_broadcast(&p->p_dbgwait);
}
PROC_UNLOCK(p);
+ } else if (p->p_flag & P_TRACED) {
+ /*
+ * This is the start of a new thread in a traced
+ * process. Report a system call exit event.
+ */
+ PROC_LOCK(p);
+ td->td_dbgflags |= TDB_SCX;
+ _STOPEVENT(p, S_SCX, td->td_dbg_sc_code);
+ if ((p->p_stops & S_PT_SCX) != 0)
+ ptracestop(td, SIGTRAP);
+ td->td_dbgflags &= ~TDB_SCX;
+ PROC_UNLOCK(p);
}
userret(td, frame);
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
index bcbc3d0..058dc19 100644
--- a/sys/kern/kern_thr.c
+++ b/sys/kern/kern_thr.c
@@ -240,6 +240,8 @@ thread_create(struct thread *td, struct rtprio *rtp,
__rangeof(struct thread, td_startcopy, td_endcopy));
newtd->td_proc = td->td_proc;
newtd->td_ucred = crhold(td->td_ucred);
+ newtd->td_dbg_sc_code = td->td_dbg_sc_code;
+ newtd->td_dbg_sc_narg = td->td_dbg_sc_narg;
error = initialize_thread(newtd, thunk);
if (error != 0) {
diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
index 925d732..1ad7dd0 100644
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -84,9 +84,12 @@ syscallenter(struct thread *td, struct syscall_args *sa)
if (error == 0) {
STOPEVENT(p, S_SCE, sa->narg);
- if (p->p_flag & P_TRACED && p->p_stops & S_PT_SCE) {
+ if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
- ptracestop((td), SIGTRAP);
+ td->td_dbg_sc_code = sa->code;
+ td->td_dbg_sc_narg = sa->narg;
+ if (p->p_stops & S_PT_SCE)
+ ptracestop((td), SIGTRAP);
PROC_UNLOCK(p);
}
if (td->td_dbgflags & TDB_USERWR) {
@@ -95,6 +98,10 @@ syscallenter(struct thread *td, struct syscall_args *sa)
* debugger modified registers or memory.
*/
error = (p->p_sysent->sv_fetch_syscall_args)(td, sa);
+ PROC_LOCK(p);
+ td->td_dbg_sc_code = sa->code;
+ td->td_dbg_sc_narg = sa->narg;
+ PROC_UNLOCK(p);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->args);
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 123dd10..15adf9a 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -96,6 +96,8 @@ struct ptrace_lwpinfo32 {
struct siginfo32 pl_siginfo; /* siginfo for signal */
char pl_tdname[MAXCOMLEN + 1]; /* LWP name. */
int pl_child_pid; /* New child pid */
+ u_int pl_syscall_code;
+ u_int pl_syscall_narg;
};
#endif
@@ -480,6 +482,8 @@ ptrace_lwpinfo_to32(const struct ptrace_lwpinfo *pl,
siginfo_to_siginfo32(&pl->pl_siginfo, &pl32->pl_siginfo);
strcpy(pl32->pl_tdname, pl->pl_tdname);
pl32->pl_child_pid = pl->pl_child_pid;
+ pl32->pl_syscall_code = pl->pl_syscall_code;
+ pl32->pl_syscall_narg = pl->pl_syscall_narg;
}
#endif /* COMPAT_FREEBSD32 */
@@ -1210,6 +1214,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
strcpy(pl->pl_tdname, td2->td_name);
+ if ((td2->td_dbgflags & (TDB_SCE | TDB_SCX)) != 0) {
+ pl->pl_syscall_code = td2->td_dbg_sc_code;
+ pl->pl_syscall_narg = td2->td_dbg_sc_narg;
+ } else {
+ pl->pl_syscall_code = 0;
+ pl->pl_syscall_narg = 0;
+ }
#ifdef COMPAT_FREEBSD32
if (wrap32)
ptrace_lwpinfo_to32(pl, pl32);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index b9606f8..3b188ca 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -170,6 +170,7 @@ struct procdesc;
struct racct;
struct sbuf;
struct sleepqueue;
+struct syscall_args;
struct td_sched;
struct thread;
struct trapframe;
@@ -320,6 +321,8 @@ struct thread {
struct vm_page **td_ma; /* (k) uio pages held */
int td_ma_cnt; /* (k) size of *td_ma */
void *td_su; /* (k) FFS SU private */
+ u_int td_dbg_sc_code; /* (c) Syscall code to debugger. */
+ u_int td_dbg_sc_narg; /* (c) Syscall arg count to debugger.*/
};
struct mtx *thread_lock_block(struct thread *);
@@ -934,7 +937,6 @@ void userret(struct thread *, struct trapframe *);
void cpu_exit(struct thread *);
void exit1(struct thread *, int) __dead2;
-struct syscall_args;
int cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
void cpu_fork(struct thread *, struct proc *, struct thread *, int);
void cpu_set_fork_handler(struct thread *, void (*)(void *), void *);
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index e770a06..de4e7a7 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -113,6 +113,8 @@ struct ptrace_lwpinfo {
struct __siginfo pl_siginfo; /* siginfo for signal */
char pl_tdname[MAXCOMLEN + 1]; /* LWP name */
int pl_child_pid; /* New child pid */
+ u_int pl_syscall_code;
+ u_int pl_syscall_narg;
};
/* Argument structure for PT_VM_ENTRY. */
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index bf6aa0d..c345e5d 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -7,6 +7,7 @@ ATF_TESTS_C+= ptrace_test
ATF_TESTS_C+= unix_seqpacket_test
TEST_METADATA.unix_seqpacket_test+= timeout="15"
+LDADD.ptrace_test+= -lpthread
LDADD.unix_seqpacket_test+= -lpthread
WARNS?= 5
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index c10c097..1731698 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -29,10 +29,12 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/ptrace.h>
+#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <errno.h>
+#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -409,12 +411,15 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
* debugger is attached to it.
*/
static __dead2 void
-follow_fork_parent(void)
+follow_fork_parent(bool use_vfork)
{
pid_t fpid, wpid;
int status;
- CHILD_REQUIRE((fpid = fork()) != -1);
+ if (use_vfork)
+ CHILD_REQUIRE((fpid = vfork()) != -1);
+ else
+ CHILD_REQUIRE((fpid = fork()) != -1);
if (fpid == 0)
/* Child */
@@ -434,7 +439,7 @@ follow_fork_parent(void)
* child process.
*/
static pid_t
-handle_fork_events(pid_t parent)
+handle_fork_events(pid_t parent, struct ptrace_lwpinfo *ppl)
{
struct ptrace_lwpinfo pl;
bool fork_reported[2];
@@ -469,6 +474,8 @@ handle_fork_events(pid_t parent)
child = wpid;
else
ATF_REQUIRE(child == wpid);
+ if (ppl != NULL)
+ ppl[1] = pl;
fork_reported[1] = true;
} else {
ATF_REQUIRE(wpid == parent);
@@ -478,6 +485,8 @@ handle_fork_events(pid_t parent)
child = pl.pl_child_pid;
else
ATF_REQUIRE(child == pl.pl_child_pid);
+ if (ppl != NULL)
+ ppl[0] = pl;
fork_reported[0] = true;
}
}
@@ -499,7 +508,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -516,7 +525,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached, tc)
/* Continue the child ignoring the SIGSTOP. */
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -555,7 +564,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -572,7 +581,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached, tc)
/* Continue the child ignoring the SIGSTOP. */
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -606,7 +615,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -623,7 +632,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc)
/* Continue the child ignoring the SIGSTOP. */
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
@@ -688,7 +697,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -715,7 +724,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc)
/* Signal the fork parent to continue. */
close(cpipe[0]);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -756,7 +765,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -783,7 +792,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc)
/* Signal the fork parent to continue. */
close(cpipe[0]);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -819,7 +828,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -846,7 +855,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
/* Signal the fork parent to continue. */
close(cpipe[0]);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
@@ -866,6 +875,223 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
ATF_REQUIRE(errno == ECHILD);
}
+/*
+ * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
+ * child process created via fork() reports the correct value.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_fork);
+ATF_TC_BODY(ptrace__new_child_pl_syscall_code_fork, tc)
+{
+ struct ptrace_lwpinfo pl[2];
+ pid_t children[2], fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ follow_fork_parent(false);
+ }
+
+ /* Parent process. */
+ children[0] = fpid;
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(children[0], &status, 0);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ /* Wait for both halves of the fork event to get reported. */
+ children[1] = handle_fork_events(children[0], pl);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE(pl[0].pl_syscall_code == SYS_fork);
+ ATF_REQUIRE(pl[0].pl_syscall_code == pl[1].pl_syscall_code);
+ ATF_REQUIRE(pl[0].pl_syscall_narg == pl[1].pl_syscall_narg);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * The child can't exit until the grandchild reports status, so the
+ * grandchild should report its exit first to the debugger.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[1]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 2);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
+ * child process created via vfork() reports the correct value.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_vfork);
+ATF_TC_BODY(ptrace__new_child_pl_syscall_code_vfork, tc)
+{
+ struct ptrace_lwpinfo pl[2];
+ pid_t children[2], fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ follow_fork_parent(true);
+ }
+
+ /* Parent process. */
+ children[0] = fpid;
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(children[0], &status, 0);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ /* Wait for both halves of the fork event to get reported. */
+ children[1] = handle_fork_events(children[0], pl);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE(pl[0].pl_syscall_code == SYS_vfork);
+ ATF_REQUIRE(pl[0].pl_syscall_code == pl[1].pl_syscall_code);
+ ATF_REQUIRE(pl[0].pl_syscall_narg == pl[1].pl_syscall_narg);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * The child can't exit until the grandchild reports status, so the
+ * grandchild should report its exit first to the debugger.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[1]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 2);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+static void *
+simple_thread(void *arg __unused)
+{
+
+ pthread_exit(NULL);
+}
+
+/*
+ * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
+ * thread reports the correct value.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_thread);
+ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ lwpid_t main;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ pthread_t thread;
+
+ trace_me();
+
+ CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread,
+ NULL) == 0);
+ CHILD_REQUIRE(pthread_join(thread, NULL) == 0);
+ exit(1);
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ main = pl.pl_lwpid;
+
+ /*
+ * Continue the child ignoring the SIGSTOP and tracing all
+ * system call exits.
+ */
+ ATF_REQUIRE(ptrace(PT_TO_SCX, fpid, (caddr_t)1, 0) != -1);
+
+ /*
+ * Wait for the new thread to arrive. pthread_create() might
+ * invoke any number of system calls. For now we just wait
+ * for the new thread to arrive and make sure it reports a
+ * valid system call code. If ptrace grows thread event
+ * reporting then this test can be made more precise.
+ */
+ for (;;) {
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE(pl.pl_syscall_code != 0);
+ if (pl.pl_lwpid != main)
+ /* New thread seen. */
+ break;
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+ }
+
+ /* Wait for the child to exit. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+ for (;;) {
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ if (WIFEXITED(status))
+ break;
+
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+ }
+
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -881,6 +1107,9 @@ ATF_TP_ADD_TCS(tp)
ptrace__follow_fork_child_detached_unrelated_debugger);
ATF_TP_ADD_TC(tp,
ptrace__follow_fork_parent_detached_unrelated_debugger);
+ ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_fork);
+ ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_vfork);
+ ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_thread);
return (atf_no_error());
}
OpenPOWER on IntegriCloud