This is an automated email from Gerrit.

Matthias Welwarsky ([email protected]) just uploaded a new patch set to 
Gerrit, which you can find at http://openocd.zylin.com/3999

-- gerrit

commit 2916152cc465b7c2dfec041f4580a7265c88e1fd
Author: Matthias Welwarsky <[email protected]>
Date:   Fri Feb 17 16:16:51 2017 +0100

    rtos/hawt: add hardware-thread pseudeo rtos
    
    This patch adds "hawt", a pseudo rtos that represents cpu cores
    in an SMP system as threads to gdb. This allows to debug SMP
    system kernels in a more sensible manner and removes the current
    atrocities of switching gdb manually between CPU cores to update
    the context.
    
    Change-Id: Ib781c6c34097689d21d9e02011e4d74a4a742379
    Signed-off-by: Matthias Welwarsky <[email protected]>

diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am
index c59ee3f..ea8a399 100644
--- a/src/rtos/Makefile.am
+++ b/src/rtos/Makefile.am
@@ -15,6 +15,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
        %D%/embKernel.c \
        %D%/mqx.c \
        %D%/uCOS-III.c \
+       %D%/hwthread.c \
        %D%/rtos.h \
        %D%/rtos_standard_stackings.h \
        %D%/rtos_ecos_stackings.h \
diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c
new file mode 100644
index 0000000..2063595
--- /dev/null
+++ b/src/rtos/hwthread.c
@@ -0,0 +1,377 @@
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/time_support.h>
+#include <jtag/jtag.h>
+#include "target/target.h"
+#include "target/target_type.h"
+#include "target/register.h"
+#include "rtos.h"
+#include "helper/log.h"
+#include "helper/types.h"
+#include "server/gdb_server.h"
+
+static int hawt_detect_rtos(struct target *target);
+static int hawt_create(struct target *target);
+static int hawt_update_threads(struct rtos *rtos);
+static int hawt_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char 
**hex_reg_list);
+static int hawt_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int hawt_smp_init(struct target *target);
+
+#define HAWT_THREAD_NAME_STR_SIZE (32)
+
+extern int rtos_thread_packet(struct connection *connection, const char 
*packet, int packet_size);
+
+const struct rtos_type hawt_rtos = {
+       .name = "hawt",
+       .detect_rtos = hawt_detect_rtos,
+       .create = hawt_create,
+       .update_threads = hawt_update_threads,
+       .get_thread_reg_list = hawt_get_thread_reg_list,
+       .get_symbol_list_to_lookup = hawt_get_symbol_list_to_lookup,
+       .smp_init = hawt_smp_init,
+};
+
+struct hawt_params {
+       int dummy_param;
+};
+
+static int hawt_fill_thread(struct rtos *rtos, struct target *curr, int 
thread_num)
+{
+       char tmp_str[HAWT_THREAD_NAME_STR_SIZE];
+       threadid_t tid = curr->coreid + 1;
+
+       memset(tmp_str, 0, HAWT_THREAD_NAME_STR_SIZE);
+
+       /* thread-id is the core-id of this core inside the SMP group plus 1 */
+       rtos->thread_details[thread_num].threadid = tid;
+       /* create the thread name */
+       rtos->thread_details[thread_num].exists = true;
+       rtos->thread_details[thread_num].thread_name_str = 
strdup(target_name(curr));
+       snprintf(tmp_str, HAWT_THREAD_NAME_STR_SIZE-1, "state: %s", 
debug_reason_name(curr));
+       rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str);
+
+       return ERROR_OK;
+}
+
+static int hawt_update_threads(struct rtos *rtos)
+{
+       int threads_found = 0;
+       int thread_list_size = 0;
+       struct target_list *head;
+       struct target *target;
+       int64_t current_thread = 0;
+       enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
+
+       if (rtos == NULL)
+               return -1;
+
+       target = rtos->target;
+
+       /* wipe out previous thread details if any */
+       rtos_free_threadlist(rtos);
+
+       /* determine the number of "threads" */
+       if (target->smp) {
+               head = target->head;
+               while (head != NULL) {
+                       ++thread_list_size;
+                       head = head->next;
+               }
+       } else
+               thread_list_size = 1;
+
+       /* create space for new thread details */
+       rtos->thread_details = malloc(sizeof(struct thread_detail) * 
thread_list_size);
+
+       if (target->smp) {
+               /* loop over all threads */
+               for (head = target->head; head != NULL; head = head->next) {
+                       struct target *curr = head->target;
+                       threadid_t tid = curr->coreid + 1;
+
+                       hawt_fill_thread(rtos, curr, threads_found);
+
+                       /* find an interesting thread to set as current */
+                       switch (current_reason) {
+                       case DBG_REASON_UNDEFINED:
+                               current_reason = curr->debug_reason;
+                               current_thread = tid;
+                               break;
+                       case DBG_REASON_SINGLESTEP:
+                               /* single-step can only be overridden by itself 
*/
+                               if (curr->debug_reason == 
DBG_REASON_SINGLESTEP) {
+                                       if (tid == rtos->current_threadid)
+                                               current_thread = tid;
+                               }
+                               break;
+                       case DBG_REASON_BREAKPOINT:
+                               /* single-step overrides breakpoint */
+                               if (curr->debug_reason == 
DBG_REASON_SINGLESTEP) {
+                                       current_reason = curr->debug_reason;
+                                       current_thread = tid;
+                               } else
+                               /* multiple breakpoints, prefer gdbs' threadid 
*/
+                               if (curr->debug_reason == 
DBG_REASON_BREAKPOINT) {
+                                       if (tid == rtos->current_threadid)
+                                               current_thread = tid;
+                               }
+                               break;
+                       case DBG_REASON_WATCHPOINT:
+                               /* breakpoint and single-step override 
watchpoint */
+                               if (curr->debug_reason == DBG_REASON_SINGLESTEP 
||
+                                               curr->debug_reason == 
DBG_REASON_BREAKPOINT) {
+                                       current_reason = curr->debug_reason;
+                                       current_thread = tid;
+                               }
+                               break;
+                       case DBG_REASON_DBGRQ:
+                               /* all other reasons override debug-request */
+                               if (curr->debug_reason == DBG_REASON_SINGLESTEP 
||
+                                               curr->debug_reason == 
DBG_REASON_WATCHPOINT ||
+                                               curr->debug_reason == 
DBG_REASON_BREAKPOINT) {
+                                       current_reason = curr->debug_reason;
+                                       current_thread = tid;
+                               } else
+                               if (curr->debug_reason == DBG_REASON_DBGRQ) {
+                                       if (tid == rtos->current_threadid)
+                                               current_thread = tid;
+                               }
+
+                               break;
+
+                       default:
+                               break;
+                       }
+
+                       threads_found++;
+               }
+       } else {
+               hawt_fill_thread(rtos, target, threads_found);
+               current_thread = target->coreid + 1;
+               threads_found++;
+       }
+
+       rtos->thread_count = threads_found;
+
+       /* we found an interesting thread, set it as current */
+       if (current_thread != 0)
+               rtos->current_thread = current_thread;
+       else if (rtos->current_threadid != 0)
+               rtos->current_thread = rtos->current_threadid;
+       else
+               rtos->current_thread = 1;
+
+       LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
+       return 0;
+}
+
+static int hawt_smp_init(struct target *target)
+{
+       LOG_INFO("HAWT SMP init");
+       return hawt_update_threads(target->rtos);
+}
+
+static inline int gdb_reg_pos(struct target *target, int pos, int len)
+{
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+               return pos;
+       else
+               return len - 1 - pos;
+}
+
+/* Convert register to string of bytes. NB! The # of bits in the
+ * register might be non-divisible by 8(a byte), in which
+ * case an entire byte is shown.
+ *
+ * NB! the format on the wire is the target endianness
+ *
+ * The format of reg->value is little endian
+ *
+ */
+static void gdb_str_to_target(struct target *target,
+               char *tstr, struct reg *reg)
+{
+       int i;
+
+       uint8_t *buf;
+       int buf_len;
+       buf = reg->value;
+       buf_len = DIV_ROUND_UP(reg->size, 8);
+
+       for (i = 0; i < buf_len; i++) {
+               int j = gdb_reg_pos(target, i, buf_len);
+               tstr += sprintf(tstr, "%02x", buf[j]);
+       }
+}
+
+
+static int hawt_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char 
**hex_reg_list)
+{
+       struct target_list *head;
+       struct target *target;
+       struct target *curr;
+       struct reg **reg_list;
+       int reg_list_size;
+       int reg_packet_size = 0;
+       char *reg_packet;
+       char *reg_packet_p;
+       int i;
+
+       int retval;
+
+       *hex_reg_list = NULL;
+
+       if (rtos == NULL)
+               return ERROR_FAIL;
+
+       target = rtos->target;
+
+       /* Find the thread with that thread_id */
+       if (target->smp) {
+               curr = NULL;
+               for (head = target->head; head != NULL; head = head->next) {
+                       curr = head->target;
+
+                       if (thread_id == curr->coreid + 1)
+                               break;
+               }
+
+               if (head == NULL)
+                       return ERROR_FAIL;
+       } else {
+               curr = target;
+               if (thread_id != curr->coreid + 1)
+                       return ERROR_FAIL;
+
+       }
+
+       retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
+                       REG_CLASS_GENERAL);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (i = 0; i < reg_list_size; i++)
+               reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
+
+       if (reg_packet_size == 0)
+               return ERROR_FAIL;
+
+       reg_packet = malloc(reg_packet_size + 1); /* plus one for string 
termination null */
+       if (reg_packet == NULL)
+               return ERROR_FAIL;
+
+       reg_packet_p = reg_packet;
+
+       for (i = 0; i < reg_list_size; i++) {
+               if (!reg_list[i]->valid)
+                       reg_list[i]->type->get(reg_list[i]);
+               gdb_str_to_target(target, reg_packet_p, reg_list[i]);
+               reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
+       }
+
+       *hex_reg_list = reg_packet;
+       free(reg_list);
+
+       return ERROR_OK;
+
+}
+
+static int hawt_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+{
+       /* return an empty list, we don't have any symbols to look up */
+       *symbol_list = calloc(1, sizeof(symbol_table_elem_t));
+       (*symbol_list)[0].symbol_name = NULL;
+       return 0;
+}
+
+static int hawt_target_for_threadid(struct connection *connection, int64_t 
thread_id, struct target **p_target)
+{
+       struct target *target = get_target_from_connection(connection);
+       struct target_list *head;
+       struct target *curr;
+
+       if (target->smp) {
+               /* Find the thread with that thread_id */
+               curr = NULL;
+               for (head = target->head; head != NULL; head = head->next) {
+                       curr = head->target;
+
+                       if (thread_id == curr->coreid + 1)
+                               break;
+               }
+
+               if (head == NULL)
+                       return ERROR_FAIL;
+       } else {
+               curr = target;
+               if (thread_id != curr->coreid + 1)
+                       return ERROR_FAIL;
+       }
+
+       *p_target = curr;
+
+       return ERROR_OK;
+}
+
+static int hawt_detect_rtos(struct target *target)
+{
+       /* always return 0, avoid auto-detection */
+       return 0;
+}
+
+static int hawt_thread_packet(struct connection *connection, const char 
*packet, int packet_size)
+{
+       struct target *target = get_target_from_connection(connection);
+
+       struct target *curr = NULL;
+       int64_t current_threadid;
+
+       if (packet[0] == 'H' && packet[1] == 'g') {
+               sscanf(packet, "Hg%16" SCNx64, &current_threadid);
+
+               if (current_threadid > 0) {
+                       if (hawt_target_for_threadid(connection, 
current_threadid, &curr) != ERROR_OK) {
+                               LOG_ERROR("hawt: cannot find thread id 
%"PRId64, current_threadid);
+                               gdb_put_packet(connection, "E01", 3);
+                               return ERROR_FAIL;
+                       }
+               }
+
+               target->rtos->current_threadid = current_threadid;
+
+               gdb_put_packet(connection, "OK", 2);
+               return ERROR_OK;
+       }
+
+       return rtos_thread_packet(connection, packet, packet_size);
+}
+
+static int hawt_create(struct target *target)
+{
+       LOG_INFO("HAWT hardware thread awareness created");
+
+       target->rtos->rtos_specific_params = NULL;
+       target->rtos->current_thread = 0;
+       target->rtos->thread_details = NULL;
+       target->rtos->gdb_target_for_threadid = hawt_target_for_threadid;
+       target->rtos->gdb_thread_packet = hawt_thread_packet;
+       return 0;
+}
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 497ea8b..cc0a8b9 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -35,6 +35,7 @@ extern struct rtos_type ChibiOS_rtos;
 extern struct rtos_type embKernel_rtos;
 extern struct rtos_type mqx_rtos;
 extern struct rtos_type uCOS_III_rtos;
+extern struct rtos_type hawt_rtos;
 
 static struct rtos_type *rtos_types[] = {
        &ThreadX_rtos,
@@ -45,6 +46,7 @@ static struct rtos_type *rtos_types[] = {
        &embKernel_rtos,
        &mqx_rtos,
        &uCOS_III_rtos,
+       &hawt_rtos,
        NULL
 };
 

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to