OpenOCD
uCOS-III.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2017 by Square, Inc. *
5  * Steven Stallion <stallion@squareup.com> *
6  ***************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11 
12 #include <helper/log.h>
13 #include <helper/time_support.h>
14 #include <helper/types.h>
15 #include <rtos/rtos.h>
16 #include <target/target.h>
17 
19 
20 #ifndef UCOS_III_MAX_STRLEN
21 #define UCOS_III_MAX_STRLEN 64
22 #endif
23 
24 #ifndef UCOS_III_MAX_THREADS
25 #define UCOS_III_MAX_THREADS 256
26 #endif
27 
29  const char *target_name;
30  const unsigned char pointer_width;
33 };
34 
36  const struct ucos_iii_params *params;
44  size_t num_threads;
46 };
47 
48 static const struct ucos_iii_params ucos_iii_params_list[] = {
49  {
50  .target_name = "cortex_m",
51  .pointer_width = sizeof(uint32_t),
52  .threadid_start = 1,
54  },
55  {
56  .target_name = "esirisc",
57  .pointer_width = sizeof(uint32_t),
58  .threadid_start = 1,
60  },
61 };
62 
63 static const char * const ucos_iii_symbol_list[] = {
64  "OSRunning",
65  "OSTCBCurPtr",
66  "OSTaskDbgListPtr",
67  "OSTaskQty",
68 
69  /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
70  "openocd_OS_TCB_StkPtr_offset",
71  "openocd_OS_TCB_NamePtr_offset",
72  "openocd_OS_TCB_TaskState_offset",
73  "openocd_OS_TCB_Prio_offset",
74  "openocd_OS_TCB_DbgPrevPtr_offset",
75  "openocd_OS_TCB_DbgNextPtr_offset",
76  NULL
77 };
78 
84 
85  /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
92 };
93 
94 static const char * const ucos_iii_thread_state_list[] = {
95  "Ready",
96  "Delay",
97  "Pend",
98  "Pend Timeout",
99  "Suspended",
100  "Delay Suspended",
101  "Pend Suspended",
102  "Pend Timeout Suspended",
103 };
104 
105 static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address,
106  threadid_t *threadid)
107 {
109  size_t thread_index;
110 
111  for (thread_index = 0; thread_index < params->num_threads; thread_index++)
112  if (params->threads[thread_index] == thread_address)
113  goto found;
114 
115  if (params->num_threads == UCOS_III_MAX_THREADS) {
116  LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS");
117  return ERROR_FAIL;
118  }
119 
120  params->threads[thread_index] = thread_address;
121  params->num_threads++;
122 found:
123  *threadid = thread_index + params->params->threadid_start;
124  return ERROR_OK;
125 }
126 
127 static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid,
128  symbol_address_t *thread_address)
129 {
131  size_t thread_index;
132 
133  thread_index = threadid - params->params->threadid_start;
134  if (thread_index >= params->num_threads) {
135  LOG_ERROR("uCOS-III: failed to find thread address");
136  return ERROR_FAIL;
137  }
138 
139  *thread_address = params->threads[thread_index];
140  return ERROR_OK;
141 }
142 
143 static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
144 {
146  int retval;
147 
148  /* read the thread list head */
149  symbol_address_t thread_list_address = 0;
150 
151  retval = target_read_memory(rtos->target,
153  params->params->pointer_width,
154  1,
155  (void *)&thread_list_address);
156  if (retval != ERROR_OK) {
157  LOG_ERROR("uCOS-III: failed to read thread list address");
158  return retval;
159  }
160 
161  /* advance to end of thread list */
162  do {
163  *thread_address = thread_list_address;
164 
165  retval = target_read_memory(rtos->target,
166  thread_list_address + params->thread_next_offset,
167  params->params->pointer_width,
168  1,
169  (void *)&thread_list_address);
170  if (retval != ERROR_OK) {
171  LOG_ERROR("uCOS-III: failed to read next thread address");
172  return retval;
173  }
174  } while (thread_list_address != 0);
175 
176  return ERROR_OK;
177 }
178 
180 {
182 
183  if (params->thread_offsets_updated)
184  return ERROR_OK;
185 
186  const struct thread_offset_map {
187  enum ucos_iii_symbol_values symbol_value;
188  symbol_address_t *thread_offset;
189  } thread_offset_maps[] = {
190  {
192  &params->thread_stack_offset,
193  },
194  {
196  &params->thread_name_offset,
197  },
198  {
200  &params->thread_state_offset,
201  },
202  {
204  &params->thread_priority_offset,
205  },
206  {
208  &params->thread_prev_offset,
209  },
210  {
212  &params->thread_next_offset,
213  },
214  };
215 
216  for (size_t i = 0; i < ARRAY_SIZE(thread_offset_maps); i++) {
217  const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i];
218 
219  int retval = target_read_memory(rtos->target,
220  rtos->symbols[thread_offset_map->symbol_value].address,
221  params->params->pointer_width,
222  1,
223  (void *)thread_offset_map->thread_offset);
224  if (retval != ERROR_OK) {
225  LOG_ERROR("uCOS-III: failed to read thread offset");
226  return retval;
227  }
228  }
229 
230  params->thread_offsets_updated = true;
231  return ERROR_OK;
232 }
233 
234 static bool ucos_iii_detect_rtos(struct target *target)
235 {
236  return target->rtos->symbols &&
238 }
239 
240 static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
241 {
243 
244  params->thread_offsets_updated = false;
245  params->num_threads = 0;
246 
247  return ERROR_OK;
248 }
249 
250 static int ucos_iii_create(struct target *target)
251 {
252  struct ucos_iii_private *params;
253 
254  for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_params_list); i++)
256  params = calloc(1, sizeof(*params));
257  if (!params) {
258  LOG_ERROR("uCOS-III: out of memory");
259  return ERROR_FAIL;
260  }
261 
262  params->params = &ucos_iii_params_list[i];
264 
266 
267  return ERROR_OK;
268  }
269 
270  LOG_ERROR("uCOS-III: target not supported: %s", target_type_name(target));
271  return ERROR_FAIL;
272 }
273 
274 static int ucos_iii_update_threads(struct rtos *rtos)
275 {
277  int retval;
278 
279  if (!rtos->symbols) {
280  LOG_ERROR("uCOS-III: symbol list not loaded");
281  return ERROR_FAIL;
282  }
283 
284  /* free previous thread details */
286 
287  /* verify RTOS is running */
288  uint8_t rtos_running;
289 
290  retval = target_read_u8(rtos->target,
292  &rtos_running);
293  if (retval != ERROR_OK) {
294  LOG_ERROR("uCOS-III: failed to read RTOS running");
295  return retval;
296  }
297 
298  if (rtos_running != 1 && rtos_running != 0) {
299  LOG_ERROR("uCOS-III: invalid RTOS running value");
300  return ERROR_FAIL;
301  }
302 
303  if (!rtos_running) {
304  rtos->thread_details = calloc(1, sizeof(struct thread_detail));
305  if (!rtos->thread_details) {
306  LOG_ERROR("uCOS-III: out of memory");
307  return ERROR_FAIL;
308  }
309 
310  rtos->thread_count = 1;
312  rtos->thread_details->exists = true;
313  rtos->current_thread = 0;
314 
315  return ERROR_OK;
316  }
317 
318  /* update thread offsets */
320  if (retval != ERROR_OK) {
321  LOG_ERROR("uCOS-III: failed to update thread offsets");
322  return retval;
323  }
324 
325  /* read current thread address */
326  symbol_address_t current_thread_address = 0;
327 
328  retval = target_read_memory(rtos->target,
330  params->params->pointer_width,
331  1,
332  (void *)&current_thread_address);
333  if (retval != ERROR_OK) {
334  LOG_ERROR("uCOS-III: failed to read current thread address");
335  return retval;
336  }
337 
338  /* read number of tasks */
339  retval = target_read_u16(rtos->target,
341  (void *)&rtos->thread_count);
342  if (retval != ERROR_OK) {
343  LOG_ERROR("uCOS-III: failed to read thread count");
344  return retval;
345  }
346 
347  rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
348  if (!rtos->thread_details) {
349  LOG_ERROR("uCOS-III: out of memory");
350  return ERROR_FAIL;
351  }
352 
353  /*
354  * uC/OS-III adds tasks in LIFO order; advance to the end of the
355  * list and work backwards to preserve the intended order.
356  */
357  symbol_address_t thread_address = 0;
358 
359  retval = ucos_iii_find_last_thread_address(rtos, &thread_address);
360  if (retval != ERROR_OK) {
361  LOG_ERROR("uCOS-III: failed to find last thread address");
362  return retval;
363  }
364 
365  for (int i = 0; i < rtos->thread_count; i++) {
367  char thread_str_buffer[UCOS_III_MAX_STRLEN + 1];
368 
369  /* find or create new threadid */
370  retval = ucos_iii_find_or_create_thread(rtos, thread_address, &thread_detail->threadid);
371  if (retval != ERROR_OK) {
372  LOG_ERROR("uCOS-III: failed to find or create thread");
373  return retval;
374  }
375 
376  if (thread_address == current_thread_address)
378 
379  thread_detail->exists = true;
380 
381  /* read thread name */
382  symbol_address_t thread_name_address = 0;
383 
384  retval = target_read_memory(rtos->target,
385  thread_address + params->thread_name_offset,
386  params->params->pointer_width,
387  1,
388  (void *)&thread_name_address);
389  if (retval != ERROR_OK) {
390  LOG_ERROR("uCOS-III: failed to name address");
391  return retval;
392  }
393 
394  retval = target_read_buffer(rtos->target,
395  thread_name_address,
396  sizeof(thread_str_buffer),
397  (void *)thread_str_buffer);
398  if (retval != ERROR_OK) {
399  LOG_ERROR("uCOS-III: failed to read thread name");
400  return retval;
401  }
402 
403  thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0';
404  thread_detail->thread_name_str = strdup(thread_str_buffer);
405 
406  /* read thread extra info */
407  uint8_t thread_state;
408  uint8_t thread_priority;
409 
410  retval = target_read_u8(rtos->target,
411  thread_address + params->thread_state_offset,
412  &thread_state);
413  if (retval != ERROR_OK) {
414  LOG_ERROR("uCOS-III: failed to read thread state");
415  return retval;
416  }
417 
418  retval = target_read_u8(rtos->target,
419  thread_address + params->thread_priority_offset,
420  &thread_priority);
421  if (retval != ERROR_OK) {
422  LOG_ERROR("uCOS-III: failed to read thread priority");
423  return retval;
424  }
425 
426  const char *thread_state_str;
427 
428  if (thread_state < ARRAY_SIZE(ucos_iii_thread_state_list))
429  thread_state_str = ucos_iii_thread_state_list[thread_state];
430  else
431  thread_state_str = "Unknown";
432 
433  snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d",
434  thread_state_str, thread_priority);
435  thread_detail->extra_info_str = strdup(thread_str_buffer);
436 
437  /* read previous thread address */
438  retval = target_read_memory(rtos->target,
439  thread_address + params->thread_prev_offset,
440  params->params->pointer_width,
441  1,
442  (void *)&thread_address);
443  if (retval != ERROR_OK) {
444  LOG_ERROR("uCOS-III: failed to read previous thread address");
445  return retval;
446  }
447  }
448 
449  return ERROR_OK;
450 }
451 
453  struct rtos_reg **reg_list, int *num_regs)
454 {
456  int retval;
457 
458  /* find thread address for threadid */
459  symbol_address_t thread_address = 0;
460 
461  retval = ucos_iii_find_thread_address(rtos, threadid, &thread_address);
462  if (retval != ERROR_OK) {
463  LOG_ERROR("uCOS-III: failed to find thread address");
464  return retval;
465  }
466 
467  /* read thread stack address */
468  symbol_address_t stack_address = 0;
469 
470  retval = target_read_memory(rtos->target,
471  thread_address + params->thread_stack_offset,
472  params->params->pointer_width,
473  1,
474  (void *)&stack_address);
475  if (retval != ERROR_OK) {
476  LOG_ERROR("uCOS-III: failed to read stack address");
477  return retval;
478  }
479 
481  params->params->stacking_info,
482  stack_address,
483  reg_list,
484  num_regs);
485 }
486 
487 static int ucos_iii_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
488 {
489  *symbol_list = calloc(ARRAY_SIZE(ucos_iii_symbol_list), sizeof(struct symbol_table_elem));
490  if (!*symbol_list) {
491  LOG_ERROR("uCOS-III: out of memory");
492  return ERROR_FAIL;
493  }
494 
495  for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_symbol_list); i++)
496  (*symbol_list)[i].symbol_name = ucos_iii_symbol_list[i];
497 
498  return ERROR_OK;
499 }
500 
501 const struct rtos_type ucos_iii_rtos = {
502  .name = "uCOS-III",
503  .detect_rtos = ucos_iii_detect_rtos,
504  .create = ucos_iii_create,
505  .update_threads = ucos_iii_update_threads,
506  .get_thread_reg_list = ucos_iii_get_thread_reg_list,
507  .get_symbol_list_to_lookup = ucos_iii_get_symbol_list_to_lookup,
508 };
static struct esp_usb_jtag * priv
Definition: esp_usb_jtag.c:219
#define LOG_WARNING(expr ...)
Definition: log.h:129
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define ERROR_OK
Definition: log.h:164
static const struct rtos_register_stacking * stacking_info
Definition: riot.c:72
int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs)
Definition: rtos.c:602
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:695
int64_t symbol_address_t
Definition: rtos.h:16
int64_t threadid_t
Definition: rtos.h:15
const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking
const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking
Definition: rtos.h:53
Definition: rtos.h:59
const char * name
Definition: rtos.h:60
Definition: rtos.h:36
int thread_count
Definition: rtos.h:47
struct thread_detail * thread_details
Definition: rtos.h:46
struct symbol_table_elem * symbols
Definition: rtos.h:39
struct target * target
Definition: rtos.h:40
void * rtos_specific_params
Definition: rtos.h:50
threadid_t current_thread
Definition: rtos.h:45
Table should be terminated by an element with NULL in symbol_name.
Definition: rtos.h:23
symbol_address_t address
Definition: rtos.h:25
Definition: target.h:116
struct rtos * rtos
Definition: target.h:183
char * extra_info_str
Definition: rtos.h:33
char * thread_name_str
Definition: rtos.h:32
bool exists
Definition: rtos.h:31
threadid_t threadid
Definition: rtos.h:30
Definition: linux.c:56
const struct rtos_register_stacking * stacking_info
Definition: uCOS-III.c:32
const unsigned char pointer_width
Definition: uCOS-III.c:30
size_t threadid_start
Definition: uCOS-III.c:31
const char * target_name
Definition: uCOS-III.c:29
symbol_address_t thread_state_offset
Definition: uCOS-III.c:39
symbol_address_t thread_prev_offset
Definition: uCOS-III.c:41
symbol_address_t thread_stack_offset
Definition: uCOS-III.c:37
const struct ucos_iii_params * params
Definition: uCOS-III.c:36
bool thread_offsets_updated
Definition: uCOS-III.c:43
symbol_address_t thread_name_offset
Definition: uCOS-III.c:38
symbol_address_t thread_next_offset
Definition: uCOS-III.c:42
symbol_address_t thread_priority_offset
Definition: uCOS-III.c:40
size_t num_threads
Definition: uCOS-III.c:44
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2407
int target_read_u8(struct target *target, target_addr_t address, uint8_t *value)
Definition: target.c:2598
int target_read_u16(struct target *target, target_addr_t address, uint16_t *value)
Definition: target.c:2574
int target_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
Read count items of size bytes from the memory of target at the address given.
Definition: target.c:1237
int target_register_reset_callback(int(*callback)(struct target *target, enum target_reset_mode reset_mode, void *priv), void *priv)
Definition: target.c:1614
const char * target_type_name(const struct target *target)
Get the target type name.
Definition: target.c:736
target_reset_mode
Definition: target.h:61
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
Definition: uCOS-III.c:240
static int ucos_iii_update_threads(struct rtos *rtos)
Definition: uCOS-III.c:274
ucos_iii_symbol_values
Definition: uCOS-III.c:79
@ UCOS_III_VAL_OS_TCB_CUR_PTR
Definition: uCOS-III.c:81
@ UCOS_III_VAL_OS_TCB_PRIO_OFFSET
Definition: uCOS-III.c:89
@ UCOS_III_VAL_OS_TASK_QTY
Definition: uCOS-III.c:83
@ UCOS_III_VAL_OS_RUNNING
Definition: uCOS-III.c:80
@ UCOS_III_VAL_OS_TCB_NAME_PTR_OFFSET
Definition: uCOS-III.c:87
@ UCOS_III_VAL_OS_TCB_DBG_PREV_PTR_OFFSET
Definition: uCOS-III.c:90
@ UCOS_III_VAL_OS_TCB_TASK_STATE_OFFSET
Definition: uCOS-III.c:88
@ UCOS_III_VAL_OS_TASK_DBG_LIST_PTR
Definition: uCOS-III.c:82
@ UCOS_III_VAL_OS_TCB_STK_PTR_OFFSET
Definition: uCOS-III.c:86
@ UCOS_III_VAL_OS_TCB_DBG_NEXT_PTR_OFFSET
Definition: uCOS-III.c:91
static const char *const ucos_iii_thread_state_list[]
Definition: uCOS-III.c:94
static const struct ucos_iii_params ucos_iii_params_list[]
Definition: uCOS-III.c:48
#define UCOS_III_MAX_STRLEN
Definition: uCOS-III.c:21
static int ucos_iii_create(struct target *target)
Definition: uCOS-III.c:250
static const char *const ucos_iii_symbol_list[]
Definition: uCOS-III.c:63
static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address, threadid_t *threadid)
Definition: uCOS-III.c:105
static int ucos_iii_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: uCOS-III.c:487
static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid, symbol_address_t *thread_address)
Definition: uCOS-III.c:127
static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, struct rtos_reg **reg_list, int *num_regs)
Definition: uCOS-III.c:452
const struct rtos_type ucos_iii_rtos
Definition: uCOS-III.c:501
#define UCOS_III_MAX_THREADS
Definition: uCOS-III.c:25
static bool ucos_iii_detect_rtos(struct target *target)
Definition: uCOS-III.c:234
static int ucos_iii_update_thread_offsets(struct rtos *rtos)
Definition: uCOS-III.c:179
static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
Definition: uCOS-III.c:143
#define NULL
Definition: usb.h:16