Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/db_trace.c
Show First 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | |||||
#define DOUBLE_FAULT 4 | #define DOUBLE_FAULT 4 | ||||
static void db_nextframe(struct i386_frame **, db_addr_t *, struct thread *); | static void db_nextframe(struct i386_frame **, db_addr_t *, struct thread *); | ||||
static int db_numargs(struct i386_frame *); | static int db_numargs(struct i386_frame *); | ||||
static void db_print_stack_entry(const char *, int, char **, int *, db_addr_t, | static void db_print_stack_entry(const char *, int, char **, int *, db_addr_t, | ||||
void *); | void *); | ||||
static void decode_syscall(int, struct thread *); | static void decode_syscall(int, struct thread *); | ||||
static const char * watchtype_str(int type); | |||||
int i386_set_watch(int watchnum, unsigned int watchaddr, int size, int access, | |||||
struct dbreg *d); | |||||
int i386_clr_watch(int watchnum, struct dbreg *d); | |||||
/* | /* | ||||
* Figure out how many arguments were passed into the frame at "fp". | * Figure out how many arguments were passed into the frame at "fp". | ||||
*/ | */ | ||||
static int | static int | ||||
db_numargs(fp) | db_numargs(fp) | ||||
struct i386_frame *fp; | struct i386_frame *fp; | ||||
{ | { | ||||
char *argp; | char *argp; | ||||
▲ Show 20 Lines • Show All 399 Lines • ▼ Show 20 Lines | db_trace_thread(struct thread *thr, int count) | ||||
ctx = kdb_thr_ctx(thr); | ctx = kdb_thr_ctx(thr); | ||||
tf = thr == kdb_thread ? kdb_frame : NULL; | tf = thr == kdb_thread ? kdb_frame : NULL; | ||||
return (db_backtrace(thr, tf, (struct i386_frame *)ctx->pcb_ebp, | return (db_backtrace(thr, tf, (struct i386_frame *)ctx->pcb_ebp, | ||||
ctx->pcb_eip, ctx->pcb_esp, count)); | ctx->pcb_eip, ctx->pcb_esp, count)); | ||||
} | } | ||||
int | int | ||||
i386_set_watch(watchnum, watchaddr, size, access, d) | db_md_set_watchpoint(db_expr_t addr, db_expr_t size) | ||||
int watchnum; | |||||
unsigned int watchaddr; | |||||
int size; | |||||
int access; | |||||
struct dbreg *d; | |||||
{ | { | ||||
int i, len; | |||||
if (watchnum == -1) { | return (dbreg_set_watchpoint((vm_offset_t)addr, (vm_size_t)size)); | ||||
for (i = 0; i < 4; i++) | |||||
if (!DBREG_DR7_ENABLED(d->dr[7], i)) | |||||
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); | |||||
} | |||||
/* | |||||
* we can watch a 1, 2, or 4 byte sized location | |||||
*/ | |||||
switch (size) { | |||||
case 1: | |||||
len = DBREG_DR7_LEN_1; | |||||
break; | |||||
case 2: | |||||
len = DBREG_DR7_LEN_2; | |||||
break; | |||||
case 4: | |||||
len = DBREG_DR7_LEN_4; | |||||
break; | |||||
default: | |||||
return (-1); | |||||
} | |||||
/* clear the bits we are about to affect */ | |||||
d->dr[7] &= ~DBREG_DR7_MASK(watchnum); | |||||
/* set drN register to the address, N=watchnum */ | |||||
DBREG_DRX(d, watchnum) = watchaddr; | |||||
/* enable the watchpoint */ | |||||
d->dr[7] |= DBREG_DR7_SET(watchnum, len, access, | |||||
DBREG_DR7_GLOBAL_ENABLE); | |||||
return (watchnum); | |||||
} | |||||
int | int | ||||
i386_clr_watch(watchnum, d) | db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) | ||||
int watchnum; | |||||
struct dbreg *d; | |||||
{ | { | ||||
if (watchnum < 0 || watchnum >= 4) | return (dbreg_clr_watchpoint((vm_offset_t)addr, (vm_size_t)size)); | ||||
return (-1); | |||||
d->dr[7] &= ~DBREG_DR7_MASK(watchnum); | |||||
DBREG_DRX(d, watchnum) = 0; | |||||
return (0); | |||||
} | } | ||||
int | |||||
db_md_set_watchpoint(addr, size) | |||||
db_expr_t addr; | |||||
db_expr_t size; | |||||
{ | |||||
struct dbreg d; | |||||
int avail, i, wsize; | |||||
fill_dbregs(NULL, &d); | |||||
avail = 0; | |||||
for(i = 0; i < 4; i++) { | |||||
if (!DBREG_DR7_ENABLED(d.dr[7], i)) | |||||
avail++; | |||||
} | |||||
if (avail * 4 < size) | |||||
return (-1); | |||||
for (i = 0; i < 4 && (size > 0); i++) { | |||||
if (!DBREG_DR7_ENABLED(d.dr[7], i)) { | |||||
if (size > 2) | |||||
wsize = 4; | |||||
else | |||||
wsize = size; | |||||
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; | |||||
{ | |||||
struct dbreg d; | |||||
int i; | |||||
fill_dbregs(NULL, &d); | |||||
for(i = 0; i < 4; i++) { | |||||
if (DBREG_DR7_ENABLED(d.dr[7], i)) { | |||||
if ((DBREG_DRX((&d), i) >= addr) && | |||||
(DBREG_DRX((&d), i) < addr+size)) | |||||
i386_clr_watch(i, &d); | |||||
} | |||||
} | |||||
set_dbregs(NULL, &d); | |||||
return(0); | |||||
} | |||||
static const 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 | void | ||||
db_md_list_watchpoints(void) | db_md_list_watchpoints(void) | ||||
{ | { | ||||
struct dbreg d; | |||||
int i, len, type; | |||||
fill_dbregs(NULL, &d); | dbreg_list_watchpoints(); | ||||
db_printf("\nhardware watchpoints:\n"); | |||||
db_printf(" watch status type len address\n"); | |||||
db_printf(" ----- -------- ---------- --- ----------\n"); | |||||
for (i = 0; i < 4; i++) { | |||||
if (DBREG_DR7_ENABLED(d.dr[7], i)) { | |||||
type = DBREG_DR7_ACCESS(d.dr[7], i); | |||||
len = DBREG_DR7_LEN(d.dr[7], i); | |||||
db_printf(" %-5d %-8s %10s %3d ", | |||||
i, "enabled", watchtype_str(type), len + 1); | |||||
db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY); | |||||
db_printf("\n"); | |||||
} else { | |||||
db_printf(" %-5d disabled\n", i); | |||||
} | |||||
} | |||||
db_printf("\ndebug register values:\n"); | |||||
for (i = 0; i < 8; i++) | |||||
if (i != 4 && i != 5) | |||||
db_printf(" dr%d 0x%08x\n", i, DBREG_DRX(&d, i)); | |||||
mhorne: Note that this block is dropped, but can be added back if desired. | |||||
db_printf("\n"); | |||||
} | } |
Note that this block is dropped, but can be added back if desired.