diff options
-rw-r--r-- | sys/alpha/alpha/db_trace.c | 33 | ||||
-rw-r--r-- | sys/amd64/amd64/db_trace.c | 202 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 160 | ||||
-rw-r--r-- | sys/ddb/db_command.c | 2 | ||||
-rw-r--r-- | sys/ddb/db_watch.c | 45 | ||||
-rw-r--r-- | sys/ddb/ddb.h | 2 | ||||
-rw-r--r-- | sys/i386/i386/db_trace.c | 202 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 160 | ||||
-rw-r--r-- | sys/ia64/ia64/db_trace.c | 33 |
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; +} + |