summaryrefslogtreecommitdiffstats
path: root/sys/amd64/amd64
diff options
context:
space:
mode:
authorbsd <bsd@FreeBSD.org>2000-02-20 20:51:23 +0000
committerbsd <bsd@FreeBSD.org>2000-02-20 20:51:23 +0000
commit85f1c223b39c92c49e8b7c6c7ad39d3e42a27574 (patch)
tree24b3d3119a30ef55034eb6483b006f39f272b986 /sys/amd64/amd64
parent5e5e3ebba622666325b5191546c69ed7f00a5781 (diff)
downloadFreeBSD-src-85f1c223b39c92c49e8b7c6c7ad39d3e42a27574.zip
FreeBSD-src-85f1c223b39c92c49e8b7c6c7ad39d3e42a27574.tar.gz
Don't forget to reset the hardware debug registers when a process that
was using them exits. Don't allow a user process to cause the kernel to take a TRCTRAP on a user space address. Reviewed by: jlemon, sef Approved by: jkh
Diffstat (limited to 'sys/amd64/amd64')
-rw-r--r--sys/amd64/amd64/machdep.c70
-rw-r--r--sys/amd64/amd64/support.S17
-rw-r--r--sys/amd64/amd64/support.s17
-rw-r--r--sys/amd64/amd64/trap.c20
-rw-r--r--sys/amd64/amd64/vm_machdep.c7
5 files changed, 130 insertions, 1 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 397efdc..1efc7e4 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -2239,6 +2239,76 @@ set_dbregs(p, dbregs)
return (0);
}
+/*
+ * Return > 0 if a hardware breakpoint has been hit, and the
+ * breakpoint was in user space. Return 0, otherwise.
+ */
+int
+user_dbreg_trap(void)
+{
+ u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */
+ u_int32_t bp; /* breakpoint bits extracted from dr6 */
+ int nbp; /* number of breakpoints that triggered */
+ caddr_t addr[4]; /* breakpoint addresses */
+ int i;
+
+ dr7 = rdr7();
+ if ((dr7 & 0x000000ff) == 0) {
+ /*
+ * all GE and LE bits in the dr7 register are zero,
+ * thus the trap couldn't have been caused by the
+ * hardware debug registers
+ */
+ return 0;
+ }
+
+ nbp = 0;
+ dr6 = rdr6();
+ bp = dr6 & 0x0000000f;
+
+ if (!bp) {
+ /*
+ * None of the breakpoint bits are set meaning this
+ * trap was not caused by any of the debug registers
+ */
+ return 0;
+ }
+
+ /*
+ * at least one of the breakpoints were hit, check to see
+ * which ones and if any of them are user space addresses
+ */
+
+ if (bp & 0x01) {
+ addr[nbp++] = (caddr_t)rdr0();
+ }
+ if (bp & 0x02) {
+ addr[nbp++] = (caddr_t)rdr1();
+ }
+ if (bp & 0x04) {
+ addr[nbp++] = (caddr_t)rdr2();
+ }
+ if (bp & 0x08) {
+ addr[nbp++] = (caddr_t)rdr3();
+ }
+
+ for (i=0; i<nbp; i++) {
+ if (addr[i] <
+ (caddr_t)VM_MAXUSER_ADDRESS) {
+ /*
+ * addr[i] is in user space
+ */
+ return nbp;
+ }
+ }
+
+ /*
+ * None of the breakpoints are in user space.
+ */
+ return 0;
+}
+
+
#ifndef DDB
void
Debugger(const char *msg)
diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S
index ae99af9..394848c 100644
--- a/sys/amd64/amd64/support.S
+++ b/sys/amd64/amd64/support.S
@@ -1586,6 +1586,23 @@ ENTRY(load_cr4)
movl %eax,%cr4
ret
+/* void load_dr6(u_int dr6) */
+ENTRY(load_dr6)
+ movl 4(%esp),%eax
+ movl %eax,%dr6
+ ret
+
+/* void reset_dbregs() */
+ENTRY(reset_dbregs)
+ movl $0,%eax
+ movl %eax,%dr7 /* disable all breapoints first */
+ movl %eax,%dr0
+ movl %eax,%dr1
+ movl %eax,%dr2
+ movl %eax,%dr3
+ movl %eax,%dr6
+ ret
+
/*****************************************************************************/
/* setjump, longjump */
/*****************************************************************************/
diff --git a/sys/amd64/amd64/support.s b/sys/amd64/amd64/support.s
index ae99af9..394848c 100644
--- a/sys/amd64/amd64/support.s
+++ b/sys/amd64/amd64/support.s
@@ -1586,6 +1586,23 @@ ENTRY(load_cr4)
movl %eax,%cr4
ret
+/* void load_dr6(u_int dr6) */
+ENTRY(load_dr6)
+ movl 4(%esp),%eax
+ movl %eax,%dr6
+ ret
+
+/* void reset_dbregs() */
+ENTRY(reset_dbregs)
+ movl $0,%eax
+ movl %eax,%dr7 /* disable all breapoints first */
+ movl %eax,%dr0
+ movl %eax,%dr1
+ movl %eax,%dr2
+ movl %eax,%dr3
+ movl %eax,%dr6
+ ret
+
/*****************************************************************************/
/* setjump, longjump */
/*****************************************************************************/
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 4199346..a8b73cf 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -519,8 +519,26 @@ kernel_trap:
frame.tf_eflags &= ~PSL_T;
return;
}
+ /*
+ * Ignore debug register trace traps due to
+ * accesses in the user's address space, which
+ * can happen under several conditions such as
+ * if a user sets a watchpoint on a buffer and
+ * then passes that buffer to a system call.
+ * We still want to get TRCTRAPS for addresses
+ * in kernel space because that is useful when
+ * debugging the kernel.
+ */
+ if (user_dbreg_trap()) {
+ /*
+ * Reset breakpoint bits because the
+ * processor doesn't
+ */
+ load_dr6(rdr6() & 0xfffffff0);
+ return;
+ }
/*
- * Fall through.
+ * Fall through (TRCTRAP kernel mode, kernel address)
*/
case T_BPTFLT:
/*
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index d7fa73b1..cdcc278 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -246,6 +246,13 @@ cpu_exit(p)
#ifdef USER_LDT
user_ldt_free(pcb);
#endif
+ if (pcb->pcb_flags & PCB_DBREGS) {
+ /*
+ * disable all hardware breakpoints
+ */
+ reset_dbregs();
+ pcb->pcb_flags &= ~PCB_DBREGS;
+ }
cnt.v_swtch++;
cpu_switch(p);
panic("cpu_exit");
OpenPOWER on IntegriCloud