summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbsd <bsd@FreeBSD.org>2001-07-11 03:15:25 +0000
committerbsd <bsd@FreeBSD.org>2001-07-11 03:15:25 +0000
commit17eb1bfcbf757a1739adfbf5d0fb91b10212a882 (patch)
tree52fdc5e25b5fc104fbb4ec3a396a3c44576aff14
parent0d42a4ee81d7081c6b0b32ccde9c7a4ec2b90f50 (diff)
downloadFreeBSD-src-17eb1bfcbf757a1739adfbf5d0fb91b10212a882.zip
FreeBSD-src-17eb1bfcbf757a1739adfbf5d0fb91b10212a882.tar.gz
Add 'hwatch' and 'dhwatch' ddb commands analogous to 'watch' and
'dwatch'. The new commands install hardware watchpoints if supported by the architecture and if there are enough registers to cover the desired memory area. No objection by: audit@, hackers@ MFC after: 2 weeks
-rw-r--r--sys/alpha/alpha/db_trace.c33
-rw-r--r--sys/amd64/amd64/db_trace.c202
-rw-r--r--sys/amd64/amd64/machdep.c160
-rw-r--r--sys/ddb/db_command.c2
-rw-r--r--sys/ddb/db_watch.c45
-rw-r--r--sys/ddb/ddb.h2
-rw-r--r--sys/i386/i386/db_trace.c202
-rw-r--r--sys/i386/i386/machdep.c160
-rw-r--r--sys/ia64/ia64/db_trace.c33
9 files changed, 699 insertions, 140 deletions
diff --git a/sys/alpha/alpha/db_trace.c b/sys/alpha/alpha/db_trace.c
index c522379..c743926 100644
--- a/sys/alpha/alpha/db_trace.c
+++ b/sys/alpha/alpha/db_trace.c
@@ -96,6 +96,12 @@ static struct special_symbol {
{ NULL }
};
+
+int db_md_set_watchpoint __P((db_expr_t addr, db_expr_t size));
+int db_md_clr_watchpoint __P((db_expr_t addr, db_expr_t size));
+void db_md_list_watchpoints __P((void));
+
+
/*
* Decode the function prologue for the function we're in, and note
* which registers are stored where, and how large the stack frame is.
@@ -367,3 +373,30 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
frame += pi.pi_frame_size;
}
}
+
+
+
+int
+db_md_set_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ return (-1);
+}
+
+
+int
+db_md_clr_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ return (-1);
+}
+
+
+void
+db_md_list_watchpoints()
+{
+ return;
+}
+
diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c
index a861d16..dc1e2f0 100644
--- a/sys/amd64/amd64/db_trace.c
+++ b/sys/amd64/amd64/db_trace.c
@@ -34,6 +34,8 @@
#include <sys/user.h>
#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/reg.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -107,6 +109,16 @@ static int db_numargs __P((struct i386_frame *));
static void db_print_stack_entry __P((const char *, int, char **, int *, db_addr_t));
static void decode_syscall __P((int, struct proc *));
+
+static char * watchtype_str __P((int type));
+int i386_set_watch __P((int watchnum, unsigned int watchaddr,
+ int size, int access, struct dbreg * d));
+int i386_clr_watch __P((int watchnum, struct dbreg * d));
+int db_md_set_watchpoint __P((db_expr_t addr, db_expr_t size));
+int db_md_clr_watchpoint __P((db_expr_t addr, db_expr_t size));
+void db_md_list_watchpoints __P((void));
+
+
/*
* Figure out how many arguments were passed into the frame at "fp".
*/
@@ -427,7 +439,7 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
}
}
-#define DB_DRX_FUNC(reg) \
+#define DB_DRX_FUNC(reg) \
int \
db_ ## reg (vp, valuep, op) \
struct db_variable *vp; \
@@ -450,3 +462,191 @@ DB_DRX_FUNC(dr4)
DB_DRX_FUNC(dr5)
DB_DRX_FUNC(dr6)
DB_DRX_FUNC(dr7)
+
+
+
+int
+i386_set_watch(watchnum, watchaddr, size, access, d)
+ int watchnum;
+ unsigned int watchaddr;
+ int size;
+ int access;
+ struct dbreg * d;
+{
+ int i;
+ unsigned int mask;
+
+ if (watchnum == -1) {
+ for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
+ if ((d->dr7 & mask) == 0)
+ break;
+ if (i < 4)
+ watchnum = i;
+ else
+ return (-1);
+ }
+
+ switch (access) {
+ case DBREG_DR7_EXEC:
+ size = 1; /* size must be 1 for an execution breakpoint */
+ /* fall through */
+ case DBREG_DR7_WRONLY:
+ case DBREG_DR7_RDWR:
+ break;
+ default : return (-1); break;
+ }
+
+ /*
+ * we can watch a 1, 2, or 4 byte sized location
+ */
+ switch (size) {
+ case 1 : mask = 0x00; break;
+ case 2 : mask = 0x01 << 2; break;
+ case 4 : mask = 0x03 << 2; break;
+ default : return (-1); break;
+ }
+
+ mask |= access;
+
+ /* clear the bits we are about to affect */
+ d->dr7 &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
+
+ /* set drN register to the address, N=watchnum */
+ DBREG_DRX(d,watchnum) = watchaddr;
+
+ /* enable the watchpoint */
+ d->dr7 |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16));
+
+ return (watchnum);
+}
+
+
+int
+i386_clr_watch(watchnum, d)
+ int watchnum;
+ struct dbreg * d;
+{
+
+ if (watchnum < 0 || watchnum >= 4)
+ return (-1);
+
+ d->dr7 = d->dr7 & ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
+ DBREG_DRX(d,watchnum) = 0;
+
+ return (0);
+}
+
+
+int
+db_md_set_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ int avail, wsize;
+ int i;
+ struct dbreg d;
+
+ fill_dbregs(NULL, &d);
+
+ avail = 0;
+ for(i=0; i<4; i++) {
+ if ((d.dr7 & (3 << (i*2))) == 0)
+ avail++;
+ }
+
+ if (avail*4 < size)
+ return (-1);
+
+ for (i=0; i<4 && (size != 0); i++) {
+ if ((d.dr7 & (3<<(i*2))) == 0) {
+ if (size > 4)
+ wsize = 4;
+ else
+ wsize = size;
+ if (wsize == 3)
+ wsize++;
+ i386_set_watch(i, addr, wsize,
+ DBREG_DR7_WRONLY, &d);
+ addr += wsize;
+ size -= wsize;
+ }
+ }
+
+ set_dbregs(NULL, &d);
+
+ return(0);
+}
+
+
+int
+db_md_clr_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ int i;
+ struct dbreg d;
+
+ fill_dbregs(NULL, &d);
+
+ for(i=0; i<4; i++) {
+ if (d.dr7 & (3 << (i*2))) {
+ if ((DBREG_DRX((&d), i) >= addr) &&
+ (DBREG_DRX((&d), i) < addr+size))
+ i386_clr_watch(i, &d);
+
+ }
+ }
+
+ set_dbregs(NULL, &d);
+
+ return(0);
+}
+
+
+static
+char *
+watchtype_str(type)
+ int type;
+{
+ switch (type) {
+ case DBREG_DR7_EXEC : return "execute"; break;
+ case DBREG_DR7_RDWR : return "read/write"; break;
+ case DBREG_DR7_WRONLY : return "write"; break;
+ default : return "invalid"; break;
+ }
+}
+
+
+void
+db_md_list_watchpoints()
+{
+ int i;
+ struct dbreg d;
+
+ fill_dbregs(NULL, &d);
+
+ db_printf("\nhardware watchpoints:\n");
+ db_printf(" watch status type len address\n"
+ " ----- -------- ---------- --- ----------\n");
+ for (i=0; i<4; i++) {
+ if (d.dr7 & (0x03 << (i*2))) {
+ unsigned type, len;
+ type = (d.dr7 >> (16+(i*4))) & 3;
+ len = (d.dr7 >> (16+(i*4)+2)) & 3;
+ db_printf(" %-5d %-8s %10s %3d 0x%08x\n",
+ i, "enabled", watchtype_str(type),
+ len+1, DBREG_DRX((&d),i));
+ }
+ else {
+ db_printf(" %-5d disabled\n", i);
+ }
+ }
+
+ db_printf("\ndebug register values:\n");
+ for (i=0; i<8; i++) {
+ db_printf(" dr%d 0x%08x\n", i, DBREG_DRX((&d),i));
+ }
+ db_printf("\n");
+}
+
+
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 9ee7bfc..544aff5 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -2186,15 +2186,27 @@ fill_dbregs(p, 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;
+ if (p == NULL) {
+ dbregs->dr0 = rdr0();
+ dbregs->dr1 = rdr1();
+ dbregs->dr2 = rdr2();
+ dbregs->dr3 = rdr3();
+ dbregs->dr4 = rdr4();
+ dbregs->dr5 = rdr5();
+ dbregs->dr6 = rdr6();
+ dbregs->dr7 = rdr7();
+ }
+ else {
+ 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);
}
@@ -2207,74 +2219,84 @@ set_dbregs(p, dbregs)
int i;
u_int32_t mask1, mask2;
- /*
- * Don't let an illegal value for dr7 get set. Specifically,
- * check for undefined settings. Setting these bit patterns
- * result in undefined behaviour and can lead to an unexpected
- * TRCTRAP.
- */
- for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8;
- i++, mask1 <<= 2, mask2 <<= 2)
- if ((dbregs->dr7 & mask1) == mask2)
+ if (p == NULL) {
+ load_dr0(dbregs->dr0);
+ load_dr1(dbregs->dr1);
+ load_dr2(dbregs->dr2);
+ load_dr3(dbregs->dr3);
+ load_dr4(dbregs->dr4);
+ load_dr5(dbregs->dr5);
+ load_dr6(dbregs->dr6);
+ load_dr7(dbregs->dr7);
+ }
+ else {
+ /*
+ * Don't let an illegal value for dr7 get set. Specifically,
+ * check for undefined settings. Setting these bit patterns
+ * result in undefined behaviour and can lead to an unexpected
+ * TRCTRAP.
+ */
+ for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8;
+ i++, mask1 <<= 2, mask2 <<= 2)
+ if ((dbregs->dr7 & mask1) == mask2)
+ return (EINVAL);
+
+ if (dbregs->dr7 & 0x0000fc00)
return (EINVAL);
- if (dbregs->dr7 & 0x0000fc00)
- return (EINVAL);
-
-
-
- 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 (suser(p) != 0) {
- if (dbregs->dr7 & 0x3) {
- /* dr0 is enabled */
- if (dbregs->dr0 >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
+ 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 (dbregs->dr7 & (0x3<<2)) {
- /* dr1 is enabled */
- if (dbregs->dr1 >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
+ if (suser(p) != 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);
+ }
}
- if (dbregs->dr7 & (0x3<<4)) {
- /* dr2 is enabled */
- if (dbregs->dr2 >= 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;
- if (dbregs->dr7 & (0x3<<6)) {
- /* dr3 is enabled */
- if (dbregs->dr3 >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
+ pcb->pcb_flags |= PCB_DBREGS;
}
- 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);
}
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
index 64cad7e..dfcc9c3 100644
--- a/sys/ddb/db_command.c
+++ b/sys/ddb/db_command.c
@@ -401,6 +401,8 @@ static struct command db_command_table[] = {
{ "break", db_breakpoint_cmd, 0, 0 },
{ "dwatch", db_deletewatch_cmd, 0, 0 },
{ "watch", db_watchpoint_cmd, CS_MORE,0 },
+ { "dhwatch", db_deletehwatch_cmd, 0, 0 },
+ { "hwatch", db_hwatchpoint_cmd, 0, 0 },
{ "step", db_single_step_cmd, 0, 0 },
{ "s", db_single_step_cmd, 0, 0 },
{ "continue", db_continue_cmd, 0, 0 },
diff --git a/sys/ddb/db_watch.c b/sys/ddb/db_watch.c
index 079013a..abfb853 100644
--- a/sys/ddb/db_watch.c
+++ b/sys/ddb/db_watch.c
@@ -67,6 +67,10 @@ static void db_list_watchpoints __P((void));
static void db_set_watchpoint __P((vm_map_t map, db_addr_t addr,
vm_size_t size));
+int db_md_set_watchpoint __P((db_expr_t addr, db_expr_t size));
+int db_md_clr_watchpoint __P((db_expr_t addr, db_expr_t size));
+void db_md_list_watchpoints __P((void));
+
db_watchpoint_t
db_watchpoint_alloc()
@@ -220,6 +224,7 @@ db_watchpoint_cmd(addr, have_addr, count, modif)
DB_SHOW_COMMAND(watches, db_listwatch_cmd)
{
db_list_watchpoints();
+ db_md_list_watchpoints();
}
void
@@ -282,3 +287,43 @@ db_find_watchpoint(map, addr, regs)
return (FALSE);
}
#endif
+
+
+
+/* Delete hardware watchpoint */
+/*ARGSUSED*/
+void
+db_deletehwatch_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ boolean_t have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ int rc;
+
+ if (count < 0)
+ count = 4;
+
+ rc = db_md_clr_watchpoint(addr, count);
+ if (rc < 0)
+ db_printf("hardware watchpoint could not be deleted\n");
+}
+
+/* Set hardware watchpoint */
+/*ARGSUSED*/
+void
+db_hwatchpoint_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ boolean_t have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ int rc;
+
+ if (count < 0)
+ count = 4;
+
+ rc = db_md_set_watchpoint(addr, count);
+ if (rc < 0)
+ db_printf("hardware watchpoint could not be set\n");
+}
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
index 972772f..df602d0 100644
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -109,8 +109,10 @@ void kdb_init __P((void));
db_cmdfcn_t db_breakpoint_cmd;
db_cmdfcn_t db_continue_cmd;
db_cmdfcn_t db_delete_cmd;
+db_cmdfcn_t db_deletehwatch_cmd;
db_cmdfcn_t db_deletewatch_cmd;
db_cmdfcn_t db_examine_cmd;
+db_cmdfcn_t db_hwatchpoint_cmd;
db_cmdfcn_t db_listbreak_cmd;
db_cmdfcn_t db_print_cmd;
db_cmdfcn_t db_ps;
diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c
index a861d16..dc1e2f0 100644
--- a/sys/i386/i386/db_trace.c
+++ b/sys/i386/i386/db_trace.c
@@ -34,6 +34,8 @@
#include <sys/user.h>
#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/reg.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -107,6 +109,16 @@ static int db_numargs __P((struct i386_frame *));
static void db_print_stack_entry __P((const char *, int, char **, int *, db_addr_t));
static void decode_syscall __P((int, struct proc *));
+
+static char * watchtype_str __P((int type));
+int i386_set_watch __P((int watchnum, unsigned int watchaddr,
+ int size, int access, struct dbreg * d));
+int i386_clr_watch __P((int watchnum, struct dbreg * d));
+int db_md_set_watchpoint __P((db_expr_t addr, db_expr_t size));
+int db_md_clr_watchpoint __P((db_expr_t addr, db_expr_t size));
+void db_md_list_watchpoints __P((void));
+
+
/*
* Figure out how many arguments were passed into the frame at "fp".
*/
@@ -427,7 +439,7 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
}
}
-#define DB_DRX_FUNC(reg) \
+#define DB_DRX_FUNC(reg) \
int \
db_ ## reg (vp, valuep, op) \
struct db_variable *vp; \
@@ -450,3 +462,191 @@ DB_DRX_FUNC(dr4)
DB_DRX_FUNC(dr5)
DB_DRX_FUNC(dr6)
DB_DRX_FUNC(dr7)
+
+
+
+int
+i386_set_watch(watchnum, watchaddr, size, access, d)
+ int watchnum;
+ unsigned int watchaddr;
+ int size;
+ int access;
+ struct dbreg * d;
+{
+ int i;
+ unsigned int mask;
+
+ if (watchnum == -1) {
+ for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
+ if ((d->dr7 & mask) == 0)
+ break;
+ if (i < 4)
+ watchnum = i;
+ else
+ return (-1);
+ }
+
+ switch (access) {
+ case DBREG_DR7_EXEC:
+ size = 1; /* size must be 1 for an execution breakpoint */
+ /* fall through */
+ case DBREG_DR7_WRONLY:
+ case DBREG_DR7_RDWR:
+ break;
+ default : return (-1); break;
+ }
+
+ /*
+ * we can watch a 1, 2, or 4 byte sized location
+ */
+ switch (size) {
+ case 1 : mask = 0x00; break;
+ case 2 : mask = 0x01 << 2; break;
+ case 4 : mask = 0x03 << 2; break;
+ default : return (-1); break;
+ }
+
+ mask |= access;
+
+ /* clear the bits we are about to affect */
+ d->dr7 &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
+
+ /* set drN register to the address, N=watchnum */
+ DBREG_DRX(d,watchnum) = watchaddr;
+
+ /* enable the watchpoint */
+ d->dr7 |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16));
+
+ return (watchnum);
+}
+
+
+int
+i386_clr_watch(watchnum, d)
+ int watchnum;
+ struct dbreg * d;
+{
+
+ if (watchnum < 0 || watchnum >= 4)
+ return (-1);
+
+ d->dr7 = d->dr7 & ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
+ DBREG_DRX(d,watchnum) = 0;
+
+ return (0);
+}
+
+
+int
+db_md_set_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ int avail, wsize;
+ int i;
+ struct dbreg d;
+
+ fill_dbregs(NULL, &d);
+
+ avail = 0;
+ for(i=0; i<4; i++) {
+ if ((d.dr7 & (3 << (i*2))) == 0)
+ avail++;
+ }
+
+ if (avail*4 < size)
+ return (-1);
+
+ for (i=0; i<4 && (size != 0); i++) {
+ if ((d.dr7 & (3<<(i*2))) == 0) {
+ if (size > 4)
+ wsize = 4;
+ else
+ wsize = size;
+ if (wsize == 3)
+ wsize++;
+ i386_set_watch(i, addr, wsize,
+ DBREG_DR7_WRONLY, &d);
+ addr += wsize;
+ size -= wsize;
+ }
+ }
+
+ set_dbregs(NULL, &d);
+
+ return(0);
+}
+
+
+int
+db_md_clr_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ int i;
+ struct dbreg d;
+
+ fill_dbregs(NULL, &d);
+
+ for(i=0; i<4; i++) {
+ if (d.dr7 & (3 << (i*2))) {
+ if ((DBREG_DRX((&d), i) >= addr) &&
+ (DBREG_DRX((&d), i) < addr+size))
+ i386_clr_watch(i, &d);
+
+ }
+ }
+
+ set_dbregs(NULL, &d);
+
+ return(0);
+}
+
+
+static
+char *
+watchtype_str(type)
+ int type;
+{
+ switch (type) {
+ case DBREG_DR7_EXEC : return "execute"; break;
+ case DBREG_DR7_RDWR : return "read/write"; break;
+ case DBREG_DR7_WRONLY : return "write"; break;
+ default : return "invalid"; break;
+ }
+}
+
+
+void
+db_md_list_watchpoints()
+{
+ int i;
+ struct dbreg d;
+
+ fill_dbregs(NULL, &d);
+
+ db_printf("\nhardware watchpoints:\n");
+ db_printf(" watch status type len address\n"
+ " ----- -------- ---------- --- ----------\n");
+ for (i=0; i<4; i++) {
+ if (d.dr7 & (0x03 << (i*2))) {
+ unsigned type, len;
+ type = (d.dr7 >> (16+(i*4))) & 3;
+ len = (d.dr7 >> (16+(i*4)+2)) & 3;
+ db_printf(" %-5d %-8s %10s %3d 0x%08x\n",
+ i, "enabled", watchtype_str(type),
+ len+1, DBREG_DRX((&d),i));
+ }
+ else {
+ db_printf(" %-5d disabled\n", i);
+ }
+ }
+
+ db_printf("\ndebug register values:\n");
+ for (i=0; i<8; i++) {
+ db_printf(" dr%d 0x%08x\n", i, DBREG_DRX((&d),i));
+ }
+ db_printf("\n");
+}
+
+
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 9ee7bfc..544aff5 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -2186,15 +2186,27 @@ fill_dbregs(p, 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;
+ if (p == NULL) {
+ dbregs->dr0 = rdr0();
+ dbregs->dr1 = rdr1();
+ dbregs->dr2 = rdr2();
+ dbregs->dr3 = rdr3();
+ dbregs->dr4 = rdr4();
+ dbregs->dr5 = rdr5();
+ dbregs->dr6 = rdr6();
+ dbregs->dr7 = rdr7();
+ }
+ else {
+ 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);
}
@@ -2207,74 +2219,84 @@ set_dbregs(p, dbregs)
int i;
u_int32_t mask1, mask2;
- /*
- * Don't let an illegal value for dr7 get set. Specifically,
- * check for undefined settings. Setting these bit patterns
- * result in undefined behaviour and can lead to an unexpected
- * TRCTRAP.
- */
- for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8;
- i++, mask1 <<= 2, mask2 <<= 2)
- if ((dbregs->dr7 & mask1) == mask2)
+ if (p == NULL) {
+ load_dr0(dbregs->dr0);
+ load_dr1(dbregs->dr1);
+ load_dr2(dbregs->dr2);
+ load_dr3(dbregs->dr3);
+ load_dr4(dbregs->dr4);
+ load_dr5(dbregs->dr5);
+ load_dr6(dbregs->dr6);
+ load_dr7(dbregs->dr7);
+ }
+ else {
+ /*
+ * Don't let an illegal value for dr7 get set. Specifically,
+ * check for undefined settings. Setting these bit patterns
+ * result in undefined behaviour and can lead to an unexpected
+ * TRCTRAP.
+ */
+ for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8;
+ i++, mask1 <<= 2, mask2 <<= 2)
+ if ((dbregs->dr7 & mask1) == mask2)
+ return (EINVAL);
+
+ if (dbregs->dr7 & 0x0000fc00)
return (EINVAL);
- if (dbregs->dr7 & 0x0000fc00)
- return (EINVAL);
-
-
-
- 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 (suser(p) != 0) {
- if (dbregs->dr7 & 0x3) {
- /* dr0 is enabled */
- if (dbregs->dr0 >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
+ 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 (dbregs->dr7 & (0x3<<2)) {
- /* dr1 is enabled */
- if (dbregs->dr1 >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
+ if (suser(p) != 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);
+ }
}
- if (dbregs->dr7 & (0x3<<4)) {
- /* dr2 is enabled */
- if (dbregs->dr2 >= 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;
- if (dbregs->dr7 & (0x3<<6)) {
- /* dr3 is enabled */
- if (dbregs->dr3 >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
+ pcb->pcb_flags |= PCB_DBREGS;
}
- 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);
}
diff --git a/sys/ia64/ia64/db_trace.c b/sys/ia64/ia64/db_trace.c
index e30e340..3fc7909 100644
--- a/sys/ia64/ia64/db_trace.c
+++ b/sys/ia64/ia64/db_trace.c
@@ -36,6 +36,12 @@
#include <ddb/db_variables.h>
#include <ddb/db_output.h>
+
+int db_md_set_watchpoint __P((db_expr_t addr, db_expr_t size));
+int db_md_clr_watchpoint __P((db_expr_t addr, db_expr_t size));
+void db_md_list_watchpoints __P((void));
+
+
void
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif)
{
@@ -99,3 +105,30 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
break;
}
}
+
+
+
+int
+db_md_set_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ return (-1);
+}
+
+
+int
+db_md_clr_watchpoint(addr, size)
+ db_expr_t addr;
+ db_expr_t size;
+{
+ return (-1);
+}
+
+
+void
+db_md_list_watchpoints()
+{
+ return;
+}
+
OpenPOWER on IntegriCloud