rtos: add support for uC/OS-III

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>
gitignore-build
Steven Stallion 2016-07-15 22:01:00 -05:00 committed by Paul Fertser
parent 29964c7984
commit 1eae39b40d
7 changed files with 653 additions and 10 deletions

View File

@ -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);

View File

@ -4123,7 +4123,8 @@ The value should normally correspond to a static mapping for the
@anchor{rtostype} @anchor{rtostype}
@item @code{-rtos} @var{rtos_type} -- enable rtos support for target, @item @code{-rtos} @var{rtos_type} -- enable rtos support for target,
@var{rtos_type} can be one of @option{auto}|@option{eCos}|@option{ThreadX}| @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}. @xref{gdbrtossupport,,RTOS Support}.
@item @code{-defer-examine} -- skip target examination at initial JTAG chain @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{ChibiOS}
@item @option{embKernel} @item @option{embKernel}
@item @option{mqx} @item @option{mqx}
@item @option{uCOS-III}
@end itemize @end itemize
@quotation Note @quotation Note
@ -8866,10 +8868,12 @@ Rtos::sCurrentTask, Rtos::sListReady, Rtos::sListSleep,
Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount. Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount.
@item mqx symbols @item mqx symbols
_mqx_kernel_data, MQX_init_struct. _mqx_kernel_data, MQX_init_struct.
@item uC/OS-III symbols
OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty
@end table @end table
For most RTOS supported the above symbols will be exported by default. However for 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 These RTOSes may require additional OpenOCD-specific file to be linked
along with the project: along with the project:
@ -8877,6 +8881,8 @@ along with the project:
@table @code @table @code
@item FreeRTOS @item FreeRTOS
contrib/rtos-helpers/FreeRTOS-openocd.c contrib/rtos-helpers/FreeRTOS-openocd.c
@item uC/OS-III
contrib/rtos-helpers/uCOS-III-openocd.c
@end table @end table
@node Tcl Scripting API @node Tcl Scripting API

View File

@ -20,8 +20,8 @@ include $(top_srcdir)/common.mk
METASOURCES = AUTO METASOURCES = AUTO
noinst_LTLIBRARIES = librtos.la 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 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 FreeRTOS.c ThreadX.c eCos.c linux.c ChibiOS.c embKernel.c mqx.c 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 = librtos_la_CFLAGS =
if IS_MINGW if IS_MINGW

View File

@ -34,6 +34,7 @@ extern struct rtos_type Linux_os;
extern struct rtos_type ChibiOS_rtos; extern struct rtos_type ChibiOS_rtos;
extern struct rtos_type embKernel_rtos; extern struct rtos_type embKernel_rtos;
extern struct rtos_type mqx_rtos; extern struct rtos_type mqx_rtos;
extern struct rtos_type uCOS_III_rtos;
static struct rtos_type *rtos_types[] = { static struct rtos_type *rtos_types[] = {
&ThreadX_rtos, &ThreadX_rtos,
@ -43,6 +44,7 @@ static struct rtos_type *rtos_types[] = {
&ChibiOS_rtos, &ChibiOS_rtos,
&embKernel_rtos, &embKernel_rtos,
&mqx_rtos, &mqx_rtos,
&uCOS_III_rtos,
NULL 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 } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
* all other operations ) */ * all other operations ) */
if ((packet[1] == 'g') && (target->rtos != NULL)) { if ((packet[1] == 'g') && (target->rtos != NULL)) {
sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid); threadid_t threadid;
LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64 "\r\n", sscanf(packet, "Hg%16" SCNx64, &threadid);
target->rtos->current_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); gdb_put_packet(connection, "OK", 2);
return ERROR_OK; return ERROR_OK;
@ -426,9 +433,13 @@ int rtos_get_gdb_reg_list(struct connection *connection)
current_threadid, current_threadid,
target->rtos->current_thread); target->rtos->current_thread);
target->rtos->type->get_thread_reg_list(target->rtos, int retval = target->rtos->type->get_thread_reg_list(target->rtos,
current_threadid, current_threadid,
&hex_reg_list); &hex_reg_list);
if (retval != ERROR_OK) {
LOG_ERROR("RTOS: failed to get register list");
return retval;
}
if (hex_reg_list != NULL) { if (hex_reg_list != NULL) {
gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list)); 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); free(rtos->thread_details);
rtos->thread_details = NULL; rtos->thread_details = NULL;
rtos->thread_count = 0; rtos->thread_count = 0;
rtos->current_threadid = -1;
rtos->current_thread = 0;
} }
} }

View File

@ -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 */
};

View File

@ -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 */

509
src/rtos/uCOS-III.c Normal file
View File

@ -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,
};