1 /***************************************************************************
2 * Copyright (C) 2017 by Square, Inc. *
3 * Steven Stallion <stallion@squareup.com> *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
23 #include <helper/log.h>
24 #include <helper/time_support.h>
25 #include <helper/types.h>
26 #include <rtos/rtos.h>
27 #include <target/target.h>
28 #include <target/target_type.h>
30 #include "rtos_ucos_iii_stackings.h"
32 #ifndef UCOS_III_MAX_STRLEN
33 #define UCOS_III_MAX_STRLEN 64
36 #ifndef UCOS_III_MAX_THREADS
37 #define UCOS_III_MAX_THREADS 256
40 struct uCOS_III_params
{
41 const char *target_name
;
42 const unsigned char pointer_width
;
43 symbol_address_t thread_stack_offset
;
44 symbol_address_t thread_name_offset
;
45 symbol_address_t thread_state_offset
;
46 symbol_address_t thread_priority_offset
;
47 symbol_address_t thread_prev_offset
;
48 symbol_address_t thread_next_offset
;
49 bool thread_offsets_updated
;
50 size_t threadid_start
;
51 const struct rtos_register_stacking
*stacking_info
;
53 symbol_address_t threads
[];
56 static const struct uCOS_III_params uCOS_III_params_list
[] = {
58 "cortex_m", /* target_name */
59 sizeof(uint32_t), /* pointer_width */
60 0, /* thread_stack_offset */
61 0, /* thread_name_offset */
62 0, /* thread_state_offset */
63 0, /* thread_priority_offset */
64 0, /* thread_prev_offset */
65 0, /* thread_next_offset */
66 false, /* thread_offsets_updated */
67 1, /* threadid_start */
68 &rtos_uCOS_III_Cortex_M_stacking
, /* stacking_info */
73 static const char * const uCOS_III_symbol_list
[] = {
79 /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
80 "openocd_OS_TCB_StkPtr_offset",
81 "openocd_OS_TCB_NamePtr_offset",
82 "openocd_OS_TCB_TaskState_offset",
83 "openocd_OS_TCB_Prio_offset",
84 "openocd_OS_TCB_DbgPrevPtr_offset",
85 "openocd_OS_TCB_DbgNextPtr_offset",
89 enum uCOS_III_symbol_values
{
90 uCOS_III_VAL_OSRunning
,
91 uCOS_III_VAL_OSTCBCurPtr
,
92 uCOS_III_VAL_OSTaskDbgListPtr
,
93 uCOS_III_VAL_OSTaskQty
,
95 /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
96 uCOS_III_VAL_OS_TCB_StkPtr_offset
,
97 uCOS_III_VAL_OS_TCB_NamePtr_offset
,
98 uCOS_III_VAL_OS_TCB_TaskState_offset
,
99 uCOS_III_VAL_OS_TCB_Prio_offset
,
100 uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset
,
101 uCOS_III_VAL_OS_TCB_DbgNextPtr_offset
,
104 static const char * const uCOS_III_thread_state_list
[] = {
112 "Pend Timeout Suspended",
115 static int uCOS_III_find_or_create_thread(struct rtos
*rtos
, symbol_address_t thread_address
,
116 threadid_t
*threadid
)
118 struct uCOS_III_params
*params
= rtos
->rtos_specific_params
;
121 for (thread_index
= 0; thread_index
< params
->num_threads
; thread_index
++)
122 if (params
->threads
[thread_index
] == thread_address
)
125 if (params
->num_threads
== UCOS_III_MAX_THREADS
) {
126 LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS");
130 params
->threads
[thread_index
] = thread_address
;
131 params
->num_threads
++;
133 *threadid
= thread_index
+ params
->threadid_start
;
137 static int uCOS_III_find_thread_address(struct rtos
*rtos
, threadid_t threadid
,
138 symbol_address_t
*thread_address
)
140 struct uCOS_III_params
*params
= rtos
->rtos_specific_params
;
143 thread_index
= threadid
- params
->threadid_start
;
144 if (thread_index
>= params
->num_threads
) {
145 LOG_ERROR("uCOS-III: failed to find thread address");
149 *thread_address
= params
->threads
[thread_index
];
153 static int uCOS_III_find_last_thread_address(struct rtos
*rtos
, symbol_address_t
*thread_address
)
155 struct uCOS_III_params
*params
= rtos
->rtos_specific_params
;
158 /* read the thread list head */
159 symbol_address_t thread_list_address
= 0;
161 retval
= target_read_memory(rtos
->target
,
162 rtos
->symbols
[uCOS_III_VAL_OSTaskDbgListPtr
].address
,
163 params
->pointer_width
,
165 (void *)&thread_list_address
);
166 if (retval
!= ERROR_OK
) {
167 LOG_ERROR("uCOS-III: failed to read thread list address");
171 /* advance to end of thread list */
173 *thread_address
= thread_list_address
;
175 retval
= target_read_memory(rtos
->target
,
176 thread_list_address
+ params
->thread_next_offset
,
177 params
->pointer_width
,
179 (void *)&thread_list_address
);
180 if (retval
!= ERROR_OK
) {
181 LOG_ERROR("uCOS-III: failed to read next thread address");
184 } while (thread_list_address
!= 0);
189 static int uCOS_III_update_thread_offsets(struct rtos
*rtos
)
191 struct uCOS_III_params
*params
= rtos
->rtos_specific_params
;
193 if (params
->thread_offsets_updated
)
196 const struct thread_offset_map
{
197 enum uCOS_III_symbol_values symbol_value
;
198 symbol_address_t
*thread_offset
;
199 } thread_offset_maps
[] = {
201 uCOS_III_VAL_OS_TCB_StkPtr_offset
,
202 ¶ms
->thread_stack_offset
,
205 uCOS_III_VAL_OS_TCB_NamePtr_offset
,
206 ¶ms
->thread_name_offset
,
209 uCOS_III_VAL_OS_TCB_TaskState_offset
,
210 ¶ms
->thread_state_offset
,
213 uCOS_III_VAL_OS_TCB_Prio_offset
,
214 ¶ms
->thread_priority_offset
,
217 uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset
,
218 ¶ms
->thread_prev_offset
,
221 uCOS_III_VAL_OS_TCB_DbgNextPtr_offset
,
222 ¶ms
->thread_next_offset
,
226 for (size_t i
= 0; i
< ARRAY_SIZE(thread_offset_maps
); i
++) {
227 const struct thread_offset_map
*thread_offset_map
= &thread_offset_maps
[i
];
229 int retval
= target_read_memory(rtos
->target
,
230 rtos
->symbols
[thread_offset_map
->symbol_value
].address
,
231 params
->pointer_width
,
233 (void *)thread_offset_map
->thread_offset
);
234 if (retval
!= ERROR_OK
) {
235 LOG_ERROR("uCOS-III: failed to read thread offset");
240 params
->thread_offsets_updated
= true;
244 static bool uCOS_III_detect_rtos(struct target
*target
)
246 return target
->rtos
->symbols
!= NULL
&&
247 target
->rtos
->symbols
[uCOS_III_VAL_OSRunning
].address
!= 0;
250 static int uCOS_III_reset_handler(struct target
*target
, enum target_reset_mode reset_mode
, void *priv
)
252 struct uCOS_III_params
*params
= target
->rtos
->rtos_specific_params
;
254 params
->thread_offsets_updated
= false;
255 params
->num_threads
= 0;
260 static int uCOS_III_create(struct target
*target
)
262 struct uCOS_III_params
*params
;
264 for (size_t i
= 0; i
< ARRAY_SIZE(uCOS_III_params_list
); i
++)
265 if (strcmp(uCOS_III_params_list
[i
].target_name
, target
->type
->name
) == 0) {
266 params
= malloc(sizeof(*params
) + (UCOS_III_MAX_THREADS
* sizeof(*params
->threads
)));
267 if (params
== NULL
) {
268 LOG_ERROR("uCOS-III: out of memory");
272 memcpy(params
, &uCOS_III_params_list
[i
], sizeof(uCOS_III_params_list
[i
]));
273 target
->rtos
->rtos_specific_params
= (void *)params
;
275 target_register_reset_callback(uCOS_III_reset_handler
, NULL
);
280 LOG_ERROR("uCOS-III: target not supported: %s", target
->type
->name
);
284 static int uCOS_III_update_threads(struct rtos
*rtos
)
286 struct uCOS_III_params
*params
= rtos
->rtos_specific_params
;
289 /* free previous thread details */
290 rtos_free_threadlist(rtos
);
292 /* verify RTOS is running */
293 uint8_t rtos_running
;
295 retval
= target_read_u8(rtos
->target
,
296 rtos
->symbols
[uCOS_III_VAL_OSRunning
].address
,
298 if (retval
!= ERROR_OK
) {
299 LOG_ERROR("uCOS-III: failed to read RTOS running");
303 if (rtos_running
!= 1 && rtos_running
!= 0) {
304 LOG_ERROR("uCOS-III: invalid RTOS running value");
309 rtos
->thread_details
= calloc(1, sizeof(struct thread_detail
));
310 if (rtos
->thread_details
== NULL
) {
311 LOG_ERROR("uCOS-III: out of memory");
315 rtos
->thread_count
= 1;
316 rtos
->thread_details
->threadid
= 0;
317 rtos
->thread_details
->exists
= true;
318 rtos
->current_thread
= 0;
323 /* update thread offsets */
324 retval
= uCOS_III_update_thread_offsets(rtos
);
325 if (retval
!= ERROR_OK
) {
326 LOG_ERROR("uCOS-III: failed to update thread offsets");
330 /* read current thread address */
331 symbol_address_t current_thread_address
= 0;
333 retval
= target_read_memory(rtos
->target
,
334 rtos
->symbols
[uCOS_III_VAL_OSTCBCurPtr
].address
,
335 params
->pointer_width
,
337 (void *)¤t_thread_address
);
338 if (retval
!= ERROR_OK
) {
339 LOG_ERROR("uCOS-III: failed to read current thread address");
343 /* read number of tasks */
344 retval
= target_read_u16(rtos
->target
,
345 rtos
->symbols
[uCOS_III_VAL_OSTaskQty
].address
,
346 (void *)&rtos
->thread_count
);
347 if (retval
!= ERROR_OK
) {
348 LOG_ERROR("uCOS-III: failed to read thread count");
352 rtos
->thread_details
= calloc(rtos
->thread_count
, sizeof(struct thread_detail
));
353 if (rtos
->thread_details
== NULL
) {
354 LOG_ERROR("uCOS-III: out of memory");
359 * uC/OS-III adds tasks in LIFO order; advance to the end of the
360 * list and work backwards to preserve the intended order.
362 symbol_address_t thread_address
= 0;
364 retval
= uCOS_III_find_last_thread_address(rtos
, &thread_address
);
365 if (retval
!= ERROR_OK
) {
366 LOG_ERROR("uCOS-III: failed to find last thread address");
370 for (int i
= 0; i
< rtos
->thread_count
; i
++) {
371 struct thread_detail
*thread_detail
= &rtos
->thread_details
[i
];
372 char thread_str_buffer
[UCOS_III_MAX_STRLEN
+ 1];
374 /* find or create new threadid */
375 retval
= uCOS_III_find_or_create_thread(rtos
, thread_address
, &thread_detail
->threadid
);
376 if (retval
!= ERROR_OK
) {
377 LOG_ERROR("uCOS-III: failed to find or create thread");
381 if (thread_address
== current_thread_address
)
382 rtos
->current_thread
= thread_detail
->threadid
;
384 thread_detail
->exists
= true;
386 /* read thread name */
387 symbol_address_t thread_name_address
= 0;
389 retval
= target_read_memory(rtos
->target
,
390 thread_address
+ params
->thread_name_offset
,
391 params
->pointer_width
,
393 (void *)&thread_name_address
);
394 if (retval
!= ERROR_OK
) {
395 LOG_ERROR("uCOS-III: failed to name address");
399 retval
= target_read_buffer(rtos
->target
,
401 sizeof(thread_str_buffer
),
402 (void *)thread_str_buffer
);
403 if (retval
!= ERROR_OK
) {
404 LOG_ERROR("uCOS-III: failed to read thread name");
408 thread_str_buffer
[sizeof(thread_str_buffer
) - 1] = '\0';
409 thread_detail
->thread_name_str
= strdup(thread_str_buffer
);
411 /* read thread extra info */
412 uint8_t thread_state
;
413 uint8_t thread_priority
;
415 retval
= target_read_u8(rtos
->target
,
416 thread_address
+ params
->thread_state_offset
,
418 if (retval
!= ERROR_OK
) {
419 LOG_ERROR("uCOS-III: failed to read thread state");
423 retval
= target_read_u8(rtos
->target
,
424 thread_address
+ params
->thread_priority_offset
,
426 if (retval
!= ERROR_OK
) {
427 LOG_ERROR("uCOS-III: failed to read thread priority");
431 const char *thread_state_str
;
433 if (thread_state
< ARRAY_SIZE(uCOS_III_thread_state_list
))
434 thread_state_str
= uCOS_III_thread_state_list
[thread_state
];
436 thread_state_str
= "Unknown";
438 snprintf(thread_str_buffer
, sizeof(thread_str_buffer
), "State: %s, Priority: %d",
439 thread_state_str
, thread_priority
);
440 thread_detail
->extra_info_str
= strdup(thread_str_buffer
);
442 /* read previous thread address */
443 retval
= target_read_memory(rtos
->target
,
444 thread_address
+ params
->thread_prev_offset
,
445 params
->pointer_width
,
447 (void *)&thread_address
);
448 if (retval
!= ERROR_OK
) {
449 LOG_ERROR("uCOS-III: failed to read previous thread address");
457 static int uCOS_III_get_thread_reg_list(struct rtos
*rtos
, threadid_t threadid
, char **hex_reg_list
)
459 struct uCOS_III_params
*params
= rtos
->rtos_specific_params
;
462 /* find thread address for threadid */
463 symbol_address_t thread_address
= 0;
465 retval
= uCOS_III_find_thread_address(rtos
, threadid
, &thread_address
);
466 if (retval
!= ERROR_OK
) {
467 LOG_ERROR("uCOS-III: failed to find thread address");
471 /* read thread stack address */
472 symbol_address_t stack_address
= 0;
474 retval
= target_read_memory(rtos
->target
,
475 thread_address
+ params
->thread_stack_offset
,
476 params
->pointer_width
,
478 (void *)&stack_address
);
479 if (retval
!= ERROR_OK
) {
480 LOG_ERROR("uCOS-III: failed to read stack address");
484 return rtos_generic_stack_read(rtos
->target
,
485 params
->stacking_info
,
490 static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
492 *symbol_list
= calloc(ARRAY_SIZE(uCOS_III_symbol_list
), sizeof(symbol_table_elem_t
));
493 if (*symbol_list
== NULL
) {
494 LOG_ERROR("uCOS-III: out of memory");
498 for (size_t i
= 0; i
< ARRAY_SIZE(uCOS_III_symbol_list
); i
++)
499 (*symbol_list
)[i
].symbol_name
= uCOS_III_symbol_list
[i
];
504 const struct rtos_type uCOS_III_rtos
= {
506 .detect_rtos
= uCOS_III_detect_rtos
,
507 .create
= uCOS_III_create
,
508 .update_threads
= uCOS_III_update_threads
,
509 .get_thread_reg_list
= uCOS_III_get_thread_reg_list
,
510 .get_symbol_list_to_lookup
= uCOS_III_get_symbol_list_to_lookup
,