]> git.sur5r.net Git - openocd/commitdiff
gdb server: new feature, add stop reason in stop reply packet for gdb
authorHsiangkai Wang <hsiangkai@gmail.com>
Wed, 26 Dec 2012 11:11:03 +0000 (19:11 +0800)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 7 Aug 2013 21:01:08 +0000 (21:01 +0000)
In GDB remote serial protocol, the stop reply packet could contain more
detail stop reason. The currently defined stop reasons are listed below.

* watch
* rwatch
* awatch
* library
* replaylog

This commit adds stop reason, watch/rwatch/awatch, in stop reply packet for
just hit watchpoint. As manual indicates, at most one stop reason should be present.

The function needs target to implement new hook, hit_watchpoint. The hook will fill
the hit watchpoint in second parameter. The information will assist gdb to locate
the watchpoint. If no such information, gdb needs to scan all watchpoints by itself.

Refer to GDB Manual, D.3 Stop Reply Packets

Change-Id: I1f70a1a9cc772e88e641b6171f1a009629a43bd1
Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-on: http://openocd.zylin.com/1092
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
src/server/gdb_server.c
src/target/breakpoints.c
src/target/breakpoints.h
src/target/nds32_v2.c
src/target/nds32_v3.c
src/target/nds32_v3_common.c
src/target/nds32_v3m.c
src/target/target.c
src/target/target.h
src/target/target_type.h

index beeeedcce1470fc804cdd96274e650370c4c3528..8eacf8c388c4b549af590eada61db30aa7abc7db 100644 (file)
@@ -705,7 +705,9 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec
         * that are to be ignored.
         */
        if (gdb_connection->frontend_state == TARGET_RUNNING) {
-               char sig_reply[4];
+               char sig_reply[20];
+               char stop_reason[20];
+               int sig_reply_len;
                int signal_var;
 
                /* stop forwarding log packets! */
@@ -717,8 +719,36 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec
                } else
                        signal_var = gdb_last_signal(target);
 
-               snprintf(sig_reply, 4, "T%2.2x", signal_var);
-               gdb_put_packet(connection, sig_reply, 3);
+               stop_reason[0] = '\0';
+               if (target->debug_reason == DBG_REASON_WATCHPOINT) {
+                       enum watchpoint_rw hit_wp_type;
+                       uint32_t hit_wp_address;
+
+                       if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) {
+
+                               switch (hit_wp_type) {
+                                       case WPT_WRITE:
+                                               snprintf(stop_reason, sizeof(stop_reason),
+                                                               "watch:%08x;", hit_wp_address);
+                                               break;
+                                       case WPT_READ:
+                                               snprintf(stop_reason, sizeof(stop_reason),
+                                                               "rwatch:%08x;", hit_wp_address);
+                                               break;
+                                       case WPT_ACCESS:
+                                               snprintf(stop_reason, sizeof(stop_reason),
+                                                               "awatch:%08x;", hit_wp_address);
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+
+               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s",
+                               signal_var, stop_reason);
+
+               gdb_put_packet(connection, sig_reply, sig_reply_len);
                gdb_connection->frontend_state = TARGET_HALTED;
                rtos_update_threads(target);
        }
index 436acddcf7483e9c9fdc8ec5be757f83feebd741..422705bc9c187ef1834bc77bf149483d3afb78e6 100644 (file)
@@ -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;
+}
index d9f4ba5d9720c249c3e7c61e6d00dac0bab58f4e..0246acd3db84dc1f17b5f146d046f7bab50e23ad 100644 (file)
@@ -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 */
index 90961d7d8249ba95759ce4db40de8348c707d43c..3f5f636fd79a9b3cc205186ac1c79f000231c057 100644 (file)
@@ -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,
index dc0ca5a67aa91bed8c4659f079659bffc72637b1..868260dc9e59f52900e42b4b3049ca1d4bf02546 100644 (file)
@@ -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,
index 49d841311f23660f431393fe93384cdbbbb28164..2fbd1a3780ad61928f76febcd38e6a3d3dfd841a 100644 (file)
@@ -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;
index 1898732327ac1b663582d114b5f9033efebbc0cf..c37798afb52897920861930359b65d42bcf53bba 100644 (file)
@@ -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,
index c5b80d6476745325fc854ce372d3d1426ea3dbe3..4c31fbea23fb05463ba802a94fd19f22c31fc1ae 100644 (file)
@@ -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,
index 42414c69207d9676f7a3b4fcc1d8ade6b1b799b4..09895bbabd86953617b7ed72901c5f3aee7b6d71 100644 (file)
@@ -399,6 +399,14 @@ int target_add_watchpoint(struct target *target,
 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.
  *
index 4d9a33f99764f20ea58ee1cea10b907f2df9a5c0..0b8d5daa1b59e122008b881391e43fb5c6eb2624 100644 (file)
@@ -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.