Add support for read and write watchpoints.

This commit is contained in:
Daniel Beer 2012-04-25 14:10:26 +12:00
parent 7413531715
commit 09ca20c91c
9 changed files with 87 additions and 13 deletions

View File

@ -53,7 +53,9 @@ typedef enum {
typedef enum {
DEVICE_BPTYPE_BREAK,
DEVICE_BPTYPE_WATCH
DEVICE_BPTYPE_WATCH,
DEVICE_BPTYPE_READ,
DEVICE_BPTYPE_WRITE
} device_bptype_t;
struct device_breakpoint {

View File

@ -226,6 +226,14 @@ static int bp_send(struct gdb_data *gdb, int c, address_t addr,
type_code = 1;
break;
case DEVICE_BPTYPE_WRITE:
type_code = 2;
break;
case DEVICE_BPTYPE_READ:
type_code = 3;
break;
case DEVICE_BPTYPE_WATCH:
type_code = 4;
break;

View File

@ -53,7 +53,8 @@ struct sim_device {
(dev)->memory[offset | 1] = (value) >> 8; \
} while (0);
static void watchpoint_check(struct sim_device *dev, uint16_t addr)
static void watchpoint_check(struct sim_device *dev, uint16_t addr,
int is_write)
{
int i;
@ -62,8 +63,10 @@ static void watchpoint_check(struct sim_device *dev, uint16_t addr)
&dev->base.breakpoints[i];
if ((bp->flags & DEVICE_BP_ENABLED) &&
bp->type == DEVICE_BPTYPE_WATCH &&
bp->addr == addr) {
(bp->addr == addr) &&
((bp->type == DEVICE_BPTYPE_WATCH ||
(bp->type == DEVICE_BPTYPE_READ && !is_write) ||
(bp->type == DEVICE_BPTYPE_WRITE && is_write)))) {
dev->watchpoint_hit = 1;
return;
}
@ -133,12 +136,12 @@ static int fetch_operand(struct sim_device *dev,
break;
}
watchpoint_check(dev, addr);
if (addr_ret)
*addr_ret = addr;
if (data_ret) {
watchpoint_check(dev, addr, 0);
*data_ret = MEM_GETW(dev, addr) & mask;
if (addr < MEM_IO_END) {
@ -172,7 +175,7 @@ static int store_operand(struct sim_device *dev,
return 0;
}
watchpoint_check(dev, addr);
watchpoint_check(dev, addr, 1);
if (is_byte)
MEM_SETB(dev, addr, data);

View File

@ -324,13 +324,14 @@ static void load_break(BpParameter_t *param, address_t addr)
param->wExtCombine = 0; /* not used? */
}
static void load_watch(BpParameter_t *param, address_t addr)
static void load_complex(BpParameter_t *param, address_t addr,
BpAccess_t acc)
{
param->bpMode = BP_COMPLEX;
param->lAddrVal = addr;
param->bpType = BP_MAB;
param->lReg = 0; /* not used (only for register-write) */
param->bpAccess = BP_NO_FETCH;
param->bpAccess = acc;
param->bpAction = BP_BRK;
param->bpOperat = BP_EQUAL;
param->lMask = 0xffffff;
@ -338,7 +339,7 @@ static void load_watch(BpParameter_t *param, address_t addr)
param->bpRangeAction = 0; /* not used */
param->bpCondition = BP_NO_COND;
param->lCondMdbVal = 0;
param->bpCondAccess = BP_NO_FETCH;
param->bpCondAccess = acc;
param->lCondMask = 0; /* what's this? */
param->bpCondOperat = BP_EQUAL;
param->wExtCombine = 0; /* not used? */
@ -362,7 +363,17 @@ static int refresh_bps(struct tilib_device *dev)
break;
case DEVICE_BPTYPE_WATCH:
load_watch(&param, bp->addr);
load_complex(&param, bp->addr, BP_NO_FETCH);
break;
case DEVICE_BPTYPE_READ:
load_complex(&param, bp->addr,
BP_READ_DMA);
break;
case DEVICE_BPTYPE_WRITE:
load_complex(&param, bp->addr,
BP_WRITE_DMA);
break;
}
} else {

View File

@ -408,6 +408,10 @@ Add a new watchpoint. The watchpoint location is an address expression, and
an optional index may be specified. Watchpoints are considered to be a type
of breakpoint and can be inspected or removed using the \fBbreak\fR and
\fBdelbreak\fR commands. Note that not all drivers support watchpoints.
.IP "\fBsetwatch_r\fR \fIaddress\fR [\fIindex\fR]"
Add a watchpoint which is triggered only on read access.
.IP "\fBsetwatch_w\fR \fIaddress\fR [\fIindex\fR]"
Add a watchpoint which is triggered only on write access.
.IP "\fBsimio add\fR \fIclass\fR \fIname\fR [\fIargs ...\fR]"
Add a new peripheral to the IO simulator. The \fIclass\fR parameter may be
any of the peripheral types named in the output of the \fBsimio classes\fR

View File

@ -68,6 +68,20 @@ const struct cmddb_record commands[] = {
"setwatch <addr> [index]\n"
" Set a watchpoint. If no index is specified. the first available\n"
" slot will be used.\n"
},
{
.name = "setwatch_r",
.func = cmd_setwatch_r,
.help =
"setwatch_r <addr> [index]\n"
" Set a read-only watchpoint.\n"
},
{
.name = "setwatch_w",
.func = cmd_setwatch_w,
.help =
"setwatch_w <addr> [index]\n"
" Set a write-only watchpoint.\n"
},
{
.name = "delbreak",

View File

@ -615,6 +615,16 @@ int cmd_setwatch(char **arg)
return do_setbreak(DEVICE_BPTYPE_WATCH, arg);
}
int cmd_setwatch_w(char **arg)
{
return do_setbreak(DEVICE_BPTYPE_WRITE, arg);
}
int cmd_setwatch_r(char **arg)
{
return do_setbreak(DEVICE_BPTYPE_READ, arg);
}
int cmd_delbreak(char **arg)
{
char *index_text = get_arg(arg);
@ -661,10 +671,22 @@ int cmd_break(char **arg)
print_address(bp->addr, name, sizeof(name));
printc(" %d. %s", i, name);
if (bp->type == DEVICE_BPTYPE_WATCH) {
switch (bp->type) {
case DEVICE_BPTYPE_WATCH:
printc(" [watchpoint]\n");
} else {
break;
case DEVICE_BPTYPE_READ:
printc(" [read watchpoint]\n");
break;
case DEVICE_BPTYPE_WRITE:
printc(" [write watchpoint]\n");
break;
case DEVICE_BPTYPE_BREAK:
printc("\n");
break;
}
}
}

View File

@ -33,6 +33,8 @@ int cmd_prog(char **arg);
int cmd_load(char **arg);
int cmd_setbreak(char **arg);
int cmd_setwatch(char **arg);
int cmd_setwatch_r(char **arg);
int cmd_setwatch_w(char **arg);
int cmd_delbreak(char **arg);
int cmd_break(char **arg);
int cmd_locka(char **arg);

View File

@ -329,6 +329,14 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
type = DEVICE_BPTYPE_BREAK;
break;
case 2:
type = DEVICE_BPTYPE_WRITE;
break;
case 3:
type = DEVICE_BPTYPE_READ;
break;
case 4:
type = DEVICE_BPTYPE_WATCH;
break;