diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index 428b0ae2d573..82c9737261e2 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.82 1999/06/01 18:19:45 jlemon Exp $ + * $Id: swtch.s,v 1.83 1999/07/03 06:33:24 alc Exp $ */ #include "npx.h" @@ -480,6 +480,26 @@ ENTRY(cpu_switch) movl %edi,PCB_EDI(%edx) movl %gs,PCB_GS(%edx) + /* test if debug regisers should be saved */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl %dr7,%eax /* yes, do the save */ + movl %eax,PCB_DR7(%edx) + andl $0x0000ff00, %eax /* disable all watchpoints */ + movl %eax,%dr7 + movl %dr6,%eax + movl %eax,PCB_DR6(%edx) + movl %dr3,%eax + movl %eax,PCB_DR3(%edx) + movl %dr2,%eax + movl %eax,PCB_DR2(%edx) + movl %dr1,%eax + movl %eax,PCB_DR1(%edx) + movl %dr0,%eax + movl %eax,PCB_DR0(%edx) +1: + #ifdef SMP movl _mp_lock, %eax /* XXX FIXME: we should be saving the local APIC TPR */ @@ -718,6 +738,24 @@ swtch_com: cpu_switch_load_gs: movl PCB_GS(%edx),%gs + /* test if debug regisers should be restored */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl PCB_DR6(%edx),%eax /* yes, do the restore */ + movl %eax,%dr6 + movl PCB_DR3(%edx),%eax + movl %eax,%dr3 + movl PCB_DR2(%edx),%eax + movl %eax,%dr2 + movl PCB_DR1(%edx),%eax + movl %eax,%dr1 + movl PCB_DR0(%edx),%eax + movl %eax,%dr0 + movl PCB_DR7(%edx),%eax + movl %eax,%dr7 +1: + sti ret diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index 3e92787bf852..dc5a18d61bf7 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 - * $Id: genassym.c,v 1.71 1999/06/28 09:21:41 peter Exp $ + * $Id: genassym.c,v 1.72 1999/07/06 07:13:32 cracauer Exp $ */ #include "opt_user_ldt.h" @@ -128,6 +128,13 @@ main() printf("#define\tTSS_ESP0 %#x\n", OS(i386tss, tss_esp0)); printf("#define\tPCB_USERLDT %#x\n", OS(pcb, pcb_ldt)); printf("#define\tPCB_GS %#x\n", OS(pcb, pcb_gs)); + printf("#define\tPCB_DR0 %#x\n", OS(pcb, pcb_dr0)); + printf("#define\tPCB_DR1 %#x\n", OS(pcb, pcb_dr1)); + printf("#define\tPCB_DR2 %#x\n", OS(pcb, pcb_dr2)); + printf("#define\tPCB_DR3 %#x\n", OS(pcb, pcb_dr3)); + printf("#define\tPCB_DR6 %#x\n", OS(pcb, pcb_dr6)); + printf("#define\tPCB_DR7 %#x\n", OS(pcb, pcb_dr7)); + printf("#define\tPCB_DBREGS %#x\n", PCB_DBREGS ); printf("#define\tPCB_EXT %#x\n", OS(pcb, pcb_ext)); #ifdef SMP printf("#define\tPCB_MPNEST %#x\n", OS(pcb, pcb_mpnest)); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index ec11c9827bd1..423de1258cf7 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.353 1999/07/06 07:13:33 cracauer Exp $ + * $Id: machdep.c,v 1.354 1999/07/08 06:05:48 mckusick Exp $ */ #include "apm.h" @@ -1927,6 +1927,87 @@ set_fpregs(p, fpregs) return (0); } +int +fill_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + struct pcb *pcb; + + pcb = &p->p_addr->u_pcb; + dbregs->dr0 = pcb->pcb_dr0; + dbregs->dr1 = pcb->pcb_dr1; + dbregs->dr2 = pcb->pcb_dr2; + dbregs->dr3 = pcb->pcb_dr3; + dbregs->dr4 = 0; + dbregs->dr5 = 0; + dbregs->dr6 = pcb->pcb_dr6; + dbregs->dr7 = pcb->pcb_dr7; + return (0); +} + +int +set_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + struct pcb *pcb; + + pcb = &p->p_addr->u_pcb; + + /* + * Don't let a process set a breakpoint that is not within the + * process's address space. If a process could do this, it + * could halt the system by setting a breakpoint in the kernel + * (if ddb was enabled). Thus, we need to check to make sure + * that no breakpoints are being enabled for addresses outside + * process's address space, unless, perhaps, we were called by + * uid 0. + * + * XXX - what about when the watched area of the user's + * address space is written into from within the kernel + * ... wouldn't that still cause a breakpoint to be generated + * from within kernel mode? + */ + + if (p->p_cred->pc_ucred->cr_uid != 0) { + if (dbregs->dr7 & 0x3) { + /* dr0 is enabled */ + if (dbregs->dr0 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<2)) { + /* dr1 is enabled */ + if (dbregs->dr1 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<4)) { + /* dr2 is enabled */ + if (dbregs->dr2 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<6)) { + /* dr3 is enabled */ + if (dbregs->dr3 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + } + + pcb->pcb_dr0 = dbregs->dr0; + pcb->pcb_dr1 = dbregs->dr1; + pcb->pcb_dr2 = dbregs->dr2; + pcb->pcb_dr3 = dbregs->dr3; + pcb->pcb_dr6 = dbregs->dr6; + pcb->pcb_dr7 = dbregs->dr7; + + pcb->pcb_flags |= PCB_DBREGS; + + return (0); +} + #ifndef DDB void Debugger(const char *msg) diff --git a/sys/amd64/amd64/swtch.s b/sys/amd64/amd64/swtch.s index 428b0ae2d573..82c9737261e2 100644 --- a/sys/amd64/amd64/swtch.s +++ b/sys/amd64/amd64/swtch.s @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.82 1999/06/01 18:19:45 jlemon Exp $ + * $Id: swtch.s,v 1.83 1999/07/03 06:33:24 alc Exp $ */ #include "npx.h" @@ -480,6 +480,26 @@ ENTRY(cpu_switch) movl %edi,PCB_EDI(%edx) movl %gs,PCB_GS(%edx) + /* test if debug regisers should be saved */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl %dr7,%eax /* yes, do the save */ + movl %eax,PCB_DR7(%edx) + andl $0x0000ff00, %eax /* disable all watchpoints */ + movl %eax,%dr7 + movl %dr6,%eax + movl %eax,PCB_DR6(%edx) + movl %dr3,%eax + movl %eax,PCB_DR3(%edx) + movl %dr2,%eax + movl %eax,PCB_DR2(%edx) + movl %dr1,%eax + movl %eax,PCB_DR1(%edx) + movl %dr0,%eax + movl %eax,PCB_DR0(%edx) +1: + #ifdef SMP movl _mp_lock, %eax /* XXX FIXME: we should be saving the local APIC TPR */ @@ -718,6 +738,24 @@ swtch_com: cpu_switch_load_gs: movl PCB_GS(%edx),%gs + /* test if debug regisers should be restored */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl PCB_DR6(%edx),%eax /* yes, do the restore */ + movl %eax,%dr6 + movl PCB_DR3(%edx),%eax + movl %eax,%dr3 + movl PCB_DR2(%edx),%eax + movl %eax,%dr2 + movl PCB_DR1(%edx),%eax + movl %eax,%dr1 + movl PCB_DR0(%edx),%eax + movl %eax,%dr0 + movl PCB_DR7(%edx),%eax + movl %eax,%dr7 +1: + sti ret diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index 35b65455e244..491eb46b024a 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: md_var.h,v 1.28 1999/01/08 16:29:58 bde Exp $ + * $Id: md_var.h,v 1.29 1999/04/28 01:04:02 luoqi Exp $ */ #ifndef _MACHINE_MD_VAR_H_ @@ -64,6 +64,7 @@ typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss)); struct proc; struct reg; struct fpreg; +struct dbreg; void bcopyb __P((const void *from, void *to, size_t len)); void busdma_swi __P((void)); @@ -80,6 +81,7 @@ void doreti_popl_fs __P((void)) __asm(__STRING(doreti_popl_fs)); void doreti_popl_fs_fault __P((void)) __asm(__STRING(doreti_popl_fs_fault)); int fill_fpregs __P((struct proc *, struct fpreg *)); int fill_regs __P((struct proc *p, struct reg *regs)); +int fill_dbregs __P((struct proc *p, struct dbreg *dbregs)); void fillw __P((int /*u_short*/ pat, void *base, size_t cnt)); void i486_bzero __P((void *buf, size_t len)); void i586_bcopy __P((const void *from, void *to, size_t len)); diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h index 2dbc707d0fcc..5cee924dd9ff 100644 --- a/sys/amd64/include/pcb.h +++ b/sys/amd64/include/pcb.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)pcb.h 5.10 (Berkeley) 5/12/91 - * $Id: pcb.h,v 1.27 1999/04/28 01:04:05 luoqi Exp $ + * $Id: pcb.h,v 1.28 1999/06/01 18:20:06 jlemon Exp $ */ #ifndef _I386_PCB_H_ @@ -54,11 +54,20 @@ struct pcb { int pcb_esp; int pcb_ebx; int pcb_eip; + + int pcb_dr0; + int pcb_dr1; + int pcb_dr2; + int pcb_dr3; + int pcb_dr6; + int pcb_dr7; + caddr_t pcb_ldt; /* per process (user) LDT */ int pcb_ldt_len; /* number of LDT entries */ struct save87 pcb_savefpu; /* floating point state for 287/387 */ u_char pcb_flags; #define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */ +#define PCB_DBREGS 0x02 /* process using debug registers */ caddr_t pcb_onfault; /* copyin/out fault recovery */ #ifdef SMP u_long pcb_mpnest; diff --git a/sys/amd64/include/ptrace.h b/sys/amd64/include/ptrace.h index ec3d5aab5ca5..2c43a2eef8d4 100644 --- a/sys/amd64/include/ptrace.h +++ b/sys/amd64/include/ptrace.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ptrace.h 8.1 (Berkeley) 6/11/93 - * $Id: ptrace.h,v 1.5 1997/02/22 09:35:03 peter Exp $ + * $Id: ptrace.h,v 1.6 1998/05/19 00:00:12 tegge Exp $ */ #ifndef _MACHINE_PTRACE_H_ @@ -44,6 +44,8 @@ #define PT_SETREGS (PT_FIRSTMACH + 2) #define PT_GETFPREGS (PT_FIRSTMACH + 3) #define PT_SETFPREGS (PT_FIRSTMACH + 4) +#define PT_GETDBREGS (PT_FIRSTMACH + 5) +#define PT_SETDBREGS (PT_FIRSTMACH + 6) #ifdef KERNEL int ptrace_read_u_check __P((struct proc *p, vm_offset_t off, size_t len)); diff --git a/sys/amd64/include/reg.h b/sys/amd64/include/reg.h index 247011646fa5..994bdfda0360 100644 --- a/sys/amd64/include/reg.h +++ b/sys/amd64/include/reg.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)reg.h 5.5 (Berkeley) 1/18/91 - * $Id: reg.h,v 1.17 1999/04/03 22:19:59 jdp Exp $ + * $Id: reg.h,v 1.18 1999/04/28 01:04:06 luoqi Exp $ */ #ifndef _MACHINE_REG_H_ @@ -118,6 +118,18 @@ struct fpreg { unsigned char fpr_pad[64]; }; +struct dbreg { + unsigned int dr0; /* debug address register 0 */ + unsigned int dr1; /* debug address register 1 */ + unsigned int dr2; /* debug address register 2 */ + unsigned int dr3; /* debug address register 3 */ + unsigned int dr4; /* reserved */ + unsigned int dr5; /* reserved */ + unsigned int dr6; /* debug status register */ + unsigned int dr7; /* debug control register */ +}; + + #ifdef KERNEL /* * XXX these interfaces are MI, so they should be declared in a MI place. @@ -125,6 +137,7 @@ struct fpreg { int set_fpregs __P((struct proc *, struct fpreg *)); int set_regs __P((struct proc *p, struct reg *regs)); void setregs __P((struct proc *, u_long, u_long, u_long)); +int set_dbregs __P((struct proc *p, struct dbreg *dbregs)); #endif #endif /* !_MACHINE_REG_H_ */ diff --git a/sys/conf/files b/sys/conf/files index 5d9bb0511996..241d71b2d24b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -362,6 +362,7 @@ miscfs/nullfs/null_vnops.c optional nullfs miscfs/portal/portal_vfsops.c optional portal miscfs/portal/portal_vnops.c optional portal miscfs/procfs/procfs_ctl.c optional procfs +miscfs/procfs/procfs_dbregs.c standard miscfs/procfs/procfs_fpregs.c standard miscfs/procfs/procfs_map.c optional procfs miscfs/procfs/procfs_mem.c standard diff --git a/sys/fs/procfs/procfs.h b/sys/fs/procfs/procfs.h index b38ed872dc8b..f813070e699e 100644 --- a/sys/fs/procfs/procfs.h +++ b/sys/fs/procfs/procfs.h @@ -37,7 +37,7 @@ * @(#)procfs.h 8.9 (Berkeley) 5/14/95 * * From: - * $Id: procfs.h,v 1.25 1999/05/04 08:00:10 phk Exp $ + * $Id: procfs.h,v 1.26 1999/06/13 20:53:13 phk Exp $ */ /* @@ -51,6 +51,7 @@ typedef enum { Pmem, /* the process's memory image */ Pregs, /* the process's register set */ Pfpregs, /* the process's FP register set */ + Pdbregs, /* the process's debug register set */ Pctl, /* process control */ Pstatus, /* process status */ Pnote, /* process notifier */ @@ -124,6 +125,7 @@ vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); /* */ struct reg; struct fpreg; +struct dbreg; #define PFIND(pid) ((pid) ? pfind(pid) : &proc0) @@ -137,9 +139,12 @@ int procfs_read_regs __P((struct proc *, struct reg *)); int procfs_write_regs __P((struct proc *, struct reg *)); int procfs_read_fpregs __P((struct proc *, struct fpreg *)); int procfs_write_fpregs __P((struct proc *, struct fpreg *)); +int procfs_read_dbregs __P((struct proc *, struct dbreg *)); +int procfs_write_dbregs __P((struct proc *, struct dbreg *)); int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dodbregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); @@ -155,6 +160,7 @@ int procfs_kmemaccess __P((struct proc *)); int procfs_validfile __P((struct proc *)); int procfs_validfpregs __P((struct proc *)); int procfs_validregs __P((struct proc *)); +int procfs_validdbregs __P((struct proc *)); int procfs_validmap __P((struct proc *)); int procfs_validtype __P((struct proc *)); diff --git a/sys/fs/procfs/procfs_subr.c b/sys/fs/procfs/procfs_subr.c index 7b5e18c440d5..cf313e863856 100644 --- a/sys/fs/procfs/procfs_subr.c +++ b/sys/fs/procfs/procfs_subr.c @@ -36,7 +36,7 @@ * * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95 * - * $Id: procfs_subr.c,v 1.23 1999/01/27 22:42:07 dillon Exp $ + * $Id: procfs_subr.c,v 1.24 1999/04/30 13:04:21 phk Exp $ */ #include @@ -167,6 +167,7 @@ loop: case Pregs: case Pfpregs: + case Pdbregs: pfs->pfs_mode = (VREAD|VWRITE); vp->v_type = VREG; break; @@ -264,6 +265,10 @@ procfs_rw(ap) rtval = procfs_dofpregs(curp, p, pfs, uio); break; + case Pdbregs: + rtval = procfs_dodbregs(curp, p, pfs, uio); + break; + case Pctl: rtval = procfs_doctl(curp, p, pfs, uio); break; diff --git a/sys/fs/procfs/procfs_vnops.c b/sys/fs/procfs/procfs_vnops.c index d421bac0e3b8..fc47353f62ce 100644 --- a/sys/fs/procfs/procfs_vnops.c +++ b/sys/fs/procfs/procfs_vnops.c @@ -36,7 +36,7 @@ * * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 * - * $Id: procfs_vnops.c,v 1.68 1999/05/04 08:01:55 phk Exp $ + * $Id: procfs_vnops.c,v 1.69 1999/06/13 20:53:16 phk Exp $ */ /* @@ -95,6 +95,7 @@ static struct proc_target { { DT_REG, N("mem"), Pmem, NULL }, { DT_REG, N("regs"), Pregs, procfs_validregs }, { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, + { DT_REG, N("dbregs"), Pdbregs, procfs_validdbregs }, { DT_REG, N("ctl"), Pctl, NULL }, { DT_REG, N("status"), Pstatus, NULL }, { DT_REG, N("note"), Pnote, NULL }, @@ -491,6 +492,7 @@ procfs_getattr(ap) case Pctl: case Pregs: case Pfpregs: + case Pdbregs: if (procp->p_flag & P_SUGID) vap->va_mode &= ~((VREAD|VWRITE)| ((VREAD|VWRITE)>>3)| @@ -571,6 +573,10 @@ procfs_getattr(ap) vap->va_bytes = vap->va_size = sizeof(struct fpreg); break; + case Pdbregs: + vap->va_bytes = vap->va_size = sizeof(struct dbreg); + break; + case Ptype: case Pmap: case Pctl: diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index 3e92787bf852..dc5a18d61bf7 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 - * $Id: genassym.c,v 1.71 1999/06/28 09:21:41 peter Exp $ + * $Id: genassym.c,v 1.72 1999/07/06 07:13:32 cracauer Exp $ */ #include "opt_user_ldt.h" @@ -128,6 +128,13 @@ main() printf("#define\tTSS_ESP0 %#x\n", OS(i386tss, tss_esp0)); printf("#define\tPCB_USERLDT %#x\n", OS(pcb, pcb_ldt)); printf("#define\tPCB_GS %#x\n", OS(pcb, pcb_gs)); + printf("#define\tPCB_DR0 %#x\n", OS(pcb, pcb_dr0)); + printf("#define\tPCB_DR1 %#x\n", OS(pcb, pcb_dr1)); + printf("#define\tPCB_DR2 %#x\n", OS(pcb, pcb_dr2)); + printf("#define\tPCB_DR3 %#x\n", OS(pcb, pcb_dr3)); + printf("#define\tPCB_DR6 %#x\n", OS(pcb, pcb_dr6)); + printf("#define\tPCB_DR7 %#x\n", OS(pcb, pcb_dr7)); + printf("#define\tPCB_DBREGS %#x\n", PCB_DBREGS ); printf("#define\tPCB_EXT %#x\n", OS(pcb, pcb_ext)); #ifdef SMP printf("#define\tPCB_MPNEST %#x\n", OS(pcb, pcb_mpnest)); diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index ec11c9827bd1..423de1258cf7 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.353 1999/07/06 07:13:33 cracauer Exp $ + * $Id: machdep.c,v 1.354 1999/07/08 06:05:48 mckusick Exp $ */ #include "apm.h" @@ -1927,6 +1927,87 @@ set_fpregs(p, fpregs) return (0); } +int +fill_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + struct pcb *pcb; + + pcb = &p->p_addr->u_pcb; + dbregs->dr0 = pcb->pcb_dr0; + dbregs->dr1 = pcb->pcb_dr1; + dbregs->dr2 = pcb->pcb_dr2; + dbregs->dr3 = pcb->pcb_dr3; + dbregs->dr4 = 0; + dbregs->dr5 = 0; + dbregs->dr6 = pcb->pcb_dr6; + dbregs->dr7 = pcb->pcb_dr7; + return (0); +} + +int +set_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + struct pcb *pcb; + + pcb = &p->p_addr->u_pcb; + + /* + * Don't let a process set a breakpoint that is not within the + * process's address space. If a process could do this, it + * could halt the system by setting a breakpoint in the kernel + * (if ddb was enabled). Thus, we need to check to make sure + * that no breakpoints are being enabled for addresses outside + * process's address space, unless, perhaps, we were called by + * uid 0. + * + * XXX - what about when the watched area of the user's + * address space is written into from within the kernel + * ... wouldn't that still cause a breakpoint to be generated + * from within kernel mode? + */ + + if (p->p_cred->pc_ucred->cr_uid != 0) { + if (dbregs->dr7 & 0x3) { + /* dr0 is enabled */ + if (dbregs->dr0 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<2)) { + /* dr1 is enabled */ + if (dbregs->dr1 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<4)) { + /* dr2 is enabled */ + if (dbregs->dr2 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<6)) { + /* dr3 is enabled */ + if (dbregs->dr3 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + } + + pcb->pcb_dr0 = dbregs->dr0; + pcb->pcb_dr1 = dbregs->dr1; + pcb->pcb_dr2 = dbregs->dr2; + pcb->pcb_dr3 = dbregs->dr3; + pcb->pcb_dr6 = dbregs->dr6; + pcb->pcb_dr7 = dbregs->dr7; + + pcb->pcb_flags |= PCB_DBREGS; + + return (0); +} + #ifndef DDB void Debugger(const char *msg) diff --git a/sys/i386/i386/procfs_machdep.c b/sys/i386/i386/procfs_machdep.c index 03a8d9dd0261..b0f8e3cda6e2 100644 --- a/sys/i386/i386/procfs_machdep.c +++ b/sys/i386/i386/procfs_machdep.c @@ -37,7 +37,7 @@ * @(#)procfs_machdep.c 8.3 (Berkeley) 1/27/94 * * From: - * $Id: procfs_machdep.c,v 1.10 1997/07/20 08:37:22 bde Exp $ + * $Id: procfs_machdep.c,v 1.11 1998/09/14 22:43:33 jdp Exp $ */ /* @@ -59,6 +59,9 @@ * procfs_read_fpregs, procfs_write_fpregs * deal with the floating point register set, otherwise as above. * + * procfs_read_dbregs, procfs_write_dbregs + * deal with the processor debug register set, otherwise as above. + * * procfs_sstep(proc) * Arrange for the process to trap after executing a single instruction. * @@ -100,6 +103,26 @@ procfs_write_regs(p, regs) return (set_regs(p, regs)); } +int +procfs_read_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + if ((p->p_flag & P_INMEM) == 0) + return (EIO); + return (fill_dbregs(p, dbregs)); +} + +int +procfs_write_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + if ((p->p_flag & P_INMEM) == 0) + return (EIO); + return (set_dbregs(p, dbregs)); +} + /* * Ptrace doesn't support fpregs at all, and there are no security holes * or translations for fpregs, so we can just copy them. diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s index 428b0ae2d573..82c9737261e2 100644 --- a/sys/i386/i386/swtch.s +++ b/sys/i386/i386/swtch.s @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.82 1999/06/01 18:19:45 jlemon Exp $ + * $Id: swtch.s,v 1.83 1999/07/03 06:33:24 alc Exp $ */ #include "npx.h" @@ -480,6 +480,26 @@ ENTRY(cpu_switch) movl %edi,PCB_EDI(%edx) movl %gs,PCB_GS(%edx) + /* test if debug regisers should be saved */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl %dr7,%eax /* yes, do the save */ + movl %eax,PCB_DR7(%edx) + andl $0x0000ff00, %eax /* disable all watchpoints */ + movl %eax,%dr7 + movl %dr6,%eax + movl %eax,PCB_DR6(%edx) + movl %dr3,%eax + movl %eax,PCB_DR3(%edx) + movl %dr2,%eax + movl %eax,PCB_DR2(%edx) + movl %dr1,%eax + movl %eax,PCB_DR1(%edx) + movl %dr0,%eax + movl %eax,PCB_DR0(%edx) +1: + #ifdef SMP movl _mp_lock, %eax /* XXX FIXME: we should be saving the local APIC TPR */ @@ -718,6 +738,24 @@ swtch_com: cpu_switch_load_gs: movl PCB_GS(%edx),%gs + /* test if debug regisers should be restored */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl PCB_DR6(%edx),%eax /* yes, do the restore */ + movl %eax,%dr6 + movl PCB_DR3(%edx),%eax + movl %eax,%dr3 + movl PCB_DR2(%edx),%eax + movl %eax,%dr2 + movl PCB_DR1(%edx),%eax + movl %eax,%dr1 + movl PCB_DR0(%edx),%eax + movl %eax,%dr0 + movl PCB_DR7(%edx),%eax + movl %eax,%dr7 +1: + sti ret diff --git a/sys/i386/include/md_var.h b/sys/i386/include/md_var.h index 35b65455e244..491eb46b024a 100644 --- a/sys/i386/include/md_var.h +++ b/sys/i386/include/md_var.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: md_var.h,v 1.28 1999/01/08 16:29:58 bde Exp $ + * $Id: md_var.h,v 1.29 1999/04/28 01:04:02 luoqi Exp $ */ #ifndef _MACHINE_MD_VAR_H_ @@ -64,6 +64,7 @@ typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss)); struct proc; struct reg; struct fpreg; +struct dbreg; void bcopyb __P((const void *from, void *to, size_t len)); void busdma_swi __P((void)); @@ -80,6 +81,7 @@ void doreti_popl_fs __P((void)) __asm(__STRING(doreti_popl_fs)); void doreti_popl_fs_fault __P((void)) __asm(__STRING(doreti_popl_fs_fault)); int fill_fpregs __P((struct proc *, struct fpreg *)); int fill_regs __P((struct proc *p, struct reg *regs)); +int fill_dbregs __P((struct proc *p, struct dbreg *dbregs)); void fillw __P((int /*u_short*/ pat, void *base, size_t cnt)); void i486_bzero __P((void *buf, size_t len)); void i586_bcopy __P((const void *from, void *to, size_t len)); diff --git a/sys/i386/include/pcb.h b/sys/i386/include/pcb.h index 2dbc707d0fcc..5cee924dd9ff 100644 --- a/sys/i386/include/pcb.h +++ b/sys/i386/include/pcb.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)pcb.h 5.10 (Berkeley) 5/12/91 - * $Id: pcb.h,v 1.27 1999/04/28 01:04:05 luoqi Exp $ + * $Id: pcb.h,v 1.28 1999/06/01 18:20:06 jlemon Exp $ */ #ifndef _I386_PCB_H_ @@ -54,11 +54,20 @@ struct pcb { int pcb_esp; int pcb_ebx; int pcb_eip; + + int pcb_dr0; + int pcb_dr1; + int pcb_dr2; + int pcb_dr3; + int pcb_dr6; + int pcb_dr7; + caddr_t pcb_ldt; /* per process (user) LDT */ int pcb_ldt_len; /* number of LDT entries */ struct save87 pcb_savefpu; /* floating point state for 287/387 */ u_char pcb_flags; #define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */ +#define PCB_DBREGS 0x02 /* process using debug registers */ caddr_t pcb_onfault; /* copyin/out fault recovery */ #ifdef SMP u_long pcb_mpnest; diff --git a/sys/i386/include/ptrace.h b/sys/i386/include/ptrace.h index ec3d5aab5ca5..2c43a2eef8d4 100644 --- a/sys/i386/include/ptrace.h +++ b/sys/i386/include/ptrace.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ptrace.h 8.1 (Berkeley) 6/11/93 - * $Id: ptrace.h,v 1.5 1997/02/22 09:35:03 peter Exp $ + * $Id: ptrace.h,v 1.6 1998/05/19 00:00:12 tegge Exp $ */ #ifndef _MACHINE_PTRACE_H_ @@ -44,6 +44,8 @@ #define PT_SETREGS (PT_FIRSTMACH + 2) #define PT_GETFPREGS (PT_FIRSTMACH + 3) #define PT_SETFPREGS (PT_FIRSTMACH + 4) +#define PT_GETDBREGS (PT_FIRSTMACH + 5) +#define PT_SETDBREGS (PT_FIRSTMACH + 6) #ifdef KERNEL int ptrace_read_u_check __P((struct proc *p, vm_offset_t off, size_t len)); diff --git a/sys/i386/include/reg.h b/sys/i386/include/reg.h index 247011646fa5..994bdfda0360 100644 --- a/sys/i386/include/reg.h +++ b/sys/i386/include/reg.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)reg.h 5.5 (Berkeley) 1/18/91 - * $Id: reg.h,v 1.17 1999/04/03 22:19:59 jdp Exp $ + * $Id: reg.h,v 1.18 1999/04/28 01:04:06 luoqi Exp $ */ #ifndef _MACHINE_REG_H_ @@ -118,6 +118,18 @@ struct fpreg { unsigned char fpr_pad[64]; }; +struct dbreg { + unsigned int dr0; /* debug address register 0 */ + unsigned int dr1; /* debug address register 1 */ + unsigned int dr2; /* debug address register 2 */ + unsigned int dr3; /* debug address register 3 */ + unsigned int dr4; /* reserved */ + unsigned int dr5; /* reserved */ + unsigned int dr6; /* debug status register */ + unsigned int dr7; /* debug control register */ +}; + + #ifdef KERNEL /* * XXX these interfaces are MI, so they should be declared in a MI place. @@ -125,6 +137,7 @@ struct fpreg { int set_fpregs __P((struct proc *, struct fpreg *)); int set_regs __P((struct proc *p, struct reg *regs)); void setregs __P((struct proc *, u_long, u_long, u_long)); +int set_dbregs __P((struct proc *p, struct dbreg *dbregs)); #endif #endif /* !_MACHINE_REG_H_ */ diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 41482954a768..814db9845c5e 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sys_process.c,v 1.45 1999/04/28 11:37:04 phk Exp $ + * $Id: sys_process.c,v 1.46 1999/07/01 22:52:40 peter Exp $ */ #include @@ -274,6 +274,12 @@ ptrace(curp, uap) #endif #ifdef PT_SETFPREGS case PT_SETFPREGS: +#endif +#ifdef PT_GETDBREGS + case PT_GETDBREGS: +#endif +#ifdef PT_SETDBREGS + case PT_SETDBREGS: #endif /* not being traced... */ if ((p->p_flag & P_TRACED) == 0) @@ -502,6 +508,32 @@ ptrace(curp, uap) } #endif /* defined(PT_SETFPREGS) || defined(PT_GETFPREGS) */ +#ifdef PT_SETDBREGS + case PT_SETDBREGS: + write = 1; + /* fallthrough */ +#endif /* PT_SETDBREGS */ +#ifdef PT_GETDBREGS + case PT_GETDBREGS: + /* write = 0 above */ +#endif /* PT_SETDBREGS */ +#if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) + if (!procfs_validdbregs(p)) /* no P_SYSTEM procs please */ + return EINVAL; + else { + iov.iov_base = uap->addr; + iov.iov_len = sizeof(struct dbreg); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = 0; + uio.uio_resid = sizeof(struct dbreg); + uio.uio_segflg = UIO_USERSPACE; + uio.uio_rw = write ? UIO_WRITE : UIO_READ; + uio.uio_procp = curp; + return (procfs_dodbregs(curp, p, NULL, &uio)); + } +#endif /* defined(PT_SETDBREGS) || defined(PT_GETDBREGS) */ + default: break; } diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h index b38ed872dc8b..f813070e699e 100644 --- a/sys/miscfs/procfs/procfs.h +++ b/sys/miscfs/procfs/procfs.h @@ -37,7 +37,7 @@ * @(#)procfs.h 8.9 (Berkeley) 5/14/95 * * From: - * $Id: procfs.h,v 1.25 1999/05/04 08:00:10 phk Exp $ + * $Id: procfs.h,v 1.26 1999/06/13 20:53:13 phk Exp $ */ /* @@ -51,6 +51,7 @@ typedef enum { Pmem, /* the process's memory image */ Pregs, /* the process's register set */ Pfpregs, /* the process's FP register set */ + Pdbregs, /* the process's debug register set */ Pctl, /* process control */ Pstatus, /* process status */ Pnote, /* process notifier */ @@ -124,6 +125,7 @@ vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); /* */ struct reg; struct fpreg; +struct dbreg; #define PFIND(pid) ((pid) ? pfind(pid) : &proc0) @@ -137,9 +139,12 @@ int procfs_read_regs __P((struct proc *, struct reg *)); int procfs_write_regs __P((struct proc *, struct reg *)); int procfs_read_fpregs __P((struct proc *, struct fpreg *)); int procfs_write_fpregs __P((struct proc *, struct fpreg *)); +int procfs_read_dbregs __P((struct proc *, struct dbreg *)); +int procfs_write_dbregs __P((struct proc *, struct dbreg *)); int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dodbregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); @@ -155,6 +160,7 @@ int procfs_kmemaccess __P((struct proc *)); int procfs_validfile __P((struct proc *)); int procfs_validfpregs __P((struct proc *)); int procfs_validregs __P((struct proc *)); +int procfs_validdbregs __P((struct proc *)); int procfs_validmap __P((struct proc *)); int procfs_validtype __P((struct proc *)); diff --git a/sys/miscfs/procfs/procfs_subr.c b/sys/miscfs/procfs/procfs_subr.c index 7b5e18c440d5..cf313e863856 100644 --- a/sys/miscfs/procfs/procfs_subr.c +++ b/sys/miscfs/procfs/procfs_subr.c @@ -36,7 +36,7 @@ * * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95 * - * $Id: procfs_subr.c,v 1.23 1999/01/27 22:42:07 dillon Exp $ + * $Id: procfs_subr.c,v 1.24 1999/04/30 13:04:21 phk Exp $ */ #include @@ -167,6 +167,7 @@ loop: case Pregs: case Pfpregs: + case Pdbregs: pfs->pfs_mode = (VREAD|VWRITE); vp->v_type = VREG; break; @@ -264,6 +265,10 @@ procfs_rw(ap) rtval = procfs_dofpregs(curp, p, pfs, uio); break; + case Pdbregs: + rtval = procfs_dodbregs(curp, p, pfs, uio); + break; + case Pctl: rtval = procfs_doctl(curp, p, pfs, uio); break; diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c index d421bac0e3b8..fc47353f62ce 100644 --- a/sys/miscfs/procfs/procfs_vnops.c +++ b/sys/miscfs/procfs/procfs_vnops.c @@ -36,7 +36,7 @@ * * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 * - * $Id: procfs_vnops.c,v 1.68 1999/05/04 08:01:55 phk Exp $ + * $Id: procfs_vnops.c,v 1.69 1999/06/13 20:53:16 phk Exp $ */ /* @@ -95,6 +95,7 @@ static struct proc_target { { DT_REG, N("mem"), Pmem, NULL }, { DT_REG, N("regs"), Pregs, procfs_validregs }, { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, + { DT_REG, N("dbregs"), Pdbregs, procfs_validdbregs }, { DT_REG, N("ctl"), Pctl, NULL }, { DT_REG, N("status"), Pstatus, NULL }, { DT_REG, N("note"), Pnote, NULL }, @@ -491,6 +492,7 @@ procfs_getattr(ap) case Pctl: case Pregs: case Pfpregs: + case Pdbregs: if (procp->p_flag & P_SUGID) vap->va_mode &= ~((VREAD|VWRITE)| ((VREAD|VWRITE)>>3)| @@ -571,6 +573,10 @@ procfs_getattr(ap) vap->va_bytes = vap->va_size = sizeof(struct fpreg); break; + case Pdbregs: + vap->va_bytes = vap->va_size = sizeof(struct dbreg); + break; + case Ptype: case Pmap: case Pctl: diff --git a/sys/powerpc/include/ptrace.h b/sys/powerpc/include/ptrace.h index ec3d5aab5ca5..2c43a2eef8d4 100644 --- a/sys/powerpc/include/ptrace.h +++ b/sys/powerpc/include/ptrace.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ptrace.h 8.1 (Berkeley) 6/11/93 - * $Id: ptrace.h,v 1.5 1997/02/22 09:35:03 peter Exp $ + * $Id: ptrace.h,v 1.6 1998/05/19 00:00:12 tegge Exp $ */ #ifndef _MACHINE_PTRACE_H_ @@ -44,6 +44,8 @@ #define PT_SETREGS (PT_FIRSTMACH + 2) #define PT_GETFPREGS (PT_FIRSTMACH + 3) #define PT_SETFPREGS (PT_FIRSTMACH + 4) +#define PT_GETDBREGS (PT_FIRSTMACH + 5) +#define PT_SETDBREGS (PT_FIRSTMACH + 6) #ifdef KERNEL int ptrace_read_u_check __P((struct proc *p, vm_offset_t off, size_t len));