1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.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/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "rtos_standard_stackings.h"
32 static const struct rtos_register_stacking
*get_stacking_info(const struct rtos
*rtos
, int64_t stack_ptr
);
33 static const struct rtos_register_stacking
*get_stacking_info_arm926ejs(const struct rtos
*rtos
, int64_t stack_ptr
);
35 static int is_thread_id_valid(const struct rtos
*rtos
, int64_t thread_id
);
36 static int is_thread_id_valid_arm926ejs(const struct rtos
*rtos
, int64_t thread_id
);
38 static bool threadx_detect_rtos(struct target
*target
);
39 static int threadx_create(struct target
*target
);
40 static int threadx_update_threads(struct rtos
*rtos
);
41 static int threadx_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, struct rtos_reg
**reg_list
, int *num_regs
);
42 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[]);
46 struct threadx_thread_state
{
51 static const struct threadx_thread_state threadx_thread_states
[] = {
57 { 5, "Waiting - Queue" },
58 { 6, "Waiting - Semaphore" },
59 { 7, "Waiting - Event flag" },
60 { 8, "Waiting - Memory" },
61 { 9, "Waiting - Memory" },
62 { 10, "Waiting - I/O" },
63 { 11, "Waiting - Filesystem" },
64 { 12, "Waiting - Network" },
65 { 13, "Waiting - Mutex" },
68 #define THREADX_NUM_STATES ARRAY_SIZE(threadx_thread_states)
70 #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
71 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited
[] = {
72 { 0, -1, 32 }, /* r0 */
73 { 1, -1, 32 }, /* r1 */
74 { 2, -1, 32 }, /* r2 */
75 { 3, -1, 32 }, /* r3 */
76 { 4, 0x08, 32 }, /* r4 */
77 { 5, 0x0C, 32 }, /* r5 */
78 { 6, 0x10, 32 }, /* r6 */
79 { 7, 0x14, 32 }, /* r7 */
80 { 8, 0x18, 32 }, /* r8 */
81 { 9, 0x1C, 32 }, /* r9 */
82 { 10, 0x20, 32 }, /* r10 */
83 { 11, 0x24, 32 }, /* r11 */
84 { 12, -1, 32 }, /* r12 */
85 { 13, -2, 32 }, /* sp (r13) */
86 { 14, 0x28, 32 }, /* lr (r14) */
87 { 15, -1, 32 }, /* pc (r15) */
88 /*{ 16, -1, 32 },*/ /* lr (r14) */
89 /*{ 17, 0x28, 32 },*/ /* pc (r15) */
90 { 16, 0x04, 32 }, /* xPSR */
92 #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
93 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt
[] = {
94 { 0, 0x08, 32 }, /* r0 */
95 { 1, 0x0C, 32 }, /* r1 */
96 { 2, 0x10, 32 }, /* r2 */
97 { 3, 0x14, 32 }, /* r3 */
98 { 4, 0x18, 32 }, /* r4 */
99 { 5, 0x1C, 32 }, /* r5 */
100 { 6, 0x20, 32 }, /* r6 */
101 { 7, 0x24, 32 }, /* r7 */
102 { 8, 0x28, 32 }, /* r8 */
103 { 9, 0x2C, 32 }, /* r9 */
104 { 10, 0x30, 32 }, /* r10 */
105 { 11, 0x34, 32 }, /* r11 */
106 { 12, 0x38, 32 }, /* r12 */
107 { 13, -2, 32 }, /* sp (r13) */
108 { 14, 0x3C, 32 }, /* lr (r14) */
109 { 15, 0x40, 32 }, /* pc (r15) */
110 { 16, 0x04, 32 }, /* xPSR */
113 static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking
[] = {
115 .stack_registers_size
= ARM926EJS_REGISTERS_SIZE_SOLICITED
,
116 .stack_growth_direction
= -1,
117 .num_output_registers
= 17,
118 .register_offsets
= rtos_threadx_arm926ejs_stack_offsets_solicited
121 .stack_registers_size
= ARM926EJS_REGISTERS_SIZE_INTERRUPT
,
122 .stack_growth_direction
= -1,
123 .num_output_registers
= 17,
124 .register_offsets
= rtos_threadx_arm926ejs_stack_offsets_interrupt
128 struct threadx_params
{
129 const char *target_name
;
130 unsigned char pointer_width
;
131 unsigned char thread_stack_offset
;
132 unsigned char thread_name_offset
;
133 unsigned char thread_state_offset
;
134 unsigned char thread_next_offset
;
135 const struct rtos_register_stacking
*stacking_info
;
136 size_t stacking_info_nb
;
137 const struct rtos_register_stacking
* (*fn_get_stacking_info
)(const struct rtos
*rtos
, int64_t stack_ptr
);
138 int (*fn_is_thread_id_valid
)(const struct rtos
*rtos
, int64_t thread_id
);
141 static const struct threadx_params threadx_params_list
[] = {
143 "cortex_m", /* target_name */
144 4, /* pointer_width; */
145 8, /* thread_stack_offset; */
146 40, /* thread_name_offset; */
147 48, /* thread_state_offset; */
148 136, /* thread_next_offset */
149 &rtos_standard_cortex_m3_stacking
, /* stacking_info */
150 1, /* stacking_info_nb */
151 NULL
, /* fn_get_stacking_info */
152 NULL
, /* fn_is_thread_id_valid */
155 "cortex_r4", /* target_name */
156 4, /* pointer_width; */
157 8, /* thread_stack_offset; */
158 40, /* thread_name_offset; */
159 48, /* thread_state_offset; */
160 136, /* thread_next_offset */
161 &rtos_standard_cortex_r4_stacking
, /* stacking_info */
162 1, /* stacking_info_nb */
163 NULL
, /* fn_get_stacking_info */
164 NULL
, /* fn_is_thread_id_valid */
167 "arm926ejs", /* target_name */
168 4, /* pointer_width; */
169 8, /* thread_stack_offset; */
170 40, /* thread_name_offset; */
171 48, /* thread_state_offset; */
172 136, /* thread_next_offset */
173 rtos_threadx_arm926ejs_stacking
, /* stacking_info */
174 2, /* stacking_info_nb */
175 get_stacking_info_arm926ejs
, /* fn_get_stacking_info */
176 is_thread_id_valid_arm926ejs
, /* fn_is_thread_id_valid */
180 enum threadx_symbol_values
{
181 THREADX_VAL_TX_THREAD_CURRENT_PTR
= 0,
182 THREADX_VAL_TX_THREAD_CREATED_PTR
= 1,
183 THREADX_VAL_TX_THREAD_CREATED_COUNT
= 2,
186 static const char * const threadx_symbol_list
[] = {
187 "_tx_thread_current_ptr",
188 "_tx_thread_created_ptr",
189 "_tx_thread_created_count",
193 const struct rtos_type threadx_rtos
= {
196 .detect_rtos
= threadx_detect_rtos
,
197 .create
= threadx_create
,
198 .update_threads
= threadx_update_threads
,
199 .get_thread_reg_list
= threadx_get_thread_reg_list
,
200 .get_symbol_list_to_lookup
= threadx_get_symbol_list_to_lookup
,
203 static const struct rtos_register_stacking
*get_stacking_info(const struct rtos
*rtos
, int64_t stack_ptr
)
205 const struct threadx_params
*param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
207 if (param
->fn_get_stacking_info
)
208 return param
->fn_get_stacking_info(rtos
, stack_ptr
);
210 return param
->stacking_info
+ 0;
213 static int is_thread_id_valid(const struct rtos
*rtos
, int64_t thread_id
)
215 const struct threadx_params
*param
;
217 if (!rtos
->rtos_specific_params
)
218 return 0; /* invalid */
220 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
222 if (param
->fn_is_thread_id_valid
)
223 return param
->fn_is_thread_id_valid(rtos
, thread_id
);
225 return (thread_id
!= 0);
228 static const struct rtos_register_stacking
*get_stacking_info_arm926ejs(const struct rtos
*rtos
, int64_t stack_ptr
)
230 const struct threadx_params
*param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
234 retval
= target_read_buffer(rtos
->target
,
238 if (retval
!= ERROR_OK
) {
239 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64
, stack_ptr
);
244 LOG_DEBUG(" solicited stack");
245 return param
->stacking_info
+ 0;
247 LOG_DEBUG(" interrupt stack: %" PRIu32
, flag
);
248 return param
->stacking_info
+ 1;
252 static int is_thread_id_valid_arm926ejs(const struct rtos
*rtos
, int64_t thread_id
)
254 return (thread_id
!= 0 && thread_id
!= 1);
257 static int threadx_update_threads(struct rtos
*rtos
)
261 int thread_list_size
= 0;
262 const struct threadx_params
*param
;
267 if (!rtos
->rtos_specific_params
)
270 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
272 if (!rtos
->symbols
) {
273 LOG_ERROR("No symbols for ThreadX");
277 if (rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_COUNT
].address
== 0) {
278 LOG_ERROR("Don't have the number of threads in ThreadX");
282 /* read the number of threads */
283 retval
= target_read_buffer(rtos
->target
,
284 rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_COUNT
].address
,
286 (uint8_t *)&thread_list_size
);
288 if (retval
!= ERROR_OK
) {
289 LOG_ERROR("Could not read ThreadX thread count from target");
293 /* wipe out previous thread details if any */
294 rtos_free_threadlist(rtos
);
296 /* read the current thread id */
297 retval
= target_read_buffer(rtos
->target
,
298 rtos
->symbols
[THREADX_VAL_TX_THREAD_CURRENT_PTR
].address
,
300 (uint8_t *)&rtos
->current_thread
);
302 if (retval
!= ERROR_OK
) {
303 LOG_ERROR("Could not read ThreadX current thread from target");
307 if ((thread_list_size
== 0) || (rtos
->current_thread
== 0)) {
308 /* Either : No RTOS threads - there is always at least the current execution though */
309 /* OR : No current thread - all threads suspended - show the current execution
311 char tmp_str
[] = "Current Execution";
314 rtos
->thread_details
= malloc(
315 sizeof(struct thread_detail
) * thread_list_size
);
316 rtos
->thread_details
->threadid
= 1;
317 rtos
->thread_details
->exists
= true;
318 rtos
->thread_details
->extra_info_str
= NULL
;
319 rtos
->thread_details
->thread_name_str
= malloc(sizeof(tmp_str
));
320 strcpy(rtos
->thread_details
->thread_name_str
, tmp_str
);
322 if (thread_list_size
== 0) {
323 rtos
->thread_count
= 1;
327 /* create space for new thread details */
328 rtos
->thread_details
= malloc(
329 sizeof(struct thread_detail
) * thread_list_size
);
332 /* Read the pointer to the first thread */
333 int64_t thread_ptr
= 0;
334 retval
= target_read_buffer(rtos
->target
,
335 rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_PTR
].address
,
336 param
->pointer_width
,
337 (uint8_t *)&thread_ptr
);
338 if (retval
!= ERROR_OK
) {
339 LOG_ERROR("Could not read ThreadX thread location from target");
343 /* loop over all threads */
344 int64_t prev_thread_ptr
= 0;
345 while ((thread_ptr
!= prev_thread_ptr
) && (tasks_found
< thread_list_size
)) {
347 #define THREADX_THREAD_NAME_STR_SIZE (200)
348 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
350 int64_t name_ptr
= 0;
352 /* Save the thread pointer */
353 rtos
->thread_details
[tasks_found
].threadid
= thread_ptr
;
355 /* read the name pointer */
356 retval
= target_read_buffer(rtos
->target
,
357 thread_ptr
+ param
->thread_name_offset
,
358 param
->pointer_width
,
359 (uint8_t *)&name_ptr
);
360 if (retval
!= ERROR_OK
) {
361 LOG_ERROR("Could not read ThreadX thread name pointer from target");
365 /* Read the thread name */
367 target_read_buffer(rtos
->target
,
369 THREADX_THREAD_NAME_STR_SIZE
,
370 (uint8_t *)&tmp_str
);
371 if (retval
!= ERROR_OK
) {
372 LOG_ERROR("Error reading thread name from ThreadX target");
375 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
377 if (tmp_str
[0] == '\x00')
378 strcpy(tmp_str
, "No Name");
380 rtos
->thread_details
[tasks_found
].thread_name_str
=
381 malloc(strlen(tmp_str
)+1);
382 strcpy(rtos
->thread_details
[tasks_found
].thread_name_str
, tmp_str
);
384 /* Read the thread status */
385 int64_t thread_status
= 0;
386 retval
= target_read_buffer(rtos
->target
,
387 thread_ptr
+ param
->thread_state_offset
,
389 (uint8_t *)&thread_status
);
390 if (retval
!= ERROR_OK
) {
391 LOG_ERROR("Error reading thread state from ThreadX target");
395 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
396 (threadx_thread_states
[i
].value
!= thread_status
); i
++) {
400 const char *state_desc
;
401 if (i
< THREADX_NUM_STATES
)
402 state_desc
= threadx_thread_states
[i
].desc
;
404 state_desc
= "Unknown state";
406 rtos
->thread_details
[tasks_found
].extra_info_str
= malloc(strlen(
408 sprintf(rtos
->thread_details
[tasks_found
].extra_info_str
, "State: %s", state_desc
);
410 rtos
->thread_details
[tasks_found
].exists
= true;
413 prev_thread_ptr
= thread_ptr
;
415 /* Get the location of the next thread structure. */
417 retval
= target_read_buffer(rtos
->target
,
418 prev_thread_ptr
+ param
->thread_next_offset
,
419 param
->pointer_width
,
420 (uint8_t *) &thread_ptr
);
421 if (retval
!= ERROR_OK
) {
422 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
427 rtos
->thread_count
= tasks_found
;
432 static int threadx_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
433 struct rtos_reg
**reg_list
, int *num_regs
)
436 const struct threadx_params
*param
;
441 if (!is_thread_id_valid(rtos
, thread_id
))
444 if (!rtos
->rtos_specific_params
)
447 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
449 /* Read the stack pointer */
450 int64_t stack_ptr
= 0;
451 retval
= target_read_buffer(rtos
->target
,
452 thread_id
+ param
->thread_stack_offset
,
453 param
->pointer_width
,
454 (uint8_t *)&stack_ptr
);
455 if (retval
!= ERROR_OK
) {
456 LOG_ERROR("Error reading stack frame from ThreadX thread");
460 LOG_INFO("thread: 0x%" PRIx64
", stack_ptr=0x%" PRIx64
, (uint64_t)thread_id
, (uint64_t)stack_ptr
);
462 if (stack_ptr
== 0) {
463 LOG_ERROR("null stack pointer in thread");
467 const struct rtos_register_stacking
*stacking_info
=
468 get_stacking_info(rtos
, stack_ptr
);
470 if (!stacking_info
) {
471 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64
, (uint64_t)thread_id
);
475 return rtos_generic_stack_read(rtos
->target
, stacking_info
, stack_ptr
, reg_list
, num_regs
);
478 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
481 *symbol_list
= calloc(
482 ARRAY_SIZE(threadx_symbol_list
), sizeof(struct symbol_table_elem
));
484 for (i
= 0; i
< ARRAY_SIZE(threadx_symbol_list
); i
++)
485 (*symbol_list
)[i
].symbol_name
= threadx_symbol_list
[i
];
490 static bool threadx_detect_rtos(struct target
*target
)
492 if ((target
->rtos
->symbols
) &&
493 (target
->rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_PTR
].address
!= 0)) {
494 /* looks like ThreadX */
502 static int threadx_set_current_thread(struct rtos
*rtos
, threadid_t thread_id
)
507 static int threadx_get_thread_detail(struct rtos
*rtos
,
508 threadid_t thread_id
,
509 struct thread_detail
*detail
)
514 #define THREADX_THREAD_NAME_STR_SIZE (200)
515 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
517 const struct threadx_params
*param
;
525 if (!rtos
->rtos_specific_params
)
528 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
530 if (!rtos
->symbols
) {
531 LOG_ERROR("No symbols for ThreadX");
535 detail
->threadid
= thread_id
;
537 int64_t name_ptr
= 0;
538 /* read the name pointer */
539 retval
= target_read_buffer(rtos
->target
,
540 thread_id
+ param
->thread_name_offset
,
541 param
->pointer_width
,
542 (uint8_t *)&name_ptr
);
543 if (retval
!= ERROR_OK
) {
544 LOG_ERROR("Could not read ThreadX thread name pointer from target");
548 /* Read the thread name */
549 retval
= target_read_buffer(rtos
->target
,
551 THREADX_THREAD_NAME_STR_SIZE
,
552 (uint8_t *)&tmp_str
);
553 if (retval
!= ERROR_OK
) {
554 LOG_ERROR("Error reading thread name from ThreadX target");
557 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
559 if (tmp_str
[0] == '\x00')
560 strcpy(tmp_str
, "No Name");
562 detail
->thread_name_str
= malloc(strlen(tmp_str
)+1);
564 /* Read the thread status */
565 int64_t thread_status
= 0;
567 target_read_buffer(rtos
->target
,
568 thread_id
+ param
->thread_state_offset
,
570 (uint8_t *)&thread_status
);
571 if (retval
!= ERROR_OK
) {
572 LOG_ERROR("Error reading thread state from ThreadX target");
576 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
577 (threadx_thread_states
[i
].value
!= thread_status
); i
++) {
582 if (i
< THREADX_NUM_STATES
)
583 state_desc
= threadx_thread_states
[i
].desc
;
585 state_desc
= "Unknown state";
587 detail
->extra_info_str
= malloc(strlen(state_desc
)+1);
589 detail
->exists
= true;
596 static int threadx_create(struct target
*target
)
598 for (unsigned int i
= 0; i
< ARRAY_SIZE(threadx_params_list
); i
++)
599 if (strcmp(threadx_params_list
[i
].target_name
, target
->type
->name
) == 0) {
600 target
->rtos
->rtos_specific_params
= (void *)&threadx_params_list
[i
];
601 target
->rtos
->current_thread
= 0;
602 target
->rtos
->thread_details
= NULL
;
606 LOG_ERROR("Could not find target in ThreadX compatibility list");
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)