diff options
Diffstat (limited to 'src/target')
-rw-r--r-- | src/target/breakpoints.c | 19 | ||||
-rw-r--r-- | src/target/breakpoints.h | 3 | ||||
-rw-r--r-- | src/target/nds32_v2.c | 37 | ||||
-rw-r--r-- | src/target/nds32_v3.c | 1 | ||||
-rw-r--r-- | src/target/nds32_v3_common.c | 39 | ||||
-rw-r--r-- | src/target/nds32_v3m.c | 1 | ||||
-rw-r--r-- | src/target/target.c | 17 | ||||
-rw-r--r-- | src/target/target.h | 8 | ||||
-rw-r--r-- | src/target/target_type.h | 5 |
9 files changed, 130 insertions, 0 deletions
diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 436acddc..422705bc 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -500,3 +500,22 @@ void watchpoint_clear_target(struct target *target) while (target->watchpoints != NULL) watchpoint_free(target, target->watchpoints); } + +int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, uint32_t *address) +{ + int retval; + struct watchpoint *hit_watchpoint; + + retval = target_hit_watchpoint(target, &hit_watchpoint); + if (retval != ERROR_OK) + return ERROR_FAIL; + + *rw = hit_watchpoint->rw; + *address = hit_watchpoint->address; + + LOG_DEBUG("Found hit watchpoint at 0x%8.8" PRIx32 " (WPID: %d)", + hit_watchpoint->address, + hit_watchpoint->unique_id); + + return ERROR_OK; +} diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index d9f4ba5d..0246acd3 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -72,4 +72,7 @@ int watchpoint_add(struct target *target, enum watchpoint_rw rw, uint32_t value, uint32_t mask); void watchpoint_remove(struct target *target, uint32_t address); +/* report type and address of just hit watchpoint */ +int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, uint32_t *address); + #endif /* BREAKPOINTS_H */ diff --git a/src/target/nds32_v2.c b/src/target/nds32_v2.c index 90961d7d..3f5f636f 100644 --- a/src/target/nds32_v2.c +++ b/src/target/nds32_v2.c @@ -534,6 +534,42 @@ static int nds32_v2_get_exception_address(struct nds32 *nds32, return ERROR_OK; } +/** + * find out which watchpoint hits + * get exception address and compare the address to watchpoints + */ +static int nds32_v2_hit_watchpoint(struct target *target, + struct watchpoint **hit_watchpoint) +{ + uint32_t exception_address; + struct watchpoint *wp; + static struct watchpoint scan_all_watchpoint; + struct nds32 *nds32 = target_to_nds32(target); + + scan_all_watchpoint.address = 0; + scan_all_watchpoint.rw = WPT_WRITE; + scan_all_watchpoint.next = 0; + scan_all_watchpoint.unique_id = 0x5CA8; + + exception_address = nds32->watched_address; + + if (exception_address == 0) { + /* send watch:0 to tell GDB to do software scan for hitting multiple watchpoints */ + *hit_watchpoint = &scan_all_watchpoint; + return ERROR_OK; + } + + for (wp = target->watchpoints; wp; wp = wp->next) { + if (((exception_address ^ wp->address) & (~wp->mask)) == 0) { + /* TODO: dispel false match */ + *hit_watchpoint = wp; + return ERROR_OK; + } + } + + return ERROR_FAIL; +} + static int nds32_v2_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, @@ -747,6 +783,7 @@ struct target_type nds32_v2_target = { .remove_breakpoint = nds32_v2_remove_breakpoint, .add_watchpoint = nds32_v2_add_watchpoint, .remove_watchpoint = nds32_v2_remove_watchpoint, + .hit_watchpoint = nds32_v2_hit_watchpoint, /* MMU */ .mmu = nds32_mmu, diff --git a/src/target/nds32_v3.c b/src/target/nds32_v3.c index dc0ca5a6..868260dc 100644 --- a/src/target/nds32_v3.c +++ b/src/target/nds32_v3.c @@ -506,6 +506,7 @@ struct target_type nds32_v3_target = { .remove_breakpoint = nds32_v3_remove_breakpoint, .add_watchpoint = nds32_v3_add_watchpoint, .remove_watchpoint = nds32_v3_remove_watchpoint, + .hit_watchpoint = nds32_v3_hit_watchpoint, /* MMU */ .mmu = nds32_mmu, diff --git a/src/target/nds32_v3_common.c b/src/target/nds32_v3_common.c index 49d84131..2fbd1a37 100644 --- a/src/target/nds32_v3_common.c +++ b/src/target/nds32_v3_common.c @@ -294,6 +294,45 @@ int nds32_v3_checksum_memory(struct target *target, return ERROR_FAIL; } +/** + * find out which watchpoint hits + * get exception address and compare the address to watchpoints + */ +int nds32_v3_hit_watchpoint(struct target *target, + struct watchpoint **hit_watchpoint) +{ + static struct watchpoint scan_all_watchpoint; + + uint32_t exception_address; + struct watchpoint *wp; + struct nds32 *nds32 = target_to_nds32(target); + + exception_address = nds32->watched_address; + + if (exception_address == 0xFFFFFFFF) + return ERROR_FAIL; + + if (exception_address == 0) { + scan_all_watchpoint.address = 0; + scan_all_watchpoint.rw = WPT_WRITE; + scan_all_watchpoint.next = 0; + scan_all_watchpoint.unique_id = 0x5CA8; + + *hit_watchpoint = &scan_all_watchpoint; + return ERROR_OK; + } + + for (wp = target->watchpoints; wp; wp = wp->next) { + if (((exception_address ^ wp->address) & (~wp->mask)) == 0) { + *hit_watchpoint = wp; + + return ERROR_OK; + } + } + + return ERROR_FAIL; +} + int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32) { nds32->register_map = nds32_v3_register_mapping; diff --git a/src/target/nds32_v3m.c b/src/target/nds32_v3m.c index 18987323..c37798af 100644 --- a/src/target/nds32_v3m.c +++ b/src/target/nds32_v3m.c @@ -494,6 +494,7 @@ struct target_type nds32_v3m_target = { .remove_breakpoint = nds32_v3m_remove_breakpoint, .add_watchpoint = nds32_v3m_add_watchpoint, .remove_watchpoint = nds32_v3m_remove_watchpoint, + .hit_watchpoint = nds32_v3_hit_watchpoint, /* MMU */ .mmu = nds32_mmu, diff --git a/src/target/target.c b/src/target/target.c index c5b80d64..4c31fbea 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1035,6 +1035,23 @@ int target_remove_watchpoint(struct target *target, { return target->type->remove_watchpoint(target, watchpoint); } +int target_hit_watchpoint(struct target *target, + struct watchpoint **hit_watchpoint) +{ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + + if (target->type->hit_watchpoint == NULL) { + /* For backward compatible, if hit_watchpoint is not implemented, + * return ERROR_FAIL such that gdb_server will not take the nonsense + * information. */ + return ERROR_FAIL; + } + + return target->type->hit_watchpoint(target, hit_watchpoint); +} int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, diff --git a/src/target/target.h b/src/target/target.h index 42414c69..09895bba 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -400,6 +400,14 @@ int target_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); /** + * Find out the just hit @a watchpoint for @a target. + * + * This routine is a wrapper for target->type->hit_watchpoint. + */ +int target_hit_watchpoint(struct target *target, + struct watchpoint **watchpoint); + +/** * Obtain the registers for GDB. * * This routine is a wrapper for target->type->get_gdb_reg_list. diff --git a/src/target/target_type.h b/src/target/target_type.h index 4d9a33f9..0b8d5daa 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -174,6 +174,11 @@ struct target_type { */ int (*remove_watchpoint)(struct target *target, struct watchpoint *watchpoint); + /* Find out just hit watchpoint. After the target hits a watchpoint, the + * information could assist gdb to locate where the modified/accessed memory is. + */ + int (*hit_watchpoint)(struct target *target, struct watchpoint **hit_watchpoint); + /** * Target algorithm support. Do @b not call this method directly, * use target_run_algorithm() instead. |