From owner-p4-projects@FreeBSD.ORG Mon Aug 7 22:01:56 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id D6AE516A4DF; Mon, 7 Aug 2006 22:01:55 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id AF0CF16A4DE for ; Mon, 7 Aug 2006 22:01:55 +0000 (UTC) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id D33F943D58 for ; Mon, 7 Aug 2006 22:01:54 +0000 (GMT) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k77M1sGc074126 for ; Mon, 7 Aug 2006 22:01:54 GMT (envelope-from marcel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k77M1rGJ074123 for perforce@freebsd.org; Mon, 7 Aug 2006 22:01:53 GMT (envelope-from marcel@freebsd.org) Date: Mon, 7 Aug 2006 22:01:53 GMT Message-Id: <200608072201.k77M1rGJ074123@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to marcel@freebsd.org using -f From: Marcel Moolenaar To: Perforce Change Reviews Cc: Subject: PERFORCE change 103403 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 Aug 2006 22:01:56 -0000 http://perforce.freebsd.org/chv.cgi?CH=103403 Change 103403 by marcel@marcel_nfs on 2006/08/07 22:01:07 The PT_GET{,DB,FP}REGS and PT_SET{,DB,FP}REGS requests are now based on a new data structure, called struct ptgetset. The struct ptregset is a meta-structure that describes the size of the register set and has two function pointers: one to build the register set from the thread's context and one to update the thread's context from the register set. These functions do the same as fill_*regs() and set_*regs() without having to hard code that. The 3 struct ptregset data structures are linked to from the process' sysentvec. As such, kern_ptrace() can now handle these requests without having to go through translation steps (see sys/i386/linux/linux_ptrace.c) or without having to hardcode special cases (see COMPAT_IA32). Add PT_GETXREGSIZE, PT_GETXREGS and PT_SETXREGS requests that too are based on struct ptregset. The data argument is used as an index, allowing for multiple extra (machine-specific) sets. The struct ptregset abtracts the MD differences between the extra registers. These requests are needed on ia64 and i386 and are to be used by GDB, in relation to proc_services.h and thread_db.h. Update procfs(4), thereby eliminating the hardcoding fo handling COMPAT_IA32. This commit does not have the changes to the various sysentvecs and is therefore incomplete... Affected files ... .. //depot/projects/gdb/sys/arm/arm/machdep.c#6 edit .. //depot/projects/gdb/sys/fs/procfs/procfs_ctl.c#4 edit .. //depot/projects/gdb/sys/fs/procfs/procfs_dbregs.c#4 edit .. //depot/projects/gdb/sys/fs/procfs/procfs_fpregs.c#4 edit .. //depot/projects/gdb/sys/fs/procfs/procfs_mem.c#4 edit .. //depot/projects/gdb/sys/fs/procfs/procfs_regs.c#4 edit .. //depot/projects/gdb/sys/i386/linux/linux_ptrace.c#4 edit .. //depot/projects/gdb/sys/ia64/ia64/machdep.c#15 edit .. //depot/projects/gdb/sys/kern/sys_process.c#11 edit .. //depot/projects/gdb/sys/sys/ptrace.h#7 edit .. //depot/projects/gdb/sys/sys/syscallsubr.h#4 edit .. //depot/projects/gdb/sys/sys/sysent.h#5 edit Differences ... ==== //depot/projects/gdb/sys/arm/arm/machdep.c#6 (text+ko) ==== @@ -364,7 +364,7 @@ uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_READ; uio.uio_td = td; - return proc_rwmem(td->td_proc, &uio); + return ptrace_rwmem(td->td_proc, &uio); } static int @@ -383,7 +383,7 @@ uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_WRITE; uio.uio_td = td; - return proc_rwmem(td->td_proc, &uio); + return ptrace_rwmem(td->td_proc, &uio); } int ==== //depot/projects/gdb/sys/fs/procfs/procfs_ctl.c#4 (text+ko) ==== @@ -245,7 +245,7 @@ * What does it mean to single step a threaded program? */ case PROCFS_CTL_STEP: - error = proc_sstep(FIRST_THREAD_IN_PROC(p)); /* XXXKSE */ + error = ptrace_sstep(FIRST_THREAD_IN_PROC(p)); /* XXXKSE */ PROC_UNLOCK(p); if (error) return (error); ==== //depot/projects/gdb/sys/fs/procfs/procfs_dbregs.c#4 (text+ko) ==== @@ -48,52 +48,27 @@ #include #include #include +#include #include #include #include +#include #include -#include - #include #include #ifdef COMPAT_IA32 -#include -#include -#include - extern struct sysentvec ia32_freebsd_sysvec; -/* - * PROC(write, dbregs, td2, &r) becomes - * proc_write_dbregs(td2, &r) or - * proc_write_dbregs32(td2, &r32) - * - * UIOMOVE_FROMBUF(r, uio) becomes - * uiomove_frombuf(&r, sizeof(r), uio) or - * uiomove_frombuf(&r32, sizeof(r32), uio) - */ -#define PROC(d, w, t, r) wrap32 ? \ - proc_ ## d ## _ ## w ## 32(t, r ## 32) : \ - proc_ ## d ## _ ## w(t, r) -#define UIOMOVE_FROMBUF(k, u) wrap32 ? \ - uiomove_frombuf(& k ## 32, sizeof(k ## 32), u) : \ - uiomove_frombuf(& k, sizeof(k), u) -#else -#define PROC(d, w, t, r) proc_ ## d ## _ ## w(t, r) -#define UIOMOVE_FROMBUF(k, u) uiomove_frombuf(& k, sizeof(k), u) #endif int procfs_doprocdbregs(PFS_FILL_ARGS) { + struct sysentvec *sv; + struct thread *td2; + void *buf; int error; - struct dbreg r; - struct thread *td2; -#ifdef COMPAT_IA32 - struct dbreg32 r32; - int wrap32 = 0; -#endif PROC_LOCK(p); KASSERT(p->p_lock > 0, ("proc not held")); @@ -104,19 +79,30 @@ /* XXXKSE: */ td2 = FIRST_THREAD_IN_PROC(p); + sv = td2->td_proc->p_sysent; + + if (sv->sv_dbreg == NULL) { + PROC_UNLOCK(p); + return (ENXIO); + } #ifdef COMPAT_IA32 - if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) { - if (td2->td_proc->p_sysent != &ia32_freebsd_sysvec) { - PROC_UNLOCK(p); - return (EINVAL); - } - wrap32 = 1; + if (td->td_proc->p_sysent == &ia32_freebsd_sysvec && + sv != &ia32_freebsd_sysvec) { + PROC_UNLOCK(p); + return (EINVAL); } #endif - error = PROC(read, dbregs, td2, &r); + + PROC_UNLOCK(p); + buf = malloc(sv->sv_dbreg->rs_size, M_TEMP, M_WAITOK); + if (buf == NULL) + return (ENOMEM); + + PROC_LOCK(p); + error = ptrace_read_regf(td2, buf, sv->sv_dbreg->rs_read); if (error == 0) { PROC_UNLOCK(p); - error = UIOMOVE_FROMBUF(r, uio); + error = uiomove_frombuf(buf, sv->sv_dbreg->rs_size, uio); PROC_LOCK(p); } if (error == 0 && uio->uio_rw == UIO_WRITE) { @@ -124,10 +110,12 @@ error = EBUSY; else /* XXXKSE: */ - error = PROC(write, dbregs, td2, &r); + error = ptrace_write_regf(td2, buf, + sv->sv_dbreg->rs_write); } PROC_UNLOCK(p); + free(buf, M_TEMP); uio->uio_offset = 0; return (error); } ==== //depot/projects/gdb/sys/fs/procfs/procfs_fpregs.c#4 (text+ko) ==== @@ -42,52 +42,27 @@ #include #include #include +#include #include #include #include +#include #include -#include - #include #include #ifdef COMPAT_IA32 -#include -#include -#include - extern struct sysentvec ia32_freebsd_sysvec; -/* - * PROC(write, fpregs, td2, &r) becomes - * proc_write_fpregs(td2, &r) or - * proc_write_fpregs32(td2, &r32) - * - * UIOMOVE_FROMBUF(r, uio) becomes - * uiomove_frombuf(&r, sizeof(r), uio) or - * uiomove_frombuf(&r32, sizeof(r32), uio) - */ -#define PROC(d, w, t, r) wrap32 ? \ - proc_ ## d ## _ ## w ## 32(t, r ## 32) : \ - proc_ ## d ## _ ## w(t, r) -#define UIOMOVE_FROMBUF(k, u) wrap32 ? \ - uiomove_frombuf(& k ## 32, sizeof(k ## 32), u) : \ - uiomove_frombuf(& k, sizeof(k), u) -#else -#define PROC(d, w, t, r) proc_ ## d ## _ ## w(t, r) -#define UIOMOVE_FROMBUF(k, u) uiomove_frombuf(& k, sizeof(k), u) #endif int procfs_doprocfpregs(PFS_FILL_ARGS) { + struct sysentvec *sv; + struct thread *td2; + void *buf; int error; - struct fpreg r; - struct thread *td2; -#ifdef COMPAT_IA32 - struct fpreg32 r32; - int wrap32 = 0; -#endif PROC_LOCK(p); KASSERT(p->p_lock > 0, ("proc not held")); @@ -98,19 +73,31 @@ /* XXXKSE: */ td2 = FIRST_THREAD_IN_PROC(p); + sv = td2->td_proc->p_sysent; + + if (sv->sv_fpreg == NULL) { + PROC_UNLOCK(p); + return (ENXIO); + } + #ifdef COMPAT_IA32 - if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) { - if (td2->td_proc->p_sysent != &ia32_freebsd_sysvec) { - PROC_UNLOCK(p); - return (EINVAL); - } - wrap32 = 1; + if (td->td_proc->p_sysent == &ia32_freebsd_sysvec && + sv != &ia32_freebsd_sysvec) { + PROC_UNLOCK(p); + return (EINVAL); } #endif - error = PROC(read, fpregs, td2, &r); + + PROC_UNLOCK(p); + buf = malloc(sv->sv_fpreg->rs_size, M_TEMP, M_WAITOK); + if (buf == NULL) + return (ENOMEM); + + PROC_LOCK(p); + error = ptrace_read_regf(td2, buf, sv->sv_fpreg->rs_read); if (error == 0) { PROC_UNLOCK(p); - error = UIOMOVE_FROMBUF(r, uio); + error = uiomove_frombuf(buf, sv->sv_fpreg->rs_size, uio); PROC_LOCK(p); } if (error == 0 && uio->uio_rw == UIO_WRITE) { @@ -118,10 +105,12 @@ error = EBUSY; else /* XXXKSE: */ - error = PROC(write, fpregs, td2, &r); + error = ptrace_write_regf(td2, buf, + sv->sv_fpreg->rs_write); } PROC_UNLOCK(p); + free(buf, M_TEMP); uio->uio_offset = 0; return (error); } ==== //depot/projects/gdb/sys/fs/procfs/procfs_mem.c#4 (text+ko) ==== @@ -65,7 +65,7 @@ error = p_candebug(td, p); PROC_UNLOCK(p); if (error == 0) - error = proc_rwmem(p, uio); + error = ptrace_rwmem(p, uio); return (error); } ==== //depot/projects/gdb/sys/fs/procfs/procfs_regs.c#4 (text+ko) ==== @@ -42,52 +42,27 @@ #include #include #include +#include #include #include #include +#include #include -#include - #include #include #ifdef COMPAT_IA32 -#include -#include -#include - extern struct sysentvec ia32_freebsd_sysvec; -/* - * PROC(write, regs, td2, &r) becomes - * proc_write_regs(td2, &r) or - * proc_write_regs32(td2, &r32) - * - * UIOMOVE_FROMBUF(r, uio) becomes - * uiomove_frombuf(&r, sizeof(r), uio) or - * uiomove_frombuf(&r32, sizeof(r32), uio) - */ -#define PROC(d, w, t, r) wrap32 ? \ - proc_ ## d ## _ ## w ## 32(t, r ## 32) : \ - proc_ ## d ## _ ## w(t, r) -#define UIOMOVE_FROMBUF(k, u) wrap32 ? \ - uiomove_frombuf(& k ## 32, sizeof(k ## 32), u) : \ - uiomove_frombuf(& k, sizeof(k), u) -#else -#define PROC(d, w, t, r) proc_ ## d ## _ ## w(t, r) -#define UIOMOVE_FROMBUF(k, u) uiomove_frombuf(& k, sizeof(k), u) #endif int procfs_doprocregs(PFS_FILL_ARGS) { + struct sysentvec *sv; + struct thread *td2; + void *buf; int error; - struct reg r; - struct thread *td2; -#ifdef COMPAT_IA32 - struct reg32 r32; - int wrap32 = 0; -#endif PROC_LOCK(p); KASSERT(p->p_lock > 0, ("proc not held")); @@ -98,19 +73,31 @@ /* XXXKSE: */ td2 = FIRST_THREAD_IN_PROC(p); + sv = td2->td_proc->p_sysent; + + if (sv->sv_reg == NULL) { + PROC_UNLOCK(p); + return (ENXIO); + } + #ifdef COMPAT_IA32 - if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) { - if (td2->td_proc->p_sysent != &ia32_freebsd_sysvec) { - PROC_UNLOCK(p); - return (EINVAL); - } - wrap32 = 1; + if (td->td_proc->p_sysent == &ia32_freebsd_sysvec && + sv != &ia32_freebsd_sysvec) { + PROC_UNLOCK(p); + return (EINVAL); } #endif - error = PROC(read, regs, td2, &r); + + PROC_UNLOCK(p); + buf = malloc(sv->sv_reg->rs_size, M_TEMP, M_WAITOK); + if (buf == NULL) + return (ENOMEM); + + PROC_LOCK(p); + error = ptrace_read_regf(td2, buf, sv->sv_reg->rs_read); if (error == 0) { PROC_UNLOCK(p); - error = UIOMOVE_FROMBUF(r, uio); + error = uiomove_frombuf(buf, sv->sv_reg->rs_size, uio); PROC_LOCK(p); } if (error == 0 && uio->uio_rw == UIO_WRITE) { @@ -118,10 +105,12 @@ error = EBUSY; else /* XXXKSE: */ - error = PROC(write, regs, td2, &r); + error = ptrace_write_regf(td2, buf, + sv->sv_reg->rs_write); } PROC_UNLOCK(p); + free(buf, M_TEMP); uio->uio_offset = 0; return (error); } ==== //depot/projects/gdb/sys/i386/linux/linux_ptrace.c#4 (text+ko) ==== @@ -269,13 +269,13 @@ case PTRACE_POKETEXT: case PTRACE_POKEDATA: case PTRACE_KILL: - error = kern_ptrace(td, req, pid, addr, uap->data); + error = kern_ptrace(td, req, pid, 0, addr, uap->data); break; case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: { /* need to preserve return value */ int rval = td->td_retval[0]; - error = kern_ptrace(td, req, pid, addr, 0); + error = kern_ptrace(td, req, pid, 0, addr, 0); if (error == 0) error = copyout(td->td_retval, (void *)uap->data, sizeof(l_int)); @@ -283,20 +283,20 @@ break; } case PTRACE_DETACH: - error = kern_ptrace(td, PT_DETACH, pid, (void *)1, + error = kern_ptrace(td, PT_DETACH, pid, 0, (void *)1, map_signum(uap->data)); break; case PTRACE_SINGLESTEP: case PTRACE_CONT: - error = kern_ptrace(td, req, pid, (void *)1, + error = kern_ptrace(td, req, pid, 0, (void *)1, map_signum(uap->data)); break; case PTRACE_ATTACH: - error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); + error = kern_ptrace(td, PT_ATTACH, pid, 0, addr, uap->data); break; case PTRACE_GETREGS: /* Linux is using data where FreeBSD is using addr */ - error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); + error = kern_ptrace(td, PT_GETREGS, pid, 0, &u.bsd_reg, 0); if (error == 0) { map_regs_to_linux(&u.bsd_reg, &r.reg); error = copyout(&r.reg, (void *)uap->data, @@ -308,12 +308,13 @@ error = copyin((void *)uap->data, &r.reg, sizeof(r.reg)); if (error == 0) { map_regs_from_linux(&u.bsd_reg, &r.reg); - error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); + error = kern_ptrace(td, PT_SETREGS, pid, 0, &u.bsd_reg, + 0); } break; case PTRACE_GETFPREGS: /* Linux is using data where FreeBSD is using addr */ - error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0); + error = kern_ptrace(td, PT_GETFPREGS, pid, 0, &u.bsd_fpreg, 0); if (error == 0) { map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg); error = copyout(&r.fpreg, (void *)uap->data, @@ -325,7 +326,7 @@ error = copyin((void *)uap->data, &r.fpreg, sizeof(r.fpreg)); if (error == 0) { map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg); - error = kern_ptrace(td, PT_SETFPREGS, pid, + error = kern_ptrace(td, PT_SETFPREGS, pid, 0, &u.bsd_fpreg, 0); } break; @@ -429,7 +430,8 @@ * as necessary. */ if (uap->addr < sizeof(struct linux_pt_reg)) { - error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); + error = kern_ptrace(td, PT_GETREGS, pid, 0, &u.bsd_reg, + 0); if (error != 0) break; @@ -444,7 +446,8 @@ (l_int)uap->data; map_regs_from_linux(&u.bsd_reg, &r.reg); - error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); + error = kern_ptrace(td, PT_SETREGS, pid, 0, &u.bsd_reg, + 0); } /* @@ -452,8 +455,8 @@ */ if (uap->addr >= LINUX_DBREG_OFFSET && uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) { - error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg, - 0); + error = kern_ptrace(td, PT_GETDBREGS, pid, 0, + &u.bsd_dbreg, 0); if (error != 0) break; @@ -467,7 +470,7 @@ *(l_int *)((char *)&u.bsd_dbreg + uap->addr) = uap->data; - error = kern_ptrace(td, PT_SETDBREGS, pid, + error = kern_ptrace(td, PT_SETDBREGS, pid, 0, &u.bsd_dbreg, 0); } ==== //depot/projects/gdb/sys/ia64/ia64/machdep.c#15 (text+ko) ==== @@ -1115,9 +1115,9 @@ uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_WRITE; uio.uio_td = td; - error = proc_rwmem(td->td_proc, &uio); + error = ptrace_rwmem(td->td_proc, &uio); /* - * XXX proc_rwmem() doesn't currently return ENOSPC, + * XXX ptrace_rwmem() doesn't currently return ENOSPC, * so I think it can bogusly return 0. Neither do * we allow short writes. */ ==== //depot/projects/gdb/sys/kern/sys_process.c#11 (text+ko) ==== @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -74,32 +75,6 @@ }; #endif -/* - * Functions implemented using PROC_ACTION(): - * - * proc_read_regs(proc, regs) - * Get the current user-visible register set from the process - * and copy it into the regs structure (). - * The process is stopped at the time read_regs is called. - * - * proc_write_regs(proc, regs) - * Update the current register set from the passed in regs - * structure. Take care to avoid clobbering special CPU - * registers or privileged bits in the PSL. - * Depending on the architecture this may have fix-up work to do, - * especially if the IAR or PCW are modified. - * The process is stopped at the time write_regs is called. - * - * proc_read_fpregs, proc_write_fpregs - * deal with the floating point register set, otherwise as above. - * - * proc_read_dbregs, proc_write_dbregs - * deal with the processor debug register set, otherwise as above. - * - * proc_sstep(proc) - * Arrange for the process to trap after executing a single instruction. - */ - #define PROC_ACTION(action) do { \ int error; \ \ @@ -112,105 +87,28 @@ } while(0) int -proc_read_regs(struct thread *td, struct reg *regs) +ptrace_read_regf(struct thread *td, void *reg, ptregset_readf f) { - PROC_ACTION(fill_regs(td, regs)); + PROC_ACTION((*f)(td, reg)); } int -proc_write_regs(struct thread *td, struct reg *regs) +ptrace_write_regf(struct thread *td, const void *reg, ptregset_writef f) { - PROC_ACTION(set_regs(td, regs)); + PROC_ACTION((*f)(td, reg)); } int -proc_read_dbregs(struct thread *td, struct dbreg *dbregs) -{ - - PROC_ACTION(fill_dbregs(td, dbregs)); -} - -int -proc_write_dbregs(struct thread *td, struct dbreg *dbregs) -{ - - PROC_ACTION(set_dbregs(td, dbregs)); -} - -/* - * Ptrace doesn't support fpregs at all, and there are no security holes - * or translations for fpregs, so we can just copy them. - */ -int -proc_read_fpregs(struct thread *td, struct fpreg *fpregs) -{ - - PROC_ACTION(fill_fpregs(td, fpregs)); -} - -int -proc_write_fpregs(struct thread *td, struct fpreg *fpregs) -{ - - PROC_ACTION(set_fpregs(td, fpregs)); -} - -#ifdef COMPAT_IA32 -/* For 32 bit binaries, we need to expose the 32 bit regs layouts. */ -int -proc_read_regs32(struct thread *td, struct reg32 *regs32) -{ - - PROC_ACTION(fill_regs32(td, regs32)); -} - -int -proc_write_regs32(struct thread *td, struct reg32 *regs32) -{ - - PROC_ACTION(set_regs32(td, regs32)); -} - -int -proc_read_dbregs32(struct thread *td, struct dbreg32 *dbregs32) -{ - - PROC_ACTION(fill_dbregs32(td, dbregs32)); -} - -int -proc_write_dbregs32(struct thread *td, struct dbreg32 *dbregs32) -{ - - PROC_ACTION(set_dbregs32(td, dbregs32)); -} - -int -proc_read_fpregs32(struct thread *td, struct fpreg32 *fpregs32) -{ - - PROC_ACTION(fill_fpregs32(td, fpregs32)); -} - -int -proc_write_fpregs32(struct thread *td, struct fpreg32 *fpregs32) -{ - - PROC_ACTION(set_fpregs32(td, fpregs32)); -} -#endif - -int -proc_sstep(struct thread *td) +ptrace_sstep(struct thread *td) { PROC_ACTION(ptrace_single_step(td)); } int -proc_rwmem(struct proc *p, struct uio *uio) +ptrace_rwmem(struct proc *p, struct uio *uio) { vm_map_t map; vm_object_t backing_object, object = NULL; @@ -347,156 +245,164 @@ }; #endif -#ifdef COMPAT_IA32 -/* - * This CPP subterfuge is to try and reduce the number of ifdefs in - * the body of the code. - * COPYIN(uap->addr, &r.reg, sizeof r.reg); - * becomes either: - * copyin(uap->addr, &r.reg, sizeof r.reg); - * or - * copyin(uap->addr, &r.reg32, sizeof r.reg32); - * .. except this is done at runtime. - */ -#define COPYIN(u, k, s) wrap32 ? \ - copyin(u, k ## 32, s ## 32) : \ - copyin(u, k, s) -#define COPYOUT(k, u, s) wrap32 ? \ - copyout(k ## 32, u, s ## 32) : \ - copyout(k, u, s) -#else -#define COPYIN(u, k, s) copyin(u, k, s) -#define COPYOUT(k, u, s) copyout(k, u, s) -#endif /* * MPSAFE */ int ptrace(struct thread *td, struct ptrace_args *uap) { - /* - * XXX this obfuscation is to reduce stack usage, but the register - * structs may be too large to put on the stack anyway. - */ - union { - struct ptrace_io_desc piod; - struct ptrace_lwpinfo pl; - struct dbreg dbreg; - struct fpreg fpreg; - struct reg reg; -#ifdef COMPAT_IA32 - struct dbreg32 dbreg32; - struct fpreg32 fpreg32; - struct reg32 reg32; - struct ptrace_io_desc32 piod32; -#endif - } r; void *addr; - int error = 0; -#ifdef COMPAT_IA32 - int wrap32 = 0; + struct sysentvec *sv; + struct proc *p; + struct thread *td2; + size_t bufsz; + int error; + lwpid_t tid; - if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) - wrap32 = 1; -#endif AUDIT_ARG(pid, uap->pid); AUDIT_ARG(cmd, uap->req); AUDIT_ARG(addr, uap->addr); AUDIT_ARG(value, uap->data); - addr = &r; + + tid = 0; + if (uap->req == PT_TRACE_ME) { + p = td->td_proc; + PROC_LOCK(p); + } else { + if (uap->pid <= PID_MAX) { + p = pfind(uap->pid); + if (p == NULL) + return (ESRCH); + } else { + tid = uap->pid; + sx_slock(&allproc_lock); + FOREACH_PROC_IN_SYSTEM(p) { + PROC_LOCK(p); + mtx_lock_spin(&sched_lock); + FOREACH_THREAD_IN_PROC(p, td2) { + if (td2->td_tid == tid) + break; + } + mtx_unlock_spin(&sched_lock); + if (td2 != NULL) + break; /* proc lock held */ + PROC_UNLOCK(p); + } + sx_sunlock(&allproc_lock); + if (p == NULL) + return (ESRCH); + uap->pid = p->p_pid; + } + } + + sv = p->p_sysent; + switch (uap->req) { case PT_GETREGS: + case PT_SETREGS: + bufsz = sv->sv_reg->rs_size; + break; case PT_GETFPREGS: + case PT_SETFPREGS: + bufsz = sv->sv_fpreg->rs_size; + break; case PT_GETDBREGS: + case PT_SETDBREGS: + bufsz = sv->sv_dbreg->rs_size; + break; + case PT_GETXREGSIZE: + bufsz = sizeof(size_t); + break; + case PT_GETXREGS: + case PT_SETXREGS: + if (uap->data < 0 || uap->data >= sv->sv_nxregs) { + PROC_UNLOCK(p); + return (EINVAL); + } + bufsz = sv->sv_xregs[uap->data].rs_size; + break; case PT_LWPINFO: + bufsz = sizeof(struct ptrace_lwpinfo); break; + case PT_IO: + if (sv == &ia32_freebsd_sysvec) + bufsz = sizeof(struct ptrace_io_desc32); + else + bufsz = sizeof(struct ptrace_io_desc); + break; + default: + bufsz = 0; + break; + } + PROC_UNLOCK(p); + + if (bufsz != 0) { + addr = malloc(bufsz, M_TEMP, M_WAITOK); + if (addr == NULL) + return (ENOMEM); + } else + addr = uap->addr; + + switch (uap->req) { case PT_SETREGS: - error = COPYIN(uap->addr, &r.reg, sizeof r.reg); - break; case PT_SETFPREGS: - error = COPYIN(uap->addr, &r.fpreg, sizeof r.fpreg); - break; case PT_SETDBREGS: - error = COPYIN(uap->addr, &r.dbreg, sizeof r.dbreg); - break; + case PT_SETXREGS: case PT_IO: - error = COPYIN(uap->addr, &r.piod, sizeof r.piod); + error = copyin(uap->addr, addr, bufsz); break; default: - addr = uap->addr; + error = 0; break; } if (error) - return (error); + goto out; - error = kern_ptrace(td, uap->req, uap->pid, addr, uap->data); + error = kern_ptrace(td, uap->req, uap->pid, tid, addr, uap->data); if (error) - return (error); + goto out; switch (uap->req) { - case PT_IO: - error = COPYOUT(&r.piod, uap->addr, sizeof r.piod); - break; + case PT_LWPINFO: + if (uap->data < bufsz) + bufsz = uap->data; + /* FALLTHROUGH */ case PT_GETREGS: - error = COPYOUT(&r.reg, uap->addr, sizeof r.reg); - break; case PT_GETFPREGS: - error = COPYOUT(&r.fpreg, uap->addr, sizeof r.fpreg); - break; case PT_GETDBREGS: - error = COPYOUT(&r.dbreg, uap->addr, sizeof r.dbreg); + case PT_GETXREGSIZE: + case PT_GETXREGS: + case PT_IO: + error = copyout(addr, uap->addr, bufsz); break; - case PT_LWPINFO: - error = copyout(&r.pl, uap->addr, uap->data); + default: + error = 0; break; } +out: + if (bufsz > 0) + free(addr, M_TEMP); return (error); } -#undef COPYIN -#undef COPYOUT - -#ifdef COMPAT_IA32 -/* - * PROC_READ(regs, td2, addr); - * becomes either: - * proc_read_regs(td2, addr); - * or - * proc_read_regs32(td2, addr); - * .. except this is done at runtime. There is an additional - * complication in that PROC_WRITE disallows 32 bit consumers - * from writing to 64 bit address space targets. - */ -#define PROC_READ(w, t, a) wrap32 ? \ - proc_read_ ## w ## 32(t, a) : \ - proc_read_ ## w (t, a) -#define PROC_WRITE(w, t, a) wrap32 ? \ - (safe ? proc_write_ ## w ## 32(t, a) : EINVAL ) : \ - proc_write_ ## w (t, a) -#else -#define PROC_READ(w, t, a) proc_read_ ## w (t, a) -#define PROC_WRITE(w, t, a) proc_write_ ## w (t, a) -#endif int -kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) +kern_ptrace(struct thread *td, int req, pid_t pid, lwpid_t tid, void *addr, int data) { struct iovec iov; struct uio uio; - struct proc *curp, *p, *pp; + struct proc *p, *pp; + struct sysentvec *sv; struct thread *td2 = NULL; struct ptrace_io_desc *piod = NULL; struct ptrace_lwpinfo *pl; int error, write, tmp, num; int proctree_locked = 0; - lwpid_t tid = 0, *buf; + lwpid_t *buf; #ifdef COMPAT_IA32 - int wrap32 = 0, safe = 0; struct ptrace_io_desc32 *piod32 = NULL; #endif - curp = td->td_proc; - /* Lock proctree before locking the process. */ switch (req) { case PT_TRACE_ME: @@ -519,35 +425,31 @@ p = td->td_proc; PROC_LOCK(p); } else { - if (pid <= PID_MAX) { - if ((p = pfind(pid)) == NULL) { - if (proctree_locked) - sx_xunlock(&proctree_lock); - return (ESRCH); + p = pfind(pid); + if (p == NULL) { + if (proctree_locked) + sx_xunlock(&proctree_lock); + return (ESRCH); + } + if (tid != 0) { + mtx_lock_spin(&sched_lock); + FOREACH_THREAD_IN_PROC(p, td2) { + if (td2->td_tid == tid) + break; } - } else { - /* this is slow, should be optimized */ - sx_slock(&allproc_lock); >>> TRUNCATED FOR MAIL (1000 lines) <<<