On Tue, May 11, 2010 at 01:35:00PM +0300, Ali Polatel wrote: > Kostik Belousov yazm??: > > On Mon, May 10, 2010 at 07:48:47PM +0300, Ali Polatel wrote: > > > Kostik Belousov yazm??: > > > > On Sun, May 09, 2010 at 09:28:51PM +0300, Ali Polatel wrote: > > > > > Kostik Belousov yazm??: > > > > > > On Sun, May 09, 2010 at 08:33:03AM +0300, Ali Polatel wrote: > > > > > > > Kostik Belousov yazm??: > > > > > > > > On Sat, May 08, 2010 at 02:15:09PM +0300, Ali Polatel wrote: > > > > > > > > > Does FreeBSD's ptrace have a way to tell the difference > > > > > > > > > between normal > > > > > > > > > traps and those caused by a system call? > > > > > > > > > > > > > > > > > > On Linux? this is possible by passing PTRACE_O_TRACESYSGOOD > > > > > > > > > option to the > > > > > > > > > ptrace request PTRACE_SETOPTIONS which makes the kernel set > > > > > > > > > bit 7 in the > > > > > > > > > syscall number when delivering system call traps, > > > > > > > > > (i.e., deliver (SIGTRAP | 0x80)). > > > > > > > > > > > > > > > > > > I'm not sure if this is possible on FreeBSD. PT_LWPINFO > > > > > > > > > request looks > > > > > > > > > related but can't be sure. > > > > > > > > > > > > > > > > > > ?: http://linux.die.net/man/2/ptrace > > > > > > > > > > > > > > > > There is already procfs(5)-based interface to get a reason for > > > > > > > > stop. > > > > > > > > Look at the ioctl PIOCSTATUS. Yes, you have to mount procfs. > > > > > > > > > > > > > > > > The interface can be lifted to ptrace(2), but I think using the > > > > > > > > capacity > > > > > > > > of procfs is not wrong there. > > > > > > > > > > > > > > Hmm ok, I've been playing around with PIOCSTATUS but it doesn't > > > > > > > seem to > > > > > > > work, there's not much documentation about it either so I figured > > > > > > > I'll > > > > > > > just ask. > > > > > > > > > > > > > > The code is here: http://alip.github.com/code/piocstatus.c > > > > > > > > > > > > > > The traced child is stopped at the beginning of a system call. I > > > > > > > await > > > > > > > that the PIOCSTATUS request sets ps.why to S_SCE but it's always > > > > > > > zero. > > > > > > > Can you help me figure out what I'm doing wrong? :) > > > > > > > > > > > > Apparently I missed the fact that S_PT_SCE and S_SCE are different > > > > > > flags. It seems you have to use procfs stop events (PIOCBIS) and > > > > > > procfs-based loop to get p_step set to 1. > > > > > > > > > > So I can't use ptrace() together with ioctl() based tracing. > > > > > Fair enough... > > > > > > > > > > I'm trying to write the ioctl() based equivalent of what I've started > > > > > but I can't figure out how to start tracing by forking a new child. > > > > > > > > > > Here's how I do it on Linux: > > > > > fork() > > > > > child: call kill(getpid(), SIGSTOP) and wait for the parent to > > > > > resume. > > > > > parent: wait for the child, set up tracing options and start tracing. > > > > > > > > > > I can directly use execve() so the child will stop too but I'm > > > > > writing a > > > > > library and for its unit tests I need to use the SIGSTOP method > > > > > because > > > > > I won't do any exec'ing. > > > > > > > > > > I tried to do the same with ioctl(), it works most of the time but it > > > > > hangs every now and then at PIOCWAIT. I'm inclined to think there's a > > > > > race condition but I couldn't figure out why. > > > > > > > > > > The code is here: http://alip.github.com/code/piocstatus-2.c > > > > > > > > > > Fwiw this is about a library called > > > > > pinktrace(http://dev.exherbo.org/~alip/pinktrace) I'm trying to write. > > > > > Its aim is to be a lightweight portable tracing library with multiple > > > > > backends (like procfs and ptrace etc.) I think this could prove useful > > > > > for many people who need to do tracing and doesn't want to bother with > > > > > platform specific details. > > > > > > > > I see. You could try this patch. It requires HEAD or recent RELENG_8 > > > > to be applicable. I added PL_EVENT_SCE/SCX to PT_LWPINFO for i386 and > > > > amd64. Please note that I did not tested it, only booted the kernel to > > > > make sure that it does not break too ugly. > > > > > > > > diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c > > > > index f3dba94..f97f875 100644 > > > <snip the nice patch> > > > > > > Looks great, I could only test it basically but it seems to work fine. > > > If this is merged, truss can make use of this too. > > > > > > Another question is how hard is it to implement PL_EVENT_EXEC? > > > This could be useful for truss as it updates the execution type of the > > > process after successful execve() calls afaict. > > > > Is this needed ? The question is not rhetorical, I am trying to > > understand what prevents use of PT_TO_SCE and checking the syscall > > number ? You would screen for SYS_execve or SYS_fexecve and > > reset the debugger state on SIGTRAP that is supplied to the debugger > > before first instruction of new image is executed. > > > > Not really needed, just cleaner imo. As system call numbers may be > different for different execution types and you need to look it up from > a table using a string as argument which is slow. > > > Can you, please, extract and provide me with the code you used to test > > the PL_EVENT_SCE/SCX patch ? > > Sure, the code is below. It doesn't work though (Sorry to tell you it > was working fine in my first post, too much vodka makes me see things > differently as it seems). The PT_LWPINFO request returns > PL_EVENT_SIGNAL in both cases.
Yes, this is a relief, since I realized that syscall enter/leave is reported
using SIGTRAP. I have to move the events to flags. Also, original patch
missed SCE on i386. Below is the updated change.
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index f3dba94..f97f875 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -911,6 +911,7 @@ syscall(struct trapframe *frame)
if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
}
error = fetch_syscall_args(td, &sa);
@@ -965,6 +966,11 @@ syscall(struct trapframe *frame)
#endif
}
retval:
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCE;
+ PROC_UNLOCK(p);
+ }
cpu_set_syscall_retval(td, error);
/*
@@ -1007,12 +1013,21 @@ syscall(struct trapframe *frame)
ktrsysret(sa.code, error, td->td_retval[0]);
#endif
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags |= TDB_SCX;
+ PROC_UNLOCK(p);
+ }
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa.code);
-
PTRACESTOP_SC(p, td, S_PT_SCX);
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCX;
+ PROC_UNLOCK(p);
+ }
}
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
index aa1ae6c..300d1f6 100644
--- a/sys/amd64/ia32/ia32_syscall.c
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -186,6 +186,7 @@ ia32_syscall(struct trapframe *frame)
if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
}
error = fetch_ia32_syscall_args(td, &sa);
@@ -218,6 +219,11 @@ ia32_syscall(struct trapframe *frame)
td->td_errno = error;
}
retval:
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCE;
+ PROC_UNLOCK(p);
+ }
cpu_set_syscall_retval(td, error);
/*
@@ -259,14 +265,23 @@ ia32_syscall(struct trapframe *frame)
ktrsysret(sa.code, error, td->td_retval[0]);
#endif
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags |= TDB_SCX;
+ PROC_UNLOCK(p);
+ }
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa.code);
-
PTRACESTOP_SC(p, td, S_PT_SCX);
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCX;
+ PROC_UNLOCK(p);
+ }
}
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index a11daa6..44c8585 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -1074,6 +1074,7 @@ syscall(struct trapframe *frame)
if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
}
error = fetch_syscall_args(td, &sa);
@@ -1128,6 +1129,11 @@ syscall(struct trapframe *frame)
#endif
}
retval:
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCE;
+ PROC_UNLOCK(p);
+ }
cpu_set_syscall_retval(td, error);
/*
@@ -1170,13 +1176,22 @@ syscall(struct trapframe *frame)
ktrsysret(sa.code, error, td->td_retval[0]);
#endif
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags |= TDB_SCX;
+ PROC_UNLOCK(p);
+ }
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa.code);
-
PTRACESTOP_SC(p, td, S_PT_SCX);
+ if (p->p_flag & P_TRACED) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCX;
+ PROC_UNLOCK(p);
+ }
}
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index d8cc4f0..bc0dd24 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -1105,9 +1105,11 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void
*addr, int data)
pl->pl_lwpid = td2->td_tid;
if (td2->td_dbgflags & TDB_XSIG)
pl->pl_event = PL_EVENT_SIGNAL;
- else
- pl->pl_event = 0;
pl->pl_flags = 0;
+ if (td2->td_dbgflags & TDB_SCE)
+ pl->pl_flags |= PL_FLAG_SCE;
+ else if (td2->td_dbgflags & TDB_SCX)
+ pl->pl_flags |= PL_FLAG_SCX;
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
break;
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index e32e494..9457ad1 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -364,6 +364,8 @@ do {
\
#define TDB_SUSPEND 0x00000001 /* Thread is suspended by debugger */
#define TDB_XSIG 0x00000002 /* Thread is exchanging signal under
trace */
#define TDB_USERWR 0x00000004 /* Debugger modified memory or
registers */
+#define TDB_SCE 0x00000008 /* Thread performs syscall enter */
+#define TDB_SCX 0x00000010 /* Thread performs syscall exit */
/*
* "Private" flags kept in td_pflags:
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index b30447c..8be0cae 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -99,6 +99,8 @@ struct ptrace_lwpinfo {
int pl_flags; /* LWP flags. */
#define PL_FLAG_SA 0x01 /* M:N thread */
#define PL_FLAG_BOUND 0x02 /* M:N bound thread */
+#define PL_FLAG_SCE 0x04 /* syscall enter point */
+#define PL_FLAG_SCX 0x08 /* syscall leave point */
sigset_t pl_sigmask; /* LWP signal mask */
sigset_t pl_siglist; /* LWP pending signal */
};
pgpveuiwen4WU.pgp
Description: PGP signature

