Add ptrace op PT_GET_SC_RET.
This ptrace operation returns a structure containing the error and return values from the current system call. It is only valid when a thread is stopped during a system call exit (PL_FLAG_SCX is set). The sr_error member holds the error value from the system call. Note that this error value is the native FreeBSD error value that has _not_ been translated to an ABI-specific error value similar to the values logged to ktrace. If sr_error is zero, then the return values of the system call will be set in sr_retval[0] and sr_retval[1]. Reviewed by: kib MFC after: 1 month Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D20901
This commit is contained in:
parent
0cc1098a1a
commit
32451fb9fc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=350017
@ -2,7 +2,7 @@
|
|||||||
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
|
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" This file is in the public domain.
|
.\" This file is in the public domain.
|
||||||
.Dd June 2, 2018
|
.Dd July 15, 2019
|
||||||
.Dt PTRACE 2
|
.Dt PTRACE 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -664,6 +664,52 @@ member of the
|
|||||||
but not more than the
|
but not more than the
|
||||||
.Fa data
|
.Fa data
|
||||||
bytes in total are copied.
|
bytes in total are copied.
|
||||||
|
.It Dv PT_GET_SC_RET
|
||||||
|
Fetch the system call return values on exit from a syscall.
|
||||||
|
This request is only valid for threads stopped in a syscall
|
||||||
|
exit (the
|
||||||
|
.Dv PL_FLAG_SCX
|
||||||
|
state).
|
||||||
|
The
|
||||||
|
.Fa addr
|
||||||
|
argument specifies a pointer to a
|
||||||
|
.Vt "struct ptrace_sc_ret" ,
|
||||||
|
which is defined as follows:
|
||||||
|
.Bd -literal
|
||||||
|
struct ptrace_sc_ret {
|
||||||
|
register_t sr_retval[2];
|
||||||
|
int sr_error;
|
||||||
|
};
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fa data
|
||||||
|
argument is set to the size of the structure.
|
||||||
|
.Pp
|
||||||
|
If the system call completed successfully,
|
||||||
|
.Va sr_error
|
||||||
|
is set to zero and the return values of the system call are saved in
|
||||||
|
.Va sr_retval .
|
||||||
|
If the system call failed to execute,
|
||||||
|
.Va sr_error
|
||||||
|
field is set to a positive
|
||||||
|
.Xr errno 2
|
||||||
|
value.
|
||||||
|
If the system call completed in an unusual fashion,
|
||||||
|
.Va sr_error
|
||||||
|
is set to a negative value:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width Dv EJUSTRETURN -compact
|
||||||
|
.It Dv ERESTART
|
||||||
|
System call will be restarted.
|
||||||
|
.It Dv EJUSTRETURN
|
||||||
|
System call completed sucessfully but did not set a return value
|
||||||
|
.Po for example,
|
||||||
|
.Xr setcontext 2
|
||||||
|
and
|
||||||
|
.Xr sigreturn 2
|
||||||
|
.Pc .
|
||||||
|
.El
|
||||||
.It Dv PT_FOLLOW_FORK
|
.It Dv PT_FOLLOW_FORK
|
||||||
This request controls tracing for new child processes of a traced process.
|
This request controls tracing for new child processes of a traced process.
|
||||||
If
|
If
|
||||||
|
@ -76,6 +76,11 @@ struct ptrace_io_desc32 {
|
|||||||
uint32_t piod_len;
|
uint32_t piod_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ptrace_sc_ret32 {
|
||||||
|
uint32_t sr_retval[2];
|
||||||
|
int sr_error;
|
||||||
|
};
|
||||||
|
|
||||||
struct ptrace_vm_entry32 {
|
struct ptrace_vm_entry32 {
|
||||||
int pve_entry;
|
int pve_entry;
|
||||||
int pve_timestamp;
|
int pve_timestamp;
|
||||||
@ -518,6 +523,17 @@ ptrace_lwpinfo_to32(const struct ptrace_lwpinfo *pl,
|
|||||||
pl32->pl_syscall_code = pl->pl_syscall_code;
|
pl32->pl_syscall_code = pl->pl_syscall_code;
|
||||||
pl32->pl_syscall_narg = pl->pl_syscall_narg;
|
pl32->pl_syscall_narg = pl->pl_syscall_narg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ptrace_sc_ret_to32(const struct ptrace_sc_ret *psr,
|
||||||
|
struct ptrace_sc_ret32 *psr32)
|
||||||
|
{
|
||||||
|
|
||||||
|
bzero(psr32, sizeof(*psr32));
|
||||||
|
psr32->sr_retval[0] = psr->sr_retval[0];
|
||||||
|
psr32->sr_retval[1] = psr->sr_retval[1];
|
||||||
|
psr32->sr_error = psr->sr_error;
|
||||||
|
}
|
||||||
#endif /* COMPAT_FREEBSD32 */
|
#endif /* COMPAT_FREEBSD32 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -580,6 +596,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
|
|||||||
struct ptrace_vm_entry32 pve32;
|
struct ptrace_vm_entry32 pve32;
|
||||||
#endif
|
#endif
|
||||||
char args[sizeof(td->td_sa.args)];
|
char args[sizeof(td->td_sa.args)];
|
||||||
|
struct ptrace_sc_ret psr;
|
||||||
int ptevents;
|
int ptevents;
|
||||||
} r;
|
} r;
|
||||||
void *addr;
|
void *addr;
|
||||||
@ -598,6 +615,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
|
|||||||
case PT_GET_EVENT_MASK:
|
case PT_GET_EVENT_MASK:
|
||||||
case PT_LWPINFO:
|
case PT_LWPINFO:
|
||||||
case PT_GET_SC_ARGS:
|
case PT_GET_SC_ARGS:
|
||||||
|
case PT_GET_SC_RET:
|
||||||
break;
|
break;
|
||||||
case PT_GETREGS:
|
case PT_GETREGS:
|
||||||
BZERO(&r.reg, sizeof r.reg);
|
BZERO(&r.reg, sizeof r.reg);
|
||||||
@ -668,6 +686,10 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
|
|||||||
error = copyout(r.args, uap->addr, MIN(uap->data,
|
error = copyout(r.args, uap->addr, MIN(uap->data,
|
||||||
sizeof(r.args)));
|
sizeof(r.args)));
|
||||||
break;
|
break;
|
||||||
|
case PT_GET_SC_RET:
|
||||||
|
error = copyout(&r.psr, uap->addr, MIN(uap->data,
|
||||||
|
sizeof(r.psr)));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
@ -719,6 +741,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
|||||||
struct thread *td2 = NULL, *td3;
|
struct thread *td2 = NULL, *td3;
|
||||||
struct ptrace_io_desc *piod = NULL;
|
struct ptrace_io_desc *piod = NULL;
|
||||||
struct ptrace_lwpinfo *pl;
|
struct ptrace_lwpinfo *pl;
|
||||||
|
struct ptrace_sc_ret *psr;
|
||||||
int error, num, tmp;
|
int error, num, tmp;
|
||||||
int proctree_locked = 0;
|
int proctree_locked = 0;
|
||||||
lwpid_t tid = 0, *buf;
|
lwpid_t tid = 0, *buf;
|
||||||
@ -726,7 +749,11 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
|||||||
int wrap32 = 0, safe = 0;
|
int wrap32 = 0, safe = 0;
|
||||||
struct ptrace_io_desc32 *piod32 = NULL;
|
struct ptrace_io_desc32 *piod32 = NULL;
|
||||||
struct ptrace_lwpinfo32 *pl32 = NULL;
|
struct ptrace_lwpinfo32 *pl32 = NULL;
|
||||||
struct ptrace_lwpinfo plr;
|
struct ptrace_sc_ret32 *psr32 = NULL;
|
||||||
|
union {
|
||||||
|
struct ptrace_lwpinfo pl;
|
||||||
|
struct ptrace_sc_ret psr;
|
||||||
|
} r;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
curp = td->td_proc;
|
curp = td->td_proc;
|
||||||
@ -1050,6 +1077,38 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
|||||||
sizeof(register_t));
|
sizeof(register_t));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PT_GET_SC_RET:
|
||||||
|
if ((td2->td_dbgflags & (TDB_SCX)) == 0
|
||||||
|
#ifdef COMPAT_FREEBSD32
|
||||||
|
|| (wrap32 && !safe)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef COMPAT_FREEBSD32
|
||||||
|
if (wrap32) {
|
||||||
|
psr = &r.psr;
|
||||||
|
psr32 = addr;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
psr = addr;
|
||||||
|
bzero(psr, sizeof(*psr));
|
||||||
|
psr->sr_error = td2->td_errno;
|
||||||
|
if (psr->sr_error == 0) {
|
||||||
|
psr->sr_retval[0] = td2->td_retval[0];
|
||||||
|
psr->sr_retval[1] = td2->td_retval[1];
|
||||||
|
}
|
||||||
|
#ifdef COMPAT_FREEBSD32
|
||||||
|
if (wrap32)
|
||||||
|
ptrace_sc_ret_to32(psr, psr32);
|
||||||
|
#endif
|
||||||
|
CTR4(KTR_PTRACE,
|
||||||
|
"PT_GET_SC_RET: pid %d error %d retval %#lx,%#lx",
|
||||||
|
p->p_pid, psr->sr_error, psr->sr_retval[0],
|
||||||
|
psr->sr_retval[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
case PT_STEP:
|
case PT_STEP:
|
||||||
case PT_CONTINUE:
|
case PT_CONTINUE:
|
||||||
case PT_TO_SCE:
|
case PT_TO_SCE:
|
||||||
@ -1335,7 +1394,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
|||||||
}
|
}
|
||||||
#ifdef COMPAT_FREEBSD32
|
#ifdef COMPAT_FREEBSD32
|
||||||
if (wrap32) {
|
if (wrap32) {
|
||||||
pl = &plr;
|
pl = &r.pl;
|
||||||
pl32 = addr;
|
pl32 = addr;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
@ -72,6 +72,7 @@
|
|||||||
#define PT_SET_EVENT_MASK 26 /* set 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_GET_SC_ARGS 27 /* fetch syscall args */
|
||||||
|
#define PT_GET_SC_RET 28 /* fetch syscall results */
|
||||||
|
|
||||||
#define PT_GETREGS 33 /* get general-purpose registers */
|
#define PT_GETREGS 33 /* get general-purpose registers */
|
||||||
#define PT_SETREGS 34 /* set general-purpose registers */
|
#define PT_SETREGS 34 /* set general-purpose registers */
|
||||||
@ -155,6 +156,12 @@ struct ptrace_lwpinfo32 {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Argument structure for PT_GET_SC_RET. */
|
||||||
|
struct ptrace_sc_ret {
|
||||||
|
register_t sr_retval[2]; /* Only valid if sr_error == 0. */
|
||||||
|
int sr_error;
|
||||||
|
};
|
||||||
|
|
||||||
/* Argument structure for PT_VM_ENTRY. */
|
/* Argument structure for PT_VM_ENTRY. */
|
||||||
struct ptrace_vm_entry {
|
struct ptrace_vm_entry {
|
||||||
int pve_entry; /* Entry number used for iteration. */
|
int pve_entry; /* Entry number used for iteration. */
|
||||||
|
@ -3905,12 +3905,13 @@ ATF_TC_BODY(ptrace__PT_LWPINFO_stale_siginfo, tc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A simple test of PT_GET_SC_ARGS.
|
* A simple test of PT_GET_SC_ARGS and PT_GET_SC_RET.
|
||||||
*/
|
*/
|
||||||
ATF_TC_WITHOUT_HEAD(ptrace__syscall_args);
|
ATF_TC_WITHOUT_HEAD(ptrace__syscall_args);
|
||||||
ATF_TC_BODY(ptrace__syscall_args, tc)
|
ATF_TC_BODY(ptrace__syscall_args, tc)
|
||||||
{
|
{
|
||||||
struct ptrace_lwpinfo pl;
|
struct ptrace_lwpinfo pl;
|
||||||
|
struct ptrace_sc_ret psr;
|
||||||
pid_t fpid, wpid;
|
pid_t fpid, wpid;
|
||||||
register_t args[2];
|
register_t args[2];
|
||||||
int events, status;
|
int events, status;
|
||||||
@ -3919,6 +3920,7 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
|
|||||||
if (fpid == 0) {
|
if (fpid == 0) {
|
||||||
trace_me();
|
trace_me();
|
||||||
kill(getpid(), 0);
|
kill(getpid(), 0);
|
||||||
|
close(3);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3930,9 +3932,9 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Continue the process ignoring the signal, but enabling
|
* Continue the process ignoring the signal, but enabling
|
||||||
* syscall entry traps.
|
* syscall traps.
|
||||||
*/
|
*/
|
||||||
ATF_REQUIRE(ptrace(PT_TO_SCE, fpid, (caddr_t)1, 0) == 0);
|
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The next stop should be the syscall entry from getpid().
|
* The next stop should be the syscall entry from getpid().
|
||||||
@ -3948,6 +3950,25 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
|
|||||||
|
|
||||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
|
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The next stop should be the syscall exit from getpid().
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
ATF_REQUIRE(pl.pl_syscall_code == SYS_getpid);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
|
||||||
|
sizeof(psr)) != -1);
|
||||||
|
ATF_REQUIRE(psr.sr_error == 0);
|
||||||
|
ATF_REQUIRE(psr.sr_retval[0] == wpid);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The next stop should be the syscall entry from kill().
|
* The next stop should be the syscall entry from kill().
|
||||||
*/
|
*/
|
||||||
@ -3966,6 +3987,61 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
|
|||||||
ATF_REQUIRE(args[0] == wpid);
|
ATF_REQUIRE(args[0] == wpid);
|
||||||
ATF_REQUIRE(args[1] == 0);
|
ATF_REQUIRE(args[1] == 0);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The next stop should be the syscall exit from kill().
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
ATF_REQUIRE(pl.pl_syscall_code == SYS_kill);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
|
||||||
|
sizeof(psr)) != -1);
|
||||||
|
ATF_REQUIRE(psr.sr_error == 0);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The next stop should be the syscall entry from close().
|
||||||
|
*/
|
||||||
|
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_SCE);
|
||||||
|
ATF_REQUIRE(pl.pl_syscall_code == SYS_close);
|
||||||
|
ATF_REQUIRE(pl.pl_syscall_narg == 1);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args,
|
||||||
|
sizeof(args)) != -1);
|
||||||
|
ATF_REQUIRE(args[0] == 3);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The next stop should be the syscall exit from close().
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
ATF_REQUIRE(pl.pl_syscall_code == SYS_close);
|
||||||
|
|
||||||
|
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
|
||||||
|
sizeof(psr)) != -1);
|
||||||
|
ATF_REQUIRE(psr.sr_error == EBADF);
|
||||||
|
|
||||||
/* Disable syscall tracing and continue the child to let it exit. */
|
/* Disable syscall tracing and continue the child to let it exit. */
|
||||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
|
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
|
||||||
sizeof(events)) == 0);
|
sizeof(events)) == 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user