aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
Diffstat (limited to 'src/target')
-rw-r--r--src/target/breakpoints.c19
-rw-r--r--src/target/breakpoints.h3
-rw-r--r--src/target/nds32_v2.c37
-rw-r--r--src/target/nds32_v3.c1
-rw-r--r--src/target/nds32_v3_common.c39
-rw-r--r--src/target/nds32_v3m.c1
-rw-r--r--src/target/target.c17
-rw-r--r--src/target/target.h8
-rw-r--r--src/target/target_type.h5
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.