Module Name: src
Committed By: kamil
Date: Wed Jan 18 05:12:00 UTC 2017
Modified Files:
src/sys/arch/amd64/amd64: trap.c
src/sys/arch/i386/i386: trap.c
src/sys/arch/x86/include: dbregs.h
src/sys/arch/x86/x86: dbregs.c
Log Message:
Embed hardware trap and its type that fired (x86), information for tracers
Now x86 throws SIGTRAP on hardware exception with:
- si_code TRAP_HWWPT - dedicated for hw assisted watchpoint interface
- si_trap - unchanged (T_TRCTRAP)
- si_trap2 - watchpoint number that fired
- si_trap3 - watchpoint specific event description
x86 returns in si_trap3 one of the field from <x86/dbregs.h>
- X86_HW_WATCHPOINT_EVENT_FIRED - watchpoint fired
- X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP - watchpoint fired under PT_STEP
Othe changes:
- restrict more code from <x86/dbregs.h> to _KERNEL
Sponsored bt <The NetBSD Foundation>
To generate a diff of this commit:
cvs rdiff -u -r1.88 -r1.89 src/sys/arch/amd64/amd64/trap.c
cvs rdiff -u -r1.281 -r1.282 src/sys/arch/i386/i386/trap.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/x86/include/dbregs.h
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/x86/dbregs.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/arch/amd64/amd64/trap.c
diff -u src/sys/arch/amd64/amd64/trap.c:1.88 src/sys/arch/amd64/amd64/trap.c:1.89
--- src/sys/arch/amd64/amd64/trap.c:1.88 Thu Dec 15 12:04:17 2016
+++ src/sys/arch/amd64/amd64/trap.c Wed Jan 18 05:11:59 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.88 2016/12/15 12:04:17 kamil Exp $ */
+/* $NetBSD: trap.c,v 1.89 2017/01/18 05:11:59 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.88 2016/12/15 12:04:17 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.89 2017/01/18 05:11:59 kamil Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@@ -230,7 +230,7 @@ trap(struct trapframe *frame)
#endif
ksiginfo_t ksi;
void *onfault;
- int type, error;
+ int type, error, wptnfo;
uint64_t cr2;
bool pfail;
@@ -706,7 +706,11 @@ faultcommon:
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGTRAP;
ksi.ksi_trap = type & ~T_USER;
- if (type == (T_BPTFLT|T_USER))
+ if ((wptnfo = user_trap_x86_hw_watchpoint())) {
+ ksi.ksi_code = TRAP_HWWPT;
+ ksi.ksi_trap2 = x86_hw_watchpoint_reg(wptnfo);
+ ksi.ksi_trap3 = x86_hw_watchpoint_type(wptnfo);
+ } else if (type == (T_BPTFLT|T_USER))
ksi.ksi_code = TRAP_BRKPT;
else
ksi.ksi_code = TRAP_TRACE;
Index: src/sys/arch/i386/i386/trap.c
diff -u src/sys/arch/i386/i386/trap.c:1.281 src/sys/arch/i386/i386/trap.c:1.282
--- src/sys/arch/i386/i386/trap.c:1.281 Tue Dec 13 10:54:27 2016
+++ src/sys/arch/i386/i386/trap.c Wed Jan 18 05:11:59 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.281 2016/12/13 10:54:27 kamil Exp $ */
+/* $NetBSD: trap.c,v 1.282 2017/01/18 05:11:59 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000, 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.281 2016/12/13 10:54:27 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.282 2017/01/18 05:11:59 kamil Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@@ -251,7 +251,7 @@ trap(struct trapframe *frame)
struct trapframe *vframe;
ksiginfo_t ksi;
void *onfault;
- int type, error;
+ int type, error, wptnfo;
uint32_t cr2;
bool pfail;
@@ -700,7 +700,11 @@ faultcommon:
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGTRAP;
ksi.ksi_trap = type & ~T_USER;
- if (type == (T_BPTFLT|T_USER))
+ if ((wptnfo = user_trap_x86_hw_watchpoint())) {
+ ksi.ksi_code = TRAP_HWWPT;
+ ksi.ksi_trap2 = x86_hw_watchpoint_reg(wptnfo);
+ ksi.ksi_trap3 = x86_hw_watchpoint_type(wptnfo);
+ } else if (type == (T_BPTFLT|T_USER))
ksi.ksi_code = TRAP_BRKPT;
else
ksi.ksi_code = TRAP_TRACE;
Index: src/sys/arch/x86/include/dbregs.h
diff -u src/sys/arch/x86/include/dbregs.h:1.2 src/sys/arch/x86/include/dbregs.h:1.3
--- src/sys/arch/x86/include/dbregs.h:1.2 Thu Dec 15 12:04:18 2016
+++ src/sys/arch/x86/include/dbregs.h Wed Jan 18 05:12:00 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: dbregs.h,v 1.2 2016/12/15 12:04:18 kamil Exp $ */
+/* $NetBSD: dbregs.h,v 1.3 2017/01/18 05:12:00 kamil Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
#ifndef _X86_DBREGS_H_
#define _X86_DBREGS_H_
-#if defined(_KMEMUSER) || defined(_KERNEL)
+#if defined(_KERNEL)
#include <sys/param.h>
#include <sys/types.h>
@@ -79,10 +79,10 @@
#define X86_HW_WATCHPOINT_DR7_DR3_CONDITION_MASK __BITS(28, 29)
#define X86_HW_WATCHPOINT_DR7_DR3_LENGTH_MASK __BITS(30, 31)
-#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+#endif /* !defined(_KERNEL) */
/*
- * X86_HW_WATCHPOINT_DR7_CONDITION_IO_READWRITE is unused
+ * X86_HW_WATCHPOINT_DR7_CONDITION_IO_READWRITE is currently unused
* it requires DE (debug extension) flag in control register CR4 set
* not all CPUs support it
*/
@@ -103,6 +103,15 @@ enum x86_hw_watchpoint_length {
X86_HW_WATCHPOINT_DR7_LENGTH_FOURBYTES = 0x3
};
+/*
+ * 0x2 is currently unimplemented - it reflects 8 bytes on modern CPUs
+ */
+enum x86_hw_watchpoint_event {
+ X86_HW_WATCHPOINT_EVENT_NONE = 0x0,
+ X86_HW_WATCHPOINT_EVENT_FIRED = 0x1,
+ X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP = 0x2,
+};
+
#if defined(_KMEMUSER) || defined(_KERNEL)
/*
@@ -122,6 +131,9 @@ struct x86_hw_watchpoint {
enum x86_hw_watchpoint_length length;
};
+#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+
+#if defined(_KERNEL)
/*
* Set CPU Debug Registers - to be used before entering user-land context
*/
@@ -134,11 +146,19 @@ void clear_x86_hw_watchpoints(void);
/*
* Check if trap is triggered from user-land if so return nonzero value
- *
- * This resets Debug Status Register (DR6) break point detection
*/
int user_trap_x86_hw_watchpoint(void);
-#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+/*
+ * Check if trap is triggered from user-land if so return nonzero value
+ */
+int x86_hw_watchpoint_type(int);
+
+/*
+ * Return register that fired
+ */
+int x86_hw_watchpoint_reg(int);
+
+#endif /* !defined(_KERNEL) */
#endif /* !_X86_DBREGS_H_ */
Index: src/sys/arch/x86/x86/dbregs.c
diff -u src/sys/arch/x86/x86/dbregs.c:1.1 src/sys/arch/x86/x86/dbregs.c:1.2
--- src/sys/arch/x86/x86/dbregs.c:1.1 Thu Dec 15 12:04:18 2016
+++ src/sys/arch/x86/x86/dbregs.c Wed Jan 18 05:12:00 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: dbregs.c,v 1.1 2016/12/15 12:04:18 kamil Exp $ */
+/* $NetBSD: dbregs.c,v 1.2 2017/01/18 05:12:00 kamil Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -150,14 +150,17 @@ clear_x86_hw_watchpoints(void)
X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED));
}
+/* Local temporary bitfield concept to compose event and register that fired */
+#define DR_EVENT_MASK __BITS(15,8)
+#define DR_REGISTER_MASK __BITS(7,0)
+
int
user_trap_x86_hw_watchpoint(void)
{
register_t dr7, dr6; /* debug registers dr6 and dr7 */
register_t bp; /* breakpoint bits extracted from dr6 */
- int nbp; /* number of breakpoints that triggered */
- vaddr_t addr[X86_HW_WATCHPOINTS]; /* breakpoint addresses */
- int i;
+ register_t dr; /* temporary value of dr0-dr3 */
+ int rv; /* register and event that fired (if any) */
dr7 = rdr7();
if ((dr7 &
@@ -173,7 +176,6 @@ user_trap_x86_hw_watchpoint(void)
return 0;
}
- nbp = 0;
dr6 = rdr6();
bp = dr6 & \
(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
@@ -190,41 +192,88 @@ user_trap_x86_hw_watchpoint(void)
}
/*
+ * Clear Status Register (DR6) now as it's not done by CPU.
+ *
+ * Clear BREAKPOINT_CONDITION_DETECTED and SINGLE_STEP bits and ignore
+ * the rest.
+ */
+ ldr6(dr6 &
+ ~(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_SINGLE_STEP));
+
+ /*
* at least one of the breakpoints were hit, check to see
* which ones and if any of them are user space addresses
*/
- if (bp & X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED)
- addr[nbp++] = (vaddr_t)rdr0();
- if (bp & X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED)
- addr[nbp++] = (vaddr_t)rdr1();
- if (bp & X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED)
- addr[nbp++] = (vaddr_t)rdr2();
- if (bp & X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED)
- addr[nbp++] = (vaddr_t)rdr3();
-
- for (i = 0; i < nbp; i++) {
- /* Check if addr[i] is in user space */
- if (addr[i] >= (vaddr_t)VM_MAXUSER_ADDRESS)
- continue;
+ if (bp & X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED) {
+ dr = rdr0();
+ if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+ rv = 0;
+ if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+ else
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+ return rv;
+ }
+
+ }
- /*
- * Clear Status Register (DR6) now as it's not done by CPU.
- *
- * Clear BREAKPOINT_CONDITION_DETECTED bits and ignore
- * the rest.
- */
- ldr6(dr6 &
- ~(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
- X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
- X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
- X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED));
+ if (bp & X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED) {
+ dr = rdr1();
+ if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+ rv = __SHIFTIN(1, DR_REGISTER_MASK);
+ if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+ else
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+ return rv;
+ }
+
+ }
- return nbp;
+ if (bp & X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED) {
+ dr = rdr2();
+ if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+ rv = __SHIFTIN(2, DR_REGISTER_MASK);
+ if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+ else
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+ return rv;
+ }
+
+ }
+
+ if (bp & X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED) {
+ dr = rdr3();
+ if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+ rv = __SHIFTIN(3, DR_REGISTER_MASK);
+ if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+ else
+ rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+ return rv;
+ }
+
}
- /*
- * None of the breakpoints are in user space.
- */
return 0;
}
+
+int
+x86_hw_watchpoint_type(int wptnfo)
+{
+
+ return __SHIFTOUT(wptnfo, DR_EVENT_MASK);
+}
+
+int
+x86_hw_watchpoint_reg(int wptnfo)
+{
+
+ return __SHIFTOUT(wptnfo, DR_REGISTER_MASK);
+}