Module Name: src Committed By: christos Date: Thu Dec 7 15:21:34 UTC 2017
Modified Files: src/sys/kern: sys_ptrace_common.c Log Message: Make {s,g}et{db,fp,}regs work again for PK_32 processes XXX: pullup-8 To generate a diff of this commit: cvs rdiff -u -r1.23 -r1.24 src/sys/kern/sys_ptrace_common.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/sys_ptrace_common.c diff -u src/sys/kern/sys_ptrace_common.c:1.23 src/sys/kern/sys_ptrace_common.c:1.24 --- src/sys/kern/sys_ptrace_common.c:1.23 Sun Aug 27 20:46:07 2017 +++ src/sys/kern/sys_ptrace_common.c Thu Dec 7 10:21:34 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_ptrace_common.c,v 1.23 2017/08/28 00:46:07 kamil Exp $ */ +/* $NetBSD: sys_ptrace_common.c,v 1.24 2017/12/07 15:21:34 christos Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -118,12 +118,13 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.23 2017/08/28 00:46:07 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.24 2017/12/07 15:21:34 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_ptrace.h" #include "opt_ktrace.h" #include "opt_pax.h" +#include "opt_compat_netbsd32.h" #endif #include <sys/param.h> @@ -1320,40 +1321,69 @@ do_ptrace(struct ptrace_methods *ptm, st return error; } -int -process_doregs(struct lwp *curl /*tracer*/, - struct lwp *l /*traced*/, - struct uio *uio) +typedef int (*regfunc_t)(struct lwp *, void *); + +#if defined(PT_GETDBREGS) || defined(PT_SETDBREGS) || \ + defined(PT_GETFPREGS) || defined(PT_SETFPREGS) || \ + defined(PT_GETREGS) || defined(PT_SETREGS) +static int +proc_regio(struct lwp *l, struct uio *uio, size_t kl, regfunc_t r, regfunc_t w) { -#if defined(PT_GETREGS) || defined(PT_SETREGS) + char buf[1024]; int error; - struct reg r; char *kv; - int kl; - if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r)) - return EINVAL; + if (kl > sizeof(buf)) + return E2BIG; - kl = sizeof(r); - kv = (char *)&r; + if (uio->uio_offset < 0 || uio->uio_offset > (off_t)kl) + return EINVAL; - kv += uio->uio_offset; + kv = buf + uio->uio_offset; kl -= uio->uio_offset; - if ((size_t)kl > uio->uio_resid) + + if (kl > uio->uio_resid) kl = uio->uio_resid; - error = process_read_regs(l, &r); + error = (*r)(l, buf); if (error == 0) error = uiomove(kv, kl, uio); if (error == 0 && uio->uio_rw == UIO_WRITE) { if (l->l_stat != LSSTOP) error = EBUSY; else - error = process_write_regs(l, &r); + error = (*w)(l, buf); } uio->uio_offset = 0; return error; +} +#endif + +int +process_doregs(struct lwp *curl /*tracer*/, + struct lwp *l /*traced*/, + struct uio *uio) +{ +#if defined(PT_GETREGS) || defined(PT_SETREGS) + size_t s; + regfunc_t r, w; + +#ifdef COMPAT_NETBSD32 + const bool pk32 = (l->l_proc->p_flag & PK_32) != 0; + + if (__predict_false(pk32)) { + s = sizeof(struct reg32); + r = (regfunc_t)process_read_regs32; + w = (regfunc_t)process_write_regs32; + } else +#endif + { + s = sizeof(struct reg); + r = (regfunc_t)process_read_regs; + w = (regfunc_t)process_write_regs; + } + return proc_regio(l, uio, s, r, w); #else return EINVAL; #endif @@ -1376,33 +1406,24 @@ process_dofpregs(struct lwp *curl /*trac struct uio *uio) { #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) - int error; - struct fpreg r; - char *kv; - size_t kl; + size_t s; + regfunc_t r, w; - if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r)) - return EINVAL; - - kl = sizeof(r); - kv = (char *)&r; +#ifdef COMPAT_NETBSD32 + const bool pk32 = (l->l_proc->p_flag & PK_32) != 0; - kv += uio->uio_offset; - kl -= uio->uio_offset; - if (kl > uio->uio_resid) - kl = uio->uio_resid; - - error = process_read_fpregs(l, &r, &kl); - if (error == 0) - error = uiomove(kv, kl, uio); - if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (l->l_stat != LSSTOP) - error = EBUSY; - else - error = process_write_fpregs(l, &r, kl); + if (__predict_false(pk32)) { + s = sizeof(struct fpreg32); + r = (regfunc_t)process_read_fpregs32; + w = (regfunc_t)process_write_fpregs32; + } else +#endif + { + s = sizeof(struct fpreg); + r = (regfunc_t)process_read_fpregs; + w = (regfunc_t)process_write_fpregs; } - uio->uio_offset = 0; - return error; + return proc_regio(l, uio, s, r, w); #else return EINVAL; #endif @@ -1425,33 +1446,24 @@ process_dodbregs(struct lwp *curl /*trac struct uio *uio) { #if defined(PT_GETDBREGS) || defined(PT_SETDBREGS) - int error; - struct dbreg r; - char *kv; - size_t kl; + size_t s; + regfunc_t r, w; - if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r)) - return EINVAL; +#ifdef COMPAT_NETBSD32 + const bool pk32 = (l->l_proc->p_flag & PK_32) != 0; - kl = sizeof(r); - kv = (char *)&r; - - kv += uio->uio_offset; - kl -= uio->uio_offset; - if (kl > uio->uio_resid) - kl = uio->uio_resid; - - error = process_read_dbregs(l, &r, &kl); - if (error == 0) - error = uiomove(kv, kl, uio); - if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (l->l_stat != LSSTOP) - error = EBUSY; - else - error = process_write_dbregs(l, &r, kl); + if (__predict_false(pk32)) { + s = sizeof(struct dbreg32); + r = (regfunc_t)process_read_dbregs32; + w = (regfunc_t)process_write_dbregs32; + } else +#endif + { + s = sizeof(struct dbreg); + r = (regfunc_t)process_read_dbregs; + w = (regfunc_t)process_write_dbregs; } - uio->uio_offset = 0; - return error; + return proc_regio(l, uio, s, r, w); #else return EINVAL; #endif