rtos: check symbol list when updating uCOS-III
[openocd.git] / src / rtos / uCOS-III.c
1 /***************************************************************************
2 * Copyright (C) 2017 by Square, Inc. *
3 * Steven Stallion <stallion@squareup.com> *
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
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>
29
30 #include "rtos_ucos_iii_stackings.h"
31
32 #ifndef UCOS_III_MAX_STRLEN
33 #define UCOS_III_MAX_STRLEN 64
34 #endif
35
36 #ifndef UCOS_III_MAX_THREADS
37 #define UCOS_III_MAX_THREADS 256
38 #endif
39
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;
52 size_t num_threads;
53 symbol_address_t threads[];
54 };
55
56 static const struct uCOS_III_params uCOS_III_params_list[] = {
57 {
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 */
69 0, /* num_threads */
70 },
71 {
72 "esirisc", /* target_name */
73 sizeof(uint32_t), /* pointer_width */
74 0, /* thread_stack_offset */
75 0, /* thread_name_offset */
76 0, /* thread_state_offset */
77 0, /* thread_priority_offset */
78 0, /* thread_prev_offset */
79 0, /* thread_next_offset */
80 false, /* thread_offsets_updated */
81 1, /* threadid_start */
82 &rtos_uCOS_III_eSi_RISC_stacking, /* stacking_info */
83 0, /* num_threads */
84 },
85 };
86
87 static const char * const uCOS_III_symbol_list[] = {
88 "OSRunning",
89 "OSTCBCurPtr",
90 "OSTaskDbgListPtr",
91 "OSTaskQty",
92
93 /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
94 "openocd_OS_TCB_StkPtr_offset",
95 "openocd_OS_TCB_NamePtr_offset",
96 "openocd_OS_TCB_TaskState_offset",
97 "openocd_OS_TCB_Prio_offset",
98 "openocd_OS_TCB_DbgPrevPtr_offset",
99 "openocd_OS_TCB_DbgNextPtr_offset",
100 NULL
101 };
102
103 enum uCOS_III_symbol_values {
104 uCOS_III_VAL_OSRunning,
105 uCOS_III_VAL_OSTCBCurPtr,
106 uCOS_III_VAL_OSTaskDbgListPtr,
107 uCOS_III_VAL_OSTaskQty,
108
109 /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
110 uCOS_III_VAL_OS_TCB_StkPtr_offset,
111 uCOS_III_VAL_OS_TCB_NamePtr_offset,
112 uCOS_III_VAL_OS_TCB_TaskState_offset,
113 uCOS_III_VAL_OS_TCB_Prio_offset,
114 uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
115 uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
116 };
117
118 static const char * const uCOS_III_thread_state_list[] = {
119 "Ready",
120 "Delay",
121 "Pend",
122 "Pend Timeout",
123 "Suspended",
124 "Delay Suspended",
125 "Pend Suspended",
126 "Pend Timeout Suspended",
127 };
128
129 static int uCOS_III_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address,
130 threadid_t *threadid)
131 {
132 struct uCOS_III_params *params = rtos->rtos_specific_params;
133 size_t thread_index;
134
135 for (thread_index = 0; thread_index < params->num_threads; thread_index++)
136 if (params->threads[thread_index] == thread_address)
137 goto found;
138
139 if (params->num_threads == UCOS_III_MAX_THREADS) {
140 LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS");
141 return ERROR_FAIL;
142 }
143
144 params->threads[thread_index] = thread_address;
145 params->num_threads++;
146 found:
147 *threadid = thread_index + params->threadid_start;
148 return ERROR_OK;
149 }
150
151 static int uCOS_III_find_thread_address(struct rtos *rtos, threadid_t threadid,
152 symbol_address_t *thread_address)
153 {
154 struct uCOS_III_params *params = rtos->rtos_specific_params;
155 size_t thread_index;
156
157 thread_index = threadid - params->threadid_start;
158 if (thread_index >= params->num_threads) {
159 LOG_ERROR("uCOS-III: failed to find thread address");
160 return ERROR_FAIL;
161 }
162
163 *thread_address = params->threads[thread_index];
164 return ERROR_OK;
165 }
166
167 static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
168 {
169 struct uCOS_III_params *params = rtos->rtos_specific_params;
170 int retval;
171
172 /* read the thread list head */
173 symbol_address_t thread_list_address = 0;
174
175 retval = target_read_memory(rtos->target,
176 rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address,
177 params->pointer_width,
178 1,
179 (void *)&thread_list_address);
180 if (retval != ERROR_OK) {
181 LOG_ERROR("uCOS-III: failed to read thread list address");
182 return retval;
183 }
184
185 /* advance to end of thread list */
186 do {
187 *thread_address = thread_list_address;
188
189 retval = target_read_memory(rtos->target,
190 thread_list_address + params->thread_next_offset,
191 params->pointer_width,
192 1,
193 (void *)&thread_list_address);
194 if (retval != ERROR_OK) {
195 LOG_ERROR("uCOS-III: failed to read next thread address");
196 return retval;
197 }
198 } while (thread_list_address != 0);
199
200 return ERROR_OK;
201 }
202
203 static int uCOS_III_update_thread_offsets(struct rtos *rtos)
204 {
205 struct uCOS_III_params *params = rtos->rtos_specific_params;
206
207 if (params->thread_offsets_updated)
208 return ERROR_OK;
209
210 const struct thread_offset_map {
211 enum uCOS_III_symbol_values symbol_value;
212 symbol_address_t *thread_offset;
213 } thread_offset_maps[] = {
214 {
215 uCOS_III_VAL_OS_TCB_StkPtr_offset,
216 &params->thread_stack_offset,
217 },
218 {
219 uCOS_III_VAL_OS_TCB_NamePtr_offset,
220 &params->thread_name_offset,
221 },
222 {
223 uCOS_III_VAL_OS_TCB_TaskState_offset,
224 &params->thread_state_offset,
225 },
226 {
227 uCOS_III_VAL_OS_TCB_Prio_offset,
228 &params->thread_priority_offset,
229 },
230 {
231 uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
232 &params->thread_prev_offset,
233 },
234 {
235 uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
236 &params->thread_next_offset,
237 },
238 };
239
240 for (size_t i = 0; i < ARRAY_SIZE(thread_offset_maps); i++) {
241 const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i];
242
243 int retval = target_read_memory(rtos->target,
244 rtos->symbols[thread_offset_map->symbol_value].address,
245 params->pointer_width,
246 1,
247 (void *)thread_offset_map->thread_offset);
248 if (retval != ERROR_OK) {
249 LOG_ERROR("uCOS-III: failed to read thread offset");
250 return retval;
251 }
252 }
253
254 params->thread_offsets_updated = true;
255 return ERROR_OK;
256 }
257
258 static bool uCOS_III_detect_rtos(struct target *target)
259 {
260 return target->rtos->symbols != NULL &&
261 target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0;
262 }
263
264 static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
265 {
266 struct uCOS_III_params *params = target->rtos->rtos_specific_params;
267
268 params->thread_offsets_updated = false;
269 params->num_threads = 0;
270
271 return ERROR_OK;
272 }
273
274 static int uCOS_III_create(struct target *target)
275 {
276 struct uCOS_III_params *params;
277
278 for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_params_list); i++)
279 if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) {
280 params = malloc(sizeof(*params) + (UCOS_III_MAX_THREADS * sizeof(*params->threads)));
281 if (params == NULL) {
282 LOG_ERROR("uCOS-III: out of memory");
283 return ERROR_FAIL;
284 }
285
286 memcpy(params, &uCOS_III_params_list[i], sizeof(uCOS_III_params_list[i]));
287 target->rtos->rtos_specific_params = (void *)params;
288
289 target_register_reset_callback(uCOS_III_reset_handler, NULL);
290
291 return ERROR_OK;
292 }
293
294 LOG_ERROR("uCOS-III: target not supported: %s", target->type->name);
295 return ERROR_FAIL;
296 }
297
298 static int uCOS_III_update_threads(struct rtos *rtos)
299 {
300 struct uCOS_III_params *params = rtos->rtos_specific_params;
301 int retval;
302
303 if (rtos->symbols == NULL) {
304 LOG_ERROR("uCOS-III: symbol list not loaded");
305 return ERROR_FAIL;
306 }
307
308 /* free previous thread details */
309 rtos_free_threadlist(rtos);
310
311 /* verify RTOS is running */
312 uint8_t rtos_running;
313
314 retval = target_read_u8(rtos->target,
315 rtos->symbols[uCOS_III_VAL_OSRunning].address,
316 &rtos_running);
317 if (retval != ERROR_OK) {
318 LOG_ERROR("uCOS-III: failed to read RTOS running");
319 return retval;
320 }
321
322 if (rtos_running != 1 && rtos_running != 0) {
323 LOG_ERROR("uCOS-III: invalid RTOS running value");
324 return ERROR_FAIL;
325 }
326
327 if (!rtos_running) {
328 rtos->thread_details = calloc(1, sizeof(struct thread_detail));
329 if (rtos->thread_details == NULL) {
330 LOG_ERROR("uCOS-III: out of memory");
331 return ERROR_FAIL;
332 }
333
334 rtos->thread_count = 1;
335 rtos->thread_details->threadid = 0;
336 rtos->thread_details->exists = true;
337 rtos->current_thread = 0;
338
339 return ERROR_OK;
340 }
341
342 /* update thread offsets */
343 retval = uCOS_III_update_thread_offsets(rtos);
344 if (retval != ERROR_OK) {
345 LOG_ERROR("uCOS-III: failed to update thread offsets");
346 return retval;
347 }
348
349 /* read current thread address */
350 symbol_address_t current_thread_address = 0;
351
352 retval = target_read_memory(rtos->target,
353 rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address,
354 params->pointer_width,
355 1,
356 (void *)&current_thread_address);
357 if (retval != ERROR_OK) {
358 LOG_ERROR("uCOS-III: failed to read current thread address");
359 return retval;
360 }
361
362 /* read number of tasks */
363 retval = target_read_u16(rtos->target,
364 rtos->symbols[uCOS_III_VAL_OSTaskQty].address,
365 (void *)&rtos->thread_count);
366 if (retval != ERROR_OK) {
367 LOG_ERROR("uCOS-III: failed to read thread count");
368 return retval;
369 }
370
371 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
372 if (rtos->thread_details == NULL) {
373 LOG_ERROR("uCOS-III: out of memory");
374 return ERROR_FAIL;
375 }
376
377 /*
378 * uC/OS-III adds tasks in LIFO order; advance to the end of the
379 * list and work backwards to preserve the intended order.
380 */
381 symbol_address_t thread_address = 0;
382
383 retval = uCOS_III_find_last_thread_address(rtos, &thread_address);
384 if (retval != ERROR_OK) {
385 LOG_ERROR("uCOS-III: failed to find last thread address");
386 return retval;
387 }
388
389 for (int i = 0; i < rtos->thread_count; i++) {
390 struct thread_detail *thread_detail = &rtos->thread_details[i];
391 char thread_str_buffer[UCOS_III_MAX_STRLEN + 1];
392
393 /* find or create new threadid */
394 retval = uCOS_III_find_or_create_thread(rtos, thread_address, &thread_detail->threadid);
395 if (retval != ERROR_OK) {
396 LOG_ERROR("uCOS-III: failed to find or create thread");
397 return retval;
398 }
399
400 if (thread_address == current_thread_address)
401 rtos->current_thread = thread_detail->threadid;
402
403 thread_detail->exists = true;
404
405 /* read thread name */
406 symbol_address_t thread_name_address = 0;
407
408 retval = target_read_memory(rtos->target,
409 thread_address + params->thread_name_offset,
410 params->pointer_width,
411 1,
412 (void *)&thread_name_address);
413 if (retval != ERROR_OK) {
414 LOG_ERROR("uCOS-III: failed to name address");
415 return retval;
416 }
417
418 retval = target_read_buffer(rtos->target,
419 thread_name_address,
420 sizeof(thread_str_buffer),
421 (void *)thread_str_buffer);
422 if (retval != ERROR_OK) {
423 LOG_ERROR("uCOS-III: failed to read thread name");
424 return retval;
425 }
426
427 thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0';
428 thread_detail->thread_name_str = strdup(thread_str_buffer);
429
430 /* read thread extra info */
431 uint8_t thread_state;
432 uint8_t thread_priority;
433
434 retval = target_read_u8(rtos->target,
435 thread_address + params->thread_state_offset,
436 &thread_state);
437 if (retval != ERROR_OK) {
438 LOG_ERROR("uCOS-III: failed to read thread state");
439 return retval;
440 }
441
442 retval = target_read_u8(rtos->target,
443 thread_address + params->thread_priority_offset,
444 &thread_priority);
445 if (retval != ERROR_OK) {
446 LOG_ERROR("uCOS-III: failed to read thread priority");
447 return retval;
448 }
449
450 const char *thread_state_str;
451
452 if (thread_state < ARRAY_SIZE(uCOS_III_thread_state_list))
453 thread_state_str = uCOS_III_thread_state_list[thread_state];
454 else
455 thread_state_str = "Unknown";
456
457 snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d",
458 thread_state_str, thread_priority);
459 thread_detail->extra_info_str = strdup(thread_str_buffer);
460
461 /* read previous thread address */
462 retval = target_read_memory(rtos->target,
463 thread_address + params->thread_prev_offset,
464 params->pointer_width,
465 1,
466 (void *)&thread_address);
467 if (retval != ERROR_OK) {
468 LOG_ERROR("uCOS-III: failed to read previous thread address");
469 return retval;
470 }
471 }
472
473 return ERROR_OK;
474 }
475
476 static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
477 struct rtos_reg **reg_list, int *num_regs)
478 {
479 struct uCOS_III_params *params = rtos->rtos_specific_params;
480 int retval;
481
482 /* find thread address for threadid */
483 symbol_address_t thread_address = 0;
484
485 retval = uCOS_III_find_thread_address(rtos, threadid, &thread_address);
486 if (retval != ERROR_OK) {
487 LOG_ERROR("uCOS-III: failed to find thread address");
488 return retval;
489 }
490
491 /* read thread stack address */
492 symbol_address_t stack_address = 0;
493
494 retval = target_read_memory(rtos->target,
495 thread_address + params->thread_stack_offset,
496 params->pointer_width,
497 1,
498 (void *)&stack_address);
499 if (retval != ERROR_OK) {
500 LOG_ERROR("uCOS-III: failed to read stack address");
501 return retval;
502 }
503
504 return rtos_generic_stack_read(rtos->target,
505 params->stacking_info,
506 stack_address,
507 reg_list,
508 num_regs);
509 }
510
511 static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
512 {
513 *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t));
514 if (*symbol_list == NULL) {
515 LOG_ERROR("uCOS-III: out of memory");
516 return ERROR_FAIL;
517 }
518
519 for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_symbol_list); i++)
520 (*symbol_list)[i].symbol_name = uCOS_III_symbol_list[i];
521
522 return ERROR_OK;
523 }
524
525 const struct rtos_type uCOS_III_rtos = {
526 .name = "uCOS-III",
527 .detect_rtos = uCOS_III_detect_rtos,
528 .create = uCOS_III_create,
529 .update_threads = uCOS_III_update_threads,
530 .get_thread_reg_list = uCOS_III_get_thread_reg_list,
531 .get_symbol_list_to_lookup = uCOS_III_get_symbol_list_to_lookup,
532 };

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)