Pull up following revision(s) (requested by kamil in ticket #1117):

sys/arch/sh3/include/ptrace.h: revision 1.19
	sys/arch/amd64/amd64/process_machdep.c: revision 1.48
	sys/arch/sh3/sh3/process_machdep.c: revision 1.23
	sys/arch/sh3/sh3/process_machdep.c: revision 1.24
	sys/arch/i386/i386/process_machdep.c: revision 1.95
	sys/arch/x86/x86/fpu.c (apply patch)
	sys/kern/sys_ptrace_common.c: revision 1.84
	sys/arch/powerpc/powerpc/process_machdep.c: revision 1.40
	sys/sys/ptrace.h: revision 1.71
	sys/arch/powerpc/powerpc/process_machdep.c: revision 1.41
	(all via patch, adapted)

Fix s87_tw reconstruction to correctly indicate register states

Fix the code reconstructing s87_tw (full tag word) from fx_sw (abridged
tag word) to correctly represent all register states.  The previous code
only distinguished between empty/non-empty registers, and assigned
'regular value' to all non-empty registers.  The new code explicitly
distinguishes the two other tag word values: empty and special.

Fix the machine-dependent ptrace register-related requests (e.g.
PT_GETXMMREGS, PT_GETXSTATE on x86) to correctly respect the LWP number
passed as the data argument.  Before this change, these requests
did not operate on the requested LWP of a multithreaded program.
This change required moving ptrace_update_lwp() out of unit scope,
and changing ptrace_machdep_dorequest() function to take a pointer
to pointer as the second argument, consistently with ptrace_regs().

I am planning to extend the ATF ptrace() register tests in the future
to check for regressions in multithreaded programs, as time permits.

Reviewed by kamil.

Add missing 'error' declaration
This commit is contained in:
martin 2020-10-18 18:42:10 +00:00
parent 1aa0bf3aca
commit 0953c39718
8 changed files with 369 additions and 21 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: process_machdep.c,v 1.43.2.1 2019/08/06 16:14:33 martin Exp $ */
/* $NetBSD: process_machdep.c,v 1.43.2.2 2020/10/18 18:42:10 martin Exp $ */
/*
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.43.2.1 2019/08/06 16:14:33 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.43.2.2 2020/10/18 18:42:10 martin Exp $");
#include "opt_xen.h"
#include <sys/param.h>
@ -367,6 +367,100 @@ ptrace_machdep_dorequest(
return 0;
}
static int
ptrace_update_lwp2(struct proc *t, struct lwp **lt, lwpid_t lid)
{
if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
return 0;
mutex_enter(t->p_lock);
lwp_delref2(*lt);
*lt = lwp_find(t, lid);
if (*lt == NULL) {
mutex_exit(t->p_lock);
return ESRCH;
}
if ((*lt)->l_flag & LW_SYSTEM) {
mutex_exit(t->p_lock);
*lt = NULL;
return EINVAL;
}
lwp_addref(*lt);
mutex_exit(t->p_lock);
return 0;
}
int
ptrace_machdep_dorequest2(
struct lwp *l,
struct lwp **lt,
int req,
void *addr,
int data
)
{
struct uio uio;
struct iovec iov;
struct vmspace *vm;
int error;
int write = 0;
switch (req) {
case PT_SETXSTATE:
write = 1;
/* FALLTHROUGH */
case PT_GETXSTATE:
/* write = 0 done above. */
if ((error = ptrace_update_lwp2((*lt)->l_proc, lt, data)) != 0)
return error;
if (!process_machdep_validxstate((*lt)->l_proc))
return EINVAL;
if (__predict_false(l->l_proc->p_flag & PK_32)) {
struct netbsd32_iovec user_iov;
if ((error = copyin(addr, &user_iov, sizeof(user_iov)))
!= 0)
return error;
iov.iov_base = NETBSD32PTR64(user_iov.iov_base);
iov.iov_len = user_iov.iov_len;
} else {
struct iovec user_iov;
if ((error = copyin(addr, &user_iov, sizeof(user_iov)))
!= 0)
return error;
iov.iov_base = user_iov.iov_base;
iov.iov_len = user_iov.iov_len;
}
error = proc_vmspace_getref(l->l_proc, &vm);
if (error)
return error;
if (iov.iov_len > sizeof(struct xstate))
iov.iov_len = sizeof(struct xstate);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = 0;
uio.uio_resid = iov.iov_len;
uio.uio_rw = write ? UIO_WRITE : UIO_READ;
uio.uio_vmspace = vm;
error = process_machdep_doxstate(l, *lt, &uio);
uvmspace_free(vm);
return error;
}
#ifdef DIAGNOSTIC
panic("ptrace_machdep: impossible");
#endif
return 0;
}
/*
* The following functions are used by both ptrace(2) and procfs.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: process_machdep.c,v 1.93.2.1 2019/08/06 16:20:19 martin Exp $ */
/* $NetBSD: process_machdep.c,v 1.93.2.2 2020/10/18 18:42:11 martin Exp $ */
/*-
* Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@ -75,7 +75,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.93.2.1 2019/08/06 16:20:19 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.93.2.2 2020/10/18 18:42:11 martin Exp $");
#include "opt_ptrace.h"
@ -347,6 +347,114 @@ ptrace_machdep_dorequest(
return 0;
}
static int
ptrace_update_lwp2(struct proc *t, struct lwp **lt, lwpid_t lid)
{
if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
return 0;
mutex_enter(t->p_lock);
lwp_delref2(*lt);
*lt = lwp_find(t, lid);
if (*lt == NULL) {
mutex_exit(t->p_lock);
return ESRCH;
}
if ((*lt)->l_flag & LW_SYSTEM) {
mutex_exit(t->p_lock);
*lt = NULL;
return EINVAL;
}
lwp_addref(*lt);
mutex_exit(t->p_lock);
return 0;
}
int
ptrace_machdep_dorequest2(
struct lwp *l,
struct lwp **lt,
int req,
void *addr,
int data
)
{
struct uio uio;
struct iovec iov;
struct iovec user_iov;
struct vmspace *vm;
int error;
int write = 0;
switch (req) {
case PT_SETXMMREGS:
write = 1;
/* FALLTHROUGH */
case PT_GETXMMREGS:
/* write = 0 done above. */
if ((error = ptrace_update_lwp2((*lt)->l_proc, lt, data)) != 0)
return error;
if (!process_machdep_validxmmregs((*lt)->l_proc))
return (EINVAL);
error = proc_vmspace_getref(l->l_proc, &vm);
if (error) {
return error;
}
iov.iov_base = addr;
iov.iov_len = sizeof(struct xmmregs);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = 0;
uio.uio_resid = sizeof(struct xmmregs);
uio.uio_rw = write ? UIO_WRITE : UIO_READ;
uio.uio_vmspace = vm;
error = process_machdep_doxmmregs(l, *lt, &uio);
uvmspace_free(vm);
return error;
case PT_SETXSTATE:
write = 1;
/* FALLTHROUGH */
case PT_GETXSTATE:
/* write = 0 done above. */
if ((error = ptrace_update_lwp2((*lt)->l_proc, lt, data)) != 0)
return error;
if (!process_machdep_validxstate((*lt)->l_proc))
return EINVAL;
if ((error = copyin(addr, &user_iov, sizeof(user_iov))) != 0)
return error;
error = proc_vmspace_getref(l->l_proc, &vm);
if (error) {
return error;
}
iov.iov_base = user_iov.iov_base;
iov.iov_len = user_iov.iov_len;
if (iov.iov_len > sizeof(struct xstate))
iov.iov_len = sizeof(struct xstate);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = 0;
uio.uio_resid = iov.iov_len;
uio.uio_rw = write ? UIO_WRITE : UIO_READ;
uio.uio_vmspace = vm;
error = process_machdep_doxstate(l, *lt, &uio);
uvmspace_free(vm);
return error;
}
#ifdef DIAGNOSTIC
panic("ptrace_machdep: impossible");
#endif
return 0;
}
/*
* The following functions are used by both ptrace(2) and procfs.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: process_machdep.c,v 1.38 2017/03/16 16:13:20 chs Exp $ */
/* $NetBSD: process_machdep.c,v 1.38.18.1 2020/10/18 18:42:11 martin Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.38 2017/03/16 16:13:20 chs Exp $");
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.38.18.1 2020/10/18 18:42:11 martin Exp $");
#include "opt_altivec.h"
@ -219,6 +219,69 @@ ptrace_machdep_dorequest(struct lwp *l, struct lwp *lt,
return (0);
}
static int
ptrace_update_lwp2(struct proc *t, struct lwp **lt, lwpid_t lid)
{
if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
return 0;
mutex_enter(t->p_lock);
lwp_delref2(*lt);
*lt = lwp_find(t, lid);
if (*lt == NULL) {
mutex_exit(t->p_lock);
return ESRCH;
}
if ((*lt)->l_flag & LW_SYSTEM) {
mutex_exit(t->p_lock);
*lt = NULL;
return EINVAL;
}
lwp_addref(*lt);
mutex_exit(t->p_lock);
return 0;
}
int
ptrace_machdep_dorequest2(struct lwp *l, struct lwp **lt,
int req, void *addr, int data)
{
struct uio uio;
struct iovec iov;
int write = 0, error;
switch (req) {
case PT_SETVECREGS:
write = 1;
case PT_GETVECREGS:
/* write = 0 done above. */
if ((error = ptrace_update_lwp2((*lt)->l_proc, lt, data)) != 0)
return error;
if (!process_machdep_validvecregs((*lt)->l_proc))
return (EINVAL);
iov.iov_base = addr;
iov.iov_len = sizeof(struct vreg);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = 0;
uio.uio_resid = sizeof(struct vreg);
uio.uio_rw = write ? UIO_WRITE : UIO_READ;
uio.uio_vmspace = l->l_proc->p_vmspace;
return process_machdep_dovecregs(l, *lt, &uio);
}
#ifdef DIAGNOSTIC
panic("ptrace_machdep: impossible");
#endif
return (0);
}
/*
* The following functions are used by both ptrace(2) and procfs.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: ptrace.h,v 1.15 2019/06/18 21:18:13 kamil Exp $ */
/* $NetBSD: ptrace.h,v 1.15.2.1 2020/10/18 18:42:10 martin Exp $ */
/*
* Copyright (c) 1993 Christopher G. Demetriou
@ -94,6 +94,7 @@
#ifdef __HAVE_PTRACE_MACHDEP
int ptrace_machdep_dorequest(struct lwp *, struct lwp *, int, void *, int);
int ptrace_machdep_dorequest2(struct lwp *, struct lwp **, int, void *, int);
#endif
#endif /* _KERNEL */

View File

@ -1,4 +1,4 @@
/* $NetBSD: process_machdep.c,v 1.21 2016/11/02 00:11:59 pgoyette Exp $ */
/* $NetBSD: process_machdep.c,v 1.21.20.1 2020/10/18 18:42:11 martin Exp $ */
/*
* Copyright (c) 1993 The Regents of the University of California.
@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.21 2016/11/02 00:11:59 pgoyette Exp $");
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.21.20.1 2020/10/18 18:42:11 martin Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -221,6 +221,69 @@ ptrace_machdep_dorequest(struct lwp *l, struct lwp *lt,
}
}
#ifdef COMPAT_40
static int
ptrace_update_lwp2(struct proc *t, struct lwp **lt, lwpid_t lid)
{
if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
return 0;
mutex_enter(t->p_lock);
lwp_delref2(*lt);
*lt = lwp_find(t, lid);
if (*lt == NULL) {
mutex_exit(t->p_lock);
return ESRCH;
}
if ((*lt)->l_flag & LW_SYSTEM) {
mutex_exit(t->p_lock);
*lt = NULL;
return EINVAL;
}
lwp_addref(*lt);
mutex_exit(t->p_lock);
return 0;
}
#endif
int
ptrace_machdep_dorequest2(struct lwp *l, struct lwp **lt,
int req, void *addr, int data)
{
struct uio uio;
struct iovec iov;
int write = 0, error;
switch (req) {
default:
return EINVAL;
#ifdef COMPAT_40
case PT___SETREGS40:
write = 1;
/* FALLTHROUGH*/
case PT___GETREGS40:
if ((error = ptrace_update_lwp2((*lt)->l_proc, lt, data)) != 0)
return error;
if (!process_validregs(*lt))
return EINVAL;
iov.iov_base = addr;
iov.iov_len = sizeof(struct __reg40);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = 0;
uio.uio_resid = sizeof(struct __reg40);
uio.uio_rw = write ? UIO_WRITE : UIO_READ;
uio.uio_vmspace = l->l_proc->p_vmspace;
return process_machdep_doregs40(l, *lt, &uio);
#endif /* COMPAT_40 */
}
}
#ifdef COMPAT_40

View File

@ -1,4 +1,4 @@
/* $NetBSD: fpu.c,v 1.55 2019/07/05 17:08:56 maxv Exp $ */
/* $NetBSD: fpu.c,v 1.55.2.1 2020/10/18 18:42:10 martin Exp $ */
/*
* Copyright (c) 2008 The NetBSD Foundation, Inc. All
@ -96,7 +96,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.55 2019/07/05 17:08:56 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.55.2.1 2020/10/18 18:42:10 martin Exp $");
#include "opt_multiprocessor.h"
@ -710,7 +710,7 @@ fpu_save_area_fork(struct pcb *pcb2, const struct pcb *pcb1)
static void
process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87)
{
unsigned int tag, ab_tag;
unsigned int tag, ab_tag, st;
const struct fpaccfx *fx_reg;
struct fpacc87 *s87_reg;
int i;
@ -765,12 +765,28 @@ process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87)
return;
}
/* For ST(i), i = fpu_reg - top, we start with fpu_reg=7. */
st = 7 - ((sxmm->fx_sw >> 11) & 7);
tag = 0;
/* Separate bits of abridged tag word with zeros */
for (i = 0x80; i != 0; tag <<= 1, i >>= 1)
tag |= ab_tag & i;
/* Replicate and invert so that 0 => 0b11 and 1 => 0b00 */
s87->s87_tw = (tag | tag >> 1) ^ 0xffff;
for (i = 0x80; i != 0; i >>= 1) {
tag <<= 2;
if (ab_tag & i) {
unsigned int exp;
/* Non-empty - we need to check ST(i) */
fx_reg = &sxmm->fx_87_ac[st];
exp = fx_reg->r.f87_exp_sign & 0x7fff;
if (exp == 0) {
if (fx_reg->r.f87_mantissa == 0)
tag |= 1; /* Zero */
else
tag |= 2; /* Denormal */
} else if (exp == 0x7fff)
tag |= 2; /* Infinity or NaN */
} else
tag |= 3; /* Empty */
st = (st - 1) & 7;
}
s87->s87_tw = tag;
}
static void

View File

@ -1,4 +1,4 @@
/* $NetBSD: sys_ptrace_common.c,v 1.58.2.12 2019/11/24 08:16:52 martin Exp $ */
/* $NetBSD: sys_ptrace_common.c,v 1.58.2.13 2020/10/18 18:42:11 martin Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@ -118,7 +118,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.58.2.12 2019/11/24 08:16:52 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.58.2.13 2020/10/18 18:42:11 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@ -1432,7 +1432,7 @@ do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid,
#ifdef __HAVE_PTRACE_MACHDEP
PTRACE_MACHDEP_REQUEST_CASES
error = ptrace_machdep_dorequest(l, lt, req, addr, data);
error = ptrace_machdep_dorequest2(l, &lt, req, addr, data);
break;
#endif
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ptrace.h,v 1.65.2.1 2019/10/15 19:11:02 martin Exp $ */
/* $NetBSD: ptrace.h,v 1.65.2.2 2020/10/18 18:42:11 martin Exp $ */
/*-
* Copyright (c) 1984, 1993
@ -281,6 +281,9 @@ int process_write_regs(struct lwp *, const struct reg *);
int ptrace_machdep_dorequest(struct lwp *, struct lwp *, int,
void *, int);
int ptrace_machdep_dorequest2(struct lwp *, struct lwp **, int,
void *, int);
#ifndef FIX_SSTEP
#define FIX_SSTEP(p)
#endif