1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-04 09:09:56 +00:00

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
This commit is contained in:
Brian S. Dean 2001-07-11 03:15:25 +00:00
parent 761d6b7150
commit 17bbfb5897
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=79573
9 changed files with 699 additions and 140 deletions

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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?
*/
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);
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<<2)) {
/* dr1 is enabled */
if (dbregs->dr1 >= 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<<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_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);
}

View File

@ -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 },

View File

@ -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");
}

View File

@ -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;

View File

@ -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");
}

View File

@ -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?
*/
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);
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<<2)) {
/* dr1 is enabled */
if (dbregs->dr1 >= 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<<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_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);
}

View File

@ -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;
}