rtos: add support for uC/OS-III 56/3556/13
authorSteven Stallion <stallion@squareup.com>
Sat, 16 Jul 2016 03:01:00 +0000 (22:01 -0500)
committerPaul Fertser <fercerpav@gmail.com>
Thu, 8 Dec 2016 12:29:35 +0000 (12:29 +0000)
This patch introduces RTOS support for uC/OS-III. Currently, only
FPU-less ARM Cortex-M targets are supported. Due to the configurability
of the RTOS, an OpenOCD-specific file must be linked along with the
project to determine the correct offsets within the OS_TCB structure.

In addition to the above, a crash was fixed in rtos_get_gdb_reg_list
such that RTOS support could be used between resets without restarting
OpenOCD and support for the Hg packet was cleaned up.

Change-Id: Ide004a689e6b886185df665c00fb644629eb31d1
Signed-off-by: Steven Stallion <stallion@squareup.com>
Reviewed-on: http://openocd.zylin.com/3556
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
contrib/rtos-helpers/uCOS-III-openocd.c [new file with mode: 0644]
doc/openocd.texi
src/rtos/Makefile.am
src/rtos/rtos.c
src/rtos/rtos_ucos_iii_stackings.c [new file with mode: 0644]
src/rtos/rtos_ucos_iii_stackings.h [new file with mode: 0644]
src/rtos/uCOS-III.c [new file with mode: 0644]

diff --git a/contrib/rtos-helpers/uCOS-III-openocd.c b/contrib/rtos-helpers/uCOS-III-openocd.c
new file mode 100644 (file)
index 0000000..9037334
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * uC/OS-III does not provide a fixed layout for OS_TCB, which makes it
+ * impossible to determine the appropriate offsets within the structure
+ * unaided. A priori knowledge of offsets based on os_dbg.c is tied to a
+ * specific release and thusly, brittle. The constants defined below
+ * provide the neccessary information OpenOCD needs to provide support
+ * in the most robust manner possible.
+ *
+ * This file should be linked along with the project to enable RTOS
+ * support for uC/OS-III.
+ */
+
+#include <os.h>
+
+#if OS_CFG_DBG_EN == 0
+#error "OS_CFG_DBG_EN is required to enable RTOS support for OpenOCD"
+#endif
+
+#define OFFSET_OF(type, member) ((CPU_SIZE_T)&(((type *)0)->member))
+
+#ifdef __GNUC__
+#define USED __attribute__((used))
+#else
+#define USED
+#endif
+
+const CPU_SIZE_T USED openocd_OS_TCB_StkPtr_offset = OFFSET_OF(OS_TCB, StkPtr);
+const CPU_SIZE_T USED openocd_OS_TCB_NamePtr_offset = OFFSET_OF(OS_TCB, NamePtr);
+const CPU_SIZE_T USED openocd_OS_TCB_TaskState_offset = OFFSET_OF(OS_TCB, TaskState);
+const CPU_SIZE_T USED openocd_OS_TCB_Prio_offset = OFFSET_OF(OS_TCB, Prio);
+const CPU_SIZE_T USED openocd_OS_TCB_DbgPrevPtr_offset = OFFSET_OF(OS_TCB, DbgPrevPtr);
+const CPU_SIZE_T USED openocd_OS_TCB_DbgNextPtr_offset = OFFSET_OF(OS_TCB, DbgNextPtr);
index 497a20b5b138a79cf1315fc211347285046c6e0f..372683a9ccc2e1313f1d47339479ed22c77f2bac 100644 (file)
@@ -4123,7 +4123,8 @@ The value should normally correspond to a static mapping for the
 @anchor{rtostype}
 @item @code{-rtos} @var{rtos_type} -- enable rtos support for target,
 @var{rtos_type} can be one of @option{auto}|@option{eCos}|@option{ThreadX}|
-@option{FreeRTOS}|@option{linux}|@option{ChibiOS}|@option{embKernel}|@option{mqx}
+@option{FreeRTOS}|@option{linux}|@option{ChibiOS}|@option{embKernel}|@option{mqx}|
+@option{uCOS-III}
 @xref{gdbrtossupport,,RTOS Support}.
 
 @item @code{-defer-examine} -- skip target examination at initial JTAG chain
@@ -8833,6 +8834,7 @@ Currently supported rtos's include:
 @item @option{ChibiOS}
 @item @option{embKernel}
 @item @option{mqx}
+@item @option{uCOS-III}
 @end itemize
 
 @quotation Note
@@ -8866,10 +8868,12 @@ Rtos::sCurrentTask, Rtos::sListReady, Rtos::sListSleep,
 Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount.
 @item mqx symbols
 _mqx_kernel_data, MQX_init_struct.
+@item uC/OS-III symbols
+OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty
 @end table
 
 For most RTOS supported the above symbols will be exported by default. However for
-some, eg. FreeRTOS, extra steps must be taken.
+some, eg. FreeRTOS and uC/OS-III, extra steps must be taken.
 
 These RTOSes may require additional OpenOCD-specific file to be linked
 along with the project:
@@ -8877,6 +8881,8 @@ along with the project:
 @table @code
 @item FreeRTOS
 contrib/rtos-helpers/FreeRTOS-openocd.c
+@item uC/OS-III
+contrib/rtos-helpers/uCOS-III-openocd.c
 @end table
 
 @node Tcl Scripting API
index fdca394e4c4998ebf47417568419360acbf192e2..a9122b262c5ae9daabb956ac87deb9726f6f5401 100644 (file)
@@ -20,8 +20,8 @@ include $(top_srcdir)/common.mk
 
 METASOURCES = AUTO
 noinst_LTLIBRARIES = librtos.la
-noinst_HEADERS = rtos.h rtos_standard_stackings.h rtos_ecos_stackings.h linux_header.h rtos_chibios_stackings.h rtos_embkernel_stackings.h rtos_mqx_stackings.h
-librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c  rtos_chibios_stackings.c rtos_embkernel_stackings.c rtos_mqx_stackings.c FreeRTOS.c ThreadX.c eCos.c linux.c ChibiOS.c embKernel.c mqx.c
+noinst_HEADERS = rtos.h rtos_standard_stackings.h rtos_ecos_stackings.h linux_header.h rtos_chibios_stackings.h rtos_embkernel_stackings.h rtos_mqx_stackings.h rtos_ucos_iii_stackings.h
+librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c  rtos_chibios_stackings.c rtos_embkernel_stackings.c rtos_mqx_stackings.c rtos_ucos_iii_stackings.c FreeRTOS.c ThreadX.c eCos.c linux.c ChibiOS.c embKernel.c mqx.c uCOS-III.c
 
 librtos_la_CFLAGS =
 if IS_MINGW
index aa8efbe7270be719b8612dd1b8e5feba0eb03f1c..785fc6161a1f798da791b0e6193b73ec683dc714 100644 (file)
@@ -34,6 +34,7 @@ extern struct rtos_type Linux_os;
 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;
 
 static struct rtos_type *rtos_types[] = {
        &ThreadX_rtos,
@@ -43,6 +44,7 @@ static struct rtos_type *rtos_types[] = {
        &ChibiOS_rtos,
        &embKernel_rtos,
        &mqx_rtos,
+       &uCOS_III_rtos,
        NULL
 };
 
@@ -400,9 +402,14 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
        } else if (packet[0] == 'H') {  /* Set current thread ( 'c' for step and continue, 'g' for
                                         * all other operations ) */
                if ((packet[1] == 'g') && (target->rtos != NULL)) {
-                       sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
-                       LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64 "\r\n",
-                                                                               target->rtos->current_threadid);
+                       threadid_t threadid;
+                       sscanf(packet, "Hg%16" SCNx64, &threadid);
+                       LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64, threadid);
+                       /* threadid of 0 indicates target should choose */
+                       if (threadid == 0)
+                               target->rtos->current_threadid = target->rtos->current_thread;
+                       else
+                               target->rtos->current_threadid = threadid;
                }
                gdb_put_packet(connection, "OK", 2);
                return ERROR_OK;
@@ -426,9 +433,13 @@ int rtos_get_gdb_reg_list(struct connection *connection)
                                                                                current_threadid,
                                                                                target->rtos->current_thread);
 
-               target->rtos->type->get_thread_reg_list(target->rtos,
-                       current_threadid,
-                       &hex_reg_list);
+               int retval = target->rtos->type->get_thread_reg_list(target->rtos,
+                               current_threadid,
+                               &hex_reg_list);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("RTOS: failed to get register list");
+                       return retval;
+               }
 
                if (hex_reg_list != NULL) {
                        gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
@@ -546,5 +557,7 @@ void rtos_free_threadlist(struct rtos *rtos)
                free(rtos->thread_details);
                rtos->thread_details = NULL;
                rtos->thread_count = 0;
+               rtos->current_threadid = -1;
+               rtos->current_thread = 0;
        }
 }
diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c
new file mode 100644 (file)
index 0000000..f2f5564
--- /dev/null
@@ -0,0 +1,53 @@
+/***************************************************************************
+ *   Copyright (C) 2016 by Square, Inc.                                    *
+ *   Steven Stallion <stallion@squareup.com>                               *
+ *                                                                         *
+ *   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 "rtos.h"
+#include "rtos_standard_stackings.h"
+#include "target/armv7m.h"
+
+static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
+       { 0x20, 32 },           /* r0   */
+       { 0x24, 32 },           /* r1   */
+       { 0x28, 32 },           /* r2   */
+       { 0x2c, 32 },           /* r3   */
+       { 0x00, 32 },           /* r4   */
+       { 0x04, 32 },           /* r5   */
+       { 0x08, 32 },           /* r6   */
+       { 0x0c, 32 },           /* r7   */
+       { 0x10, 32 },           /* r8   */
+       { 0x14, 32 },           /* r9   */
+       { 0x18, 32 },           /* r10  */
+       { 0x1c, 32 },           /* r11  */
+       { 0x30, 32 },           /* r12  */
+       { -2,   32 },           /* sp   */
+       { 0x34, 32 },           /* lr   */
+       { 0x38, 32 },           /* pc   */
+       { 0x3c, 32 },           /* xPSR */
+};
+
+const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = {
+       0x40,                                   /* stack_registers_size */
+       -1,                                     /* stack_growth_direction */
+       ARMV7M_NUM_CORE_REGS,                   /* num_output_registers */
+       rtos_generic_stack_align8,              /* stack_alignment */
+       rtos_uCOS_III_Cortex_M_stack_offsets    /* register_offsets */
+};
diff --git a/src/rtos/rtos_ucos_iii_stackings.h b/src/rtos/rtos_ucos_iii_stackings.h
new file mode 100644 (file)
index 0000000..c462cd7
--- /dev/null
@@ -0,0 +1,30 @@
+/***************************************************************************
+ *   Copyright (C) 2016 by Square, Inc.                                    *
+ *   Steven Stallion <stallion@squareup.com>                               *
+ *                                                                         *
+ *   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/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H
+#define OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rtos.h"
+
+extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking;
+
+#endif /* OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H */
diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c
new file mode 100644 (file)
index 0000000..75cfe52
--- /dev/null
@@ -0,0 +1,509 @@
+/***************************************************************************
+ *   Copyright (C) 2016 by Square, Inc.                                    *
+ *   Steven Stallion <stallion@squareup.com>                               *
+ *                                                                         *
+ *   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 "rtos.h"
+#include "helper/log.h"
+#include "helper/types.h"
+#include "rtos/rtos_ucos_iii_stackings.h"
+
+#ifndef UCOS_III_MAX_STRLEN
+#define UCOS_III_MAX_STRLEN 64
+#endif
+
+#ifndef UCOS_III_MAX_THREADS
+#define UCOS_III_MAX_THREADS 256
+#endif
+
+struct uCOS_III_params {
+       const char *target_name;
+       const unsigned char pointer_width;
+       symbol_address_t thread_stack_offset;
+       symbol_address_t thread_name_offset;
+       symbol_address_t thread_state_offset;
+       symbol_address_t thread_priority_offset;
+       symbol_address_t thread_prev_offset;
+       symbol_address_t thread_next_offset;
+       bool thread_offsets_updated;
+       size_t threadid_start;
+       const struct rtos_register_stacking *stacking_info;
+       size_t num_threads;
+       symbol_address_t threads[];
+};
+
+static const struct uCOS_III_params uCOS_III_params_list[] = {
+       {
+               "cortex_m",                             /* target_name */
+               sizeof(uint32_t),                       /* pointer_width */
+               0,                                      /* thread_stack_offset */
+               0,                                      /* thread_name_offset */
+               0,                                      /* thread_state_offset */
+               0,                                      /* thread_priority_offset */
+               0,                                      /* thread_prev_offset */
+               0,                                      /* thread_next_offset */
+               false,                                  /* thread_offsets_updated */
+               1,                                      /* threadid_start */
+               &rtos_uCOS_III_Cortex_M_stacking,       /* stacking_info */
+               0,                                      /* num_threads */
+       },
+};
+
+static const char * const uCOS_III_symbol_list[] = {
+       "OSRunning",
+       "OSTCBCurPtr",
+       "OSTaskDbgListPtr",
+       "OSTaskQty",
+
+       /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
+       "openocd_OS_TCB_StkPtr_offset",
+       "openocd_OS_TCB_NamePtr_offset",
+       "openocd_OS_TCB_TaskState_offset",
+       "openocd_OS_TCB_Prio_offset",
+       "openocd_OS_TCB_DbgPrevPtr_offset",
+       "openocd_OS_TCB_DbgNextPtr_offset",
+       NULL
+};
+
+enum uCOS_III_symbol_values {
+       uCOS_III_VAL_OSRunning,
+       uCOS_III_VAL_OSTCBCurPtr,
+       uCOS_III_VAL_OSTaskDbgListPtr,
+       uCOS_III_VAL_OSTaskQty,
+
+       /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
+       uCOS_III_VAL_OS_TCB_StkPtr_offset,
+       uCOS_III_VAL_OS_TCB_NamePtr_offset,
+       uCOS_III_VAL_OS_TCB_TaskState_offset,
+       uCOS_III_VAL_OS_TCB_Prio_offset,
+       uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
+       uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
+};
+
+static const char * const uCOS_III_thread_state_list[] = {
+       "Ready",
+       "Delay",
+       "Pend",
+       "Pend Timeout",
+       "Suspended",
+       "Delay Suspended",
+       "Pend Suspended",
+       "Pend Timeout Suspended",
+};
+
+static int uCOS_III_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address,
+               threadid_t *threadid)
+{
+       struct uCOS_III_params *params = rtos->rtos_specific_params;
+       size_t thread_index;
+
+       for (thread_index = 0; thread_index < params->num_threads; thread_index++)
+               if (params->threads[thread_index] == thread_address)
+                       goto found;
+
+       if (params->num_threads == UCOS_III_MAX_THREADS) {
+               LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS");
+               return ERROR_FAIL;
+       }
+
+       params->threads[thread_index] = thread_address;
+       params->num_threads++;
+found:
+       *threadid = thread_index + params->threadid_start;
+       return ERROR_OK;
+}
+
+static int uCOS_III_find_thread_address(struct rtos *rtos, threadid_t threadid,
+               symbol_address_t *thread_address)
+{
+       struct uCOS_III_params *params = rtos->rtos_specific_params;
+       size_t thread_index;
+
+       thread_index = threadid - params->threadid_start;
+       if (thread_index >= params->num_threads) {
+               LOG_ERROR("uCOS-III: failed to find thread address");
+               return ERROR_FAIL;
+       }
+
+       *thread_address = params->threads[thread_index];
+       return ERROR_OK;
+}
+
+static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
+{
+       struct uCOS_III_params *params = rtos->rtos_specific_params;
+       int retval;
+
+       /* read the thread list head */
+       symbol_address_t thread_list_address = 0;
+
+       retval = target_read_memory(rtos->target,
+                                   rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address,
+                                   params->pointer_width,
+                                   1,
+                                   (void *)&thread_list_address);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to read thread list address");
+               return retval;
+       }
+
+       /* advance to end of thread list */
+       do {
+               *thread_address = thread_list_address;
+
+               retval = target_read_memory(rtos->target,
+                                           thread_list_address + params->thread_next_offset,
+                                           params->pointer_width,
+                                           1,
+                                           (void *)&thread_list_address);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to read next thread address");
+                       return retval;
+               }
+       } while (thread_list_address != 0);
+
+       return ERROR_OK;
+}
+
+static int uCOS_III_update_thread_offsets(struct rtos *rtos)
+{
+       struct uCOS_III_params *params = rtos->rtos_specific_params;
+
+       if (params->thread_offsets_updated)
+               return ERROR_OK;
+
+       const struct thread_offset_map {
+               enum uCOS_III_symbol_values symbol_value;
+               symbol_address_t *thread_offset;
+       } thread_offset_maps[] = {
+               {
+                       uCOS_III_VAL_OS_TCB_StkPtr_offset,
+                       &params->thread_stack_offset,
+               },
+               {
+                       uCOS_III_VAL_OS_TCB_NamePtr_offset,
+                       &params->thread_name_offset,
+               },
+               {
+                       uCOS_III_VAL_OS_TCB_TaskState_offset,
+                       &params->thread_state_offset,
+               },
+               {
+                       uCOS_III_VAL_OS_TCB_Prio_offset,
+                       &params->thread_priority_offset,
+               },
+               {
+                       uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
+                       &params->thread_prev_offset,
+               },
+               {
+                       uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
+                       &params->thread_next_offset,
+               },
+       };
+
+       for (size_t i = 0; i < ARRAY_SIZE(thread_offset_maps); i++) {
+               const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i];
+
+               int retval = target_read_memory(rtos->target,
+                                               rtos->symbols[thread_offset_map->symbol_value].address,
+                                               params->pointer_width,
+                                               1,
+                                               (void *)thread_offset_map->thread_offset);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to read thread offset");
+                       return retval;
+               }
+       }
+
+       params->thread_offsets_updated = true;
+       return ERROR_OK;
+}
+
+static int uCOS_III_detect_rtos(struct target *target)
+{
+       return target->rtos->symbols != NULL &&
+           target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0;
+}
+
+static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
+{
+       struct uCOS_III_params *params = target->rtos->rtos_specific_params;
+
+       params->thread_offsets_updated = false;
+       params->num_threads = 0;
+
+       return ERROR_OK;
+}
+
+static int uCOS_III_create(struct target *target)
+{
+       struct uCOS_III_params *params;
+
+       for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_params_list); i++)
+               if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) {
+                       params = malloc(sizeof(*params) +
+                           UCOS_III_MAX_THREADS * sizeof(*params->threads));
+                       if (params == NULL) {
+                               LOG_ERROR("uCOS-III: out of memory");
+                               return ERROR_FAIL;
+                       }
+
+                       memcpy(params, &uCOS_III_params_list[i], sizeof(uCOS_III_params_list[i]));
+                       target->rtos->rtos_specific_params = (void *)params;
+
+                       target_register_reset_callback(uCOS_III_reset_handler, NULL);
+
+                       return ERROR_OK;
+               }
+
+       LOG_ERROR("uCOS-III: target not supported: %s", target->type->name);
+       return ERROR_FAIL;
+}
+
+static int uCOS_III_update_threads(struct rtos *rtos)
+{
+       struct uCOS_III_params *params = rtos->rtos_specific_params;
+       int retval;
+
+       /* free previous thread details */
+       rtos_free_threadlist(rtos);
+
+       /* verify RTOS is running */
+       uint8_t rtos_running;
+
+       retval = target_read_u8(rtos->target,
+                               rtos->symbols[uCOS_III_VAL_OSRunning].address,
+                               &rtos_running);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to read RTOS running");
+               return retval;
+       }
+
+       if (!rtos_running) {
+               rtos->thread_details = calloc(1, sizeof(struct thread_detail));
+               if (rtos->thread_details == NULL) {
+                       LOG_ERROR("uCOS-III: out of memory");
+                       return ERROR_FAIL;
+               }
+
+               rtos->thread_count = 1;
+               rtos->thread_details->threadid = 0;
+               rtos->thread_details->exists = true;
+               rtos->current_thread = 0;
+
+               return ERROR_OK;
+       }
+
+       /* update thread offsets */
+       retval = uCOS_III_update_thread_offsets(rtos);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to update thread offsets");
+               return retval;
+       }
+
+       /* read current thread address */
+       symbol_address_t current_thread_address = 0;
+
+       retval = target_read_memory(rtos->target,
+                                   rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address,
+                                   params->pointer_width,
+                                   1,
+                                   (void *)&current_thread_address);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to read current thread address");
+               return retval;
+       }
+
+       /* read number of tasks */
+       retval = target_read_u16(rtos->target,
+                                rtos->symbols[uCOS_III_VAL_OSTaskQty].address,
+                                (void *)&rtos->thread_count);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to read thread count");
+               return retval;
+       }
+
+       rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
+       if (rtos->thread_details == NULL) {
+               LOG_ERROR("uCOS-III: out of memory");
+               return ERROR_FAIL;
+       }
+
+       /*
+        * uC/OS-III adds tasks in LIFO order; advance to the end of the
+        * list and work backwards to preserve the intended order.
+        */
+       symbol_address_t thread_address = 0;
+
+       retval = uCOS_III_find_last_thread_address(rtos, &thread_address);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to find last thread address");
+               return retval;
+       }
+
+       for (int i = 0; i < rtos->thread_count; i++) {
+               struct thread_detail *thread_detail = &rtos->thread_details[i];
+               char thread_str_buffer[UCOS_III_MAX_STRLEN + 1];
+
+               /* find or create new threadid */
+               retval = uCOS_III_find_or_create_thread(rtos,
+                                                       thread_address,
+                                                       &thread_detail->threadid);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to find or create thread");
+                       return retval;
+               }
+
+               if (thread_address == current_thread_address)
+                       rtos->current_thread = thread_detail->threadid;
+
+               thread_detail->exists = true;
+
+               /* read thread name */
+               symbol_address_t thread_name_address = 0;
+
+               retval = target_read_memory(rtos->target,
+                                           thread_address + params->thread_name_offset,
+                                           params->pointer_width,
+                                           1,
+                                           (void *)&thread_name_address);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to name address");
+                       return retval;
+               }
+
+               retval = target_read_buffer(rtos->target,
+                                           thread_name_address,
+                                           sizeof(thread_str_buffer),
+                                           (void *)thread_str_buffer);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to read thread name");
+                       return retval;
+               }
+
+               thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0';
+               thread_detail->thread_name_str = strdup(thread_str_buffer);
+
+               /* read thread extra info */
+               uint8_t thread_state;
+               uint8_t thread_priority;
+
+               retval = target_read_u8(rtos->target,
+                                       thread_address + params->thread_state_offset,
+                                       &thread_state);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to read thread state");
+                       return retval;
+               }
+
+               retval = target_read_u8(rtos->target,
+                                       thread_address + params->thread_priority_offset,
+                                       &thread_priority);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to read thread priority");
+                       return retval;
+               }
+
+               const char *thread_state_str;
+
+               if (thread_state < ARRAY_SIZE(uCOS_III_thread_state_list))
+                       thread_state_str = uCOS_III_thread_state_list[thread_state];
+               else
+                       thread_state_str = "Unknown";
+
+               snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d",
+                        thread_state_str, thread_priority);
+               thread_detail->extra_info_str = strdup(thread_str_buffer);
+
+               /* read previous thread address */
+               retval = target_read_memory(rtos->target,
+                                           thread_address + params->thread_prev_offset,
+                                           params->pointer_width,
+                                           1,
+                                           (void *)&thread_address);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("uCOS-III: failed to read previous thread address");
+                       return retval;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, char **hex_reg_list)
+{
+       struct uCOS_III_params *params = rtos->rtos_specific_params;
+       int retval;
+
+       /* find thread address for threadid */
+       symbol_address_t thread_address = 0;
+
+       retval = uCOS_III_find_thread_address(rtos, threadid, &thread_address);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to find thread address");
+               return retval;
+       }
+
+       /* read thread stack address */
+       symbol_address_t stack_address = 0;
+
+       retval = target_read_memory(rtos->target,
+                                   thread_address + params->thread_stack_offset,
+                                   params->pointer_width,
+                                   1,
+                                   (void *)&stack_address);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("uCOS-III: failed to read stack address");
+               return retval;
+       }
+
+       return rtos_generic_stack_read(rtos->target,
+                                      params->stacking_info,
+                                      stack_address,
+                                      hex_reg_list);
+}
+
+static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+{
+       *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t));
+       if (*symbol_list == NULL) {
+               LOG_ERROR("uCOS-III: out of memory");
+               return ERROR_FAIL;
+       }
+
+       for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_symbol_list); i++)
+               (*symbol_list)[i].symbol_name = uCOS_III_symbol_list[i];
+
+       return ERROR_OK;
+}
+
+const struct rtos_type uCOS_III_rtos = {
+       .name = "uCOS-III",
+       .detect_rtos = uCOS_III_detect_rtos,
+       .create = uCOS_III_create,
+       .update_threads = uCOS_III_update_threads,
+       .get_thread_reg_list = uCOS_III_get_thread_reg_list,
+       .get_symbol_list_to_lookup = uCOS_III_get_symbol_list_to_lookup,
+};

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)