Ability to tell the difference between normal and syscall traps
Kostik Belousov
kostikbel at gmail.com
Fri May 14 12:57:38 UTC 2010
On Fri, May 14, 2010 at 06:51:19AM -0400, John Baldwin wrote:
> Ali Polatel wrote:
> >Kostik Belousov yazm????:
> >>On Mon, May 10, 2010 at 07:48:47PM +0300, Ali Polatel wrote:
> >>>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.
>
> I agree that this would be cleaner. Having worked on the ptrace/procfs
> stuff in other tools like strace and truss, exec truly is an important
> event to a debugger aside from just being another system call as it
> signals that the address space has been changed.
Ok, I would not much object. But I finally tired of adding the same code
to three places (ignoring !x86 arches).
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index d5ddc59..39eb435 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -170,7 +170,7 @@ static int prot_fault_translation = 0;
SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW,
&prot_fault_translation, 0, "Select signal to deliver on protection fault");
-extern char *syscallnames[];
+extern const char *syscallnames[];
/*
* Exception, fault, and trap interface to the FreeBSD kernel.
@@ -884,7 +884,7 @@ syscall(struct trapframe *frame)
struct proc *p;
struct syscall_args sa;
register_t orig_tf_rflags;
- int error;
+ int error, traced;
ksiginfo_t ksi;
PCPU_INC(cnt.v_syscall);
@@ -905,10 +905,13 @@ syscall(struct trapframe *frame)
cred_update_thread(td);
orig_tf_rflags = frame->tf_rflags;
if (p->p_flag & P_TRACED) {
+ traced = 1;
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
- }
+ } else
+ traced = 0;
error = fetch_syscall_args(td, &sa);
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
@@ -961,6 +964,11 @@ syscall(struct trapframe *frame)
#endif
}
retval:
+ if (traced) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCE;
+ PROC_UNLOCK(p);
+ }
cpu_set_syscall_retval(td, error);
/*
@@ -975,40 +983,5 @@ syscall(struct trapframe *frame)
trapsignal(td, &ksi);
}
- /*
- * Check for misbehavior.
- */
- WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- syscallnames[sa.code] : "???");
- KASSERT(td->td_critnest == 0,
- ("System call %s returning in a critical section",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- syscallnames[sa.code] : "???"));
- KASSERT(td->td_locks == 0,
- ("System call %s returning with %d locks held",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- syscallnames[sa.code] : "???", td->td_locks));
-
- /*
- * Handle reschedule and other end-of-syscall issues
- */
- userret(td, frame);
-
- CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
- td->td_proc->p_pid, td->td_name, sa.code);
-
-#ifdef KTRACE
- if (KTRPOINT(td, KTR_SYSRET))
- ktrsysret(sa.code, error, td->td_retval[0]);
-#endif
-
- /*
- * 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);
+ syscallret(td, error, sa.code, syscallnames);
}
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
index aa1ae6c..ad82210 100644
--- a/sys/amd64/ia32/ia32_syscall.c
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -170,7 +170,7 @@ ia32_syscall(struct trapframe *frame)
struct proc *p;
struct ia32_syscall_args sa;
register_t orig_tf_rflags;
- int error;
+ int error, traced;
ksiginfo_t ksi;
PCPU_INC(cnt.v_syscall);
@@ -184,10 +184,13 @@ ia32_syscall(struct trapframe *frame)
cred_update_thread(td);
orig_tf_rflags = frame->tf_rflags;
if (p->p_flag & P_TRACED) {
+ traced = 1;
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
- }
+ } else
+ traced = 0;
error = fetch_ia32_syscall_args(td, &sa);
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
@@ -218,6 +221,11 @@ ia32_syscall(struct trapframe *frame)
td->td_errno = error;
}
retval:
+ if (traced) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCE;
+ PROC_UNLOCK(p);
+ }
cpu_set_syscall_retval(td, error);
/*
@@ -232,44 +240,9 @@ ia32_syscall(struct trapframe *frame)
trapsignal(td, &ksi);
}
- /*
- * Check for misbehavior.
- */
- WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- freebsd32_syscallnames[sa.code] : "???");
- KASSERT(td->td_critnest == 0,
- ("System call %s returning in a critical section",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- freebsd32_syscallnames[sa.code] : "???"));
- KASSERT(td->td_locks == 0,
- ("System call %s returning with %d locks held",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- freebsd32_syscallnames[sa.code] : "???", td->td_locks));
-
- /*
- * Handle reschedule and other end-of-syscall issues
- */
- userret(td, frame);
-
- CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
- td->td_proc->p_pid, td->td_proc->p_comm, sa.code);
-#ifdef KTRACE
- if (KTRPOINT(td, KTR_SYSRET))
- ktrsysret(sa.code, error, td->td_retval[0]);
-#endif
-
- /*
- * 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);
+ syscallret(td, error, sa.code, freebsd32_syscallnames);
}
-
static void
ia32_syscall_enable(void *dummy)
{
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index a11daa6..35df54b 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -184,7 +184,7 @@ static int prot_fault_translation = 0;
SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW,
&prot_fault_translation, 0, "Select signal to deliver on protection fault");
-extern char *syscallnames[];
+extern const char *syscallnames[];
/*
* Exception, fault, and trap interface to the FreeBSD kernel.
@@ -1051,7 +1051,7 @@ syscall(struct trapframe *frame)
struct proc *p;
struct syscall_args sa;
register_t orig_tf_eflags;
- int error;
+ int error, traced;
ksiginfo_t ksi;
PCPU_INC(cnt.v_syscall);
@@ -1072,10 +1072,13 @@ syscall(struct trapframe *frame)
cred_update_thread(td);
orig_tf_eflags = frame->tf_eflags;
if (p->p_flag & P_TRACED) {
+ traced = 1;
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
- }
+ } else
+ traced = 0;
error = fetch_syscall_args(td, &sa);
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
@@ -1128,6 +1131,11 @@ syscall(struct trapframe *frame)
#endif
}
retval:
+ if (traced) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~TDB_SCE;
+ PROC_UNLOCK(p);
+ }
cpu_set_syscall_retval(td, error);
/*
@@ -1142,41 +1150,6 @@ syscall(struct trapframe *frame)
trapsignal(td, &ksi);
}
- /*
- * Check for misbehavior.
- */
- WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- syscallnames[sa.code] : "???");
- KASSERT(td->td_critnest == 0,
- ("System call %s returning in a critical section",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- syscallnames[sa.code] : "???"));
- KASSERT(td->td_locks == 0,
- ("System call %s returning with %d locks held",
- (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
- syscallnames[sa.code] : "???", td->td_locks));
-
- /*
- * Handle reschedule and other end-of-syscall issues
- */
- userret(td, frame);
-
- CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
- td->td_proc->p_pid, td->td_name, sa.code);
-
-#ifdef KTRACE
- if (KTRPOINT(td, KTR_SYSRET))
- ktrsysret(sa.code, error, td->td_retval[0]);
-#endif
-
- /*
- * 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);
+ syscallret(td, error, sa.code, syscallnames);
}
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index fc87d63..149e6df 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -871,6 +871,10 @@ exec_fail_dealloc:
free(imgp->freepath, M_TEMP);
if (error == 0) {
+ PROC_LOCK(p);
+ td->td_dbgflags |= TDB_EXEC;
+ PROC_UNLOCK(p);
+
/*
* Stop the process here if its stop event mask has
* the S_EXEC bit set.
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index 4d20ebd..ea6b0ae 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -58,9 +58,12 @@ __FBSDID("$FreeBSD$");
#include <sys/pmckern.h>
#include <sys/proc.h>
#include <sys/ktr.h>
+#include <sys/pioctl.h>
+#include <sys/ptrace.h>
#include <sys/resourcevar.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
+#include <sys/syscall.h>
#include <sys/systm.h>
#include <sys/vmmeter.h>
#ifdef KTRACE
@@ -253,3 +256,61 @@ ast(struct trapframe *framep)
userret(td, framep);
mtx_assert(&Giant, MA_NOTOWNED);
}
+
+void
+syscallret(struct thread *td, int error, u_int sa_code __unused,
+ const char *scnames[] __unused)
+{
+ struct proc *p;
+ int traced;
+
+ p = td->td_proc;
+
+ /*
+ * Check for misbehavior.
+ */
+ WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
+ (sa_code >= 0 && sa_code < SYS_MAXSYSCALL) ?
+ scnames[sa_code] : "???");
+ KASSERT(td->td_critnest == 0,
+ ("System call %s returning in a critical section",
+ (sa_code >= 0 && sa_code < SYS_MAXSYSCALL) ?
+ scnames[sa_code] : "???"));
+ KASSERT(td->td_locks == 0,
+ ("System call %s returning with %d locks held",
+ (sa_code >= 0 && sa_code < SYS_MAXSYSCALL) ?
+ scnames[sa_code] : "???", td->td_locks));
+
+ /*
+ * Handle reschedule and other end-of-syscall issues
+ */
+ userret(td, td->td_frame);
+
+ CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
+ td->td_proc->p_pid, td->td_name, sa_code);
+
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_SYSRET))
+ ktrsysret(sa_code, error, td->td_retval[0]);
+#endif
+
+ if (p->p_flag & P_TRACED) {
+ traced = 1;
+ PROC_LOCK(p);
+ td->td_dbgflags |= TDB_SCX;
+ PROC_UNLOCK(p);
+ } else
+ traced = 0;
+ /*
+ * 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 (traced || (td->td_dbgflags & TDB_EXEC) != 0) {
+ PROC_LOCK(p);
+ td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC);
+ PROC_UNLOCK(p);
+ }
+}
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index d8cc4f0..6decc02 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -1105,9 +1105,13 @@ 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;
+ if (td2->td_dbgflags & TDB_EXEC)
+ pl->pl_flags |= PL_FLAG_EXEC;
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..c2b9f4a 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -364,6 +364,9 @@ 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 */
+#define TDB_EXEC 0x00000020 /* TDB_SCX from exec(2) family */
/*
* "Private" flags kept in td_pflags:
@@ -837,6 +840,7 @@ void cpu_switch(struct thread *, struct thread *, struct mtx *);
void cpu_throw(struct thread *, struct thread *) __dead2;
void unsleep(struct thread *);
void userret(struct thread *, struct trapframe *);
+void syscallret(struct thread *, int, u_int, const char *[]);
void cpu_exit(struct thread *);
void exit1(struct thread *, int) __dead2;
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index b30447c..a6dbe2c 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -99,6 +99,9 @@ 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 */
+#define PL_FLAG_EXEC 0x10 /* exec(2) succeeded */
sigset_t pl_sigmask; /* LWP signal mask */
sigset_t pl_siglist; /* LWP pending signal */
};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20100514/1f1b8c08/attachment.pgp
More information about the freebsd-hackers
mailing list