From b43ce76c770f4c3728b6918f7d4cf175296753ff Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 12 Jun 2017 21:15:43 +0000 Subject: [PATCH] Add ptrace(PT_GET_SC_ARGS) command to return debuggee' current syscall arguments. Reviewed by: jhb (previous version) Sponsored by: The FreeBSD Foundation MFC after: 3 weeks Differential revision: https://reviews.freebsd.org/D11080 --- lib/libc/sys/ptrace.2 | 22 +++++++++++++++++++++- sys/kern/sys_process.c | 29 +++++++++++++++++++++++++++++ sys/sys/ptrace.h | 2 ++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2 index 8eb26dd9279b..b8968ebaa3da 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 August 29, 2016 +.Dd June 11, 2017 .Dt PTRACE 2 .Os .Sh NAME @@ -643,6 +643,26 @@ and .Fa data arguments are used the same as for .Dv PT_CONTINUE. +.It Dv PT_GET_SC_ARGS +For the thread which is stopped in either +.Dv PL_FLAG_SCE +or +.Dv PL_FLAG_SCX +state, that is, on entry or exit to a syscall, +this request fetches the syscall arguments. +.Pp +The arguments are copied out into the buffer pointed to by the +.Fa addr +pointer, sequentially. +Each syscall argument is stored as the machine word. +Kernel copies out as many arguments as the syscall accepts, +see the +.Va pl_syscall_narg +member of the +.Vt struct ptrace_lwpinfo , +but not more than the +.Fa data +bytes in total are copied. .It Dv PT_FOLLOW_FORK This request controls tracing for new child processes of a traced process. If diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index e18b7e6a2971..e9c57a7a57e5 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -586,6 +586,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap) struct ptrace_lwpinfo32 pl32; struct ptrace_vm_entry32 pve32; #endif + char args[nitems(td->td_sa.args) * sizeof(register_t)]; int ptevents; } r; void *addr; @@ -606,6 +607,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap) case PT_GETFPREGS: case PT_GETDBREGS: case PT_LWPINFO: + case PT_GET_SC_ARGS: break; case PT_SETREGS: error = COPYIN(uap->addr, &r.reg, sizeof r.reg); @@ -663,6 +665,10 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap) /* NB: The size in uap->data is validated in kern_ptrace(). */ error = copyout(&r.pl, uap->addr, uap->data); break; + case PT_GET_SC_ARGS: + error = copyout(r.args, uap->addr, MIN(uap->data, + sizeof(r.args))); + break; } return (error); @@ -739,6 +745,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) case PT_GET_EVENT_MASK: case PT_SET_EVENT_MASK: case PT_DETACH: + case PT_GET_SC_ARGS: sx_xlock(&proctree_lock); proctree_locked = 1; break; @@ -1009,6 +1016,28 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) p->p_pid, p->p_ptevents, tmp); p->p_ptevents = tmp; break; + + case PT_GET_SC_ARGS: + CTR1(KTR_PTRACE, "PT_GET_SC_ARGS: pid %d", p->p_pid); + if ((td2->td_dbgflags & (TDB_SCE | TDB_SCX)) == 0 +#ifdef COMPAT_FREEBSD32 + || (wrap32 && !safe) +#endif + ) { + error = EINVAL; + break; + } + bzero(addr, sizeof(td2->td_sa.args)); +#ifdef COMPAT_FREEBSD32 + if (wrap32) + for (num = 0; num < nitems(td2->td_sa.args); num++) + ((uint32_t *)addr)[num] = (uint32_t) + td2->td_sa.args[num]; + else +#endif + bcopy(td2->td_sa.args, addr, td2->td_sa.narg * + sizeof(register_t)); + break; case PT_STEP: case PT_CONTINUE: diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 2fa7c12b0277..903d9d83ee13 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -69,6 +69,8 @@ #define PT_GET_EVENT_MASK 25 /* get mask of optional events */ #define PT_SET_EVENT_MASK 26 /* set mask of optional events */ +#define PT_GET_SC_ARGS 27 /* fetch syscall args */ + #define PT_GETREGS 33 /* get general-purpose registers */ #define PT_SETREGS 34 /* set general-purpose registers */ #define PT_GETFPREGS 35 /* get floating-point registers */