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 (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state))
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 ARM926EJS_REGISTERS_SIZE_SOLICITED
, /* stack_registers_size */
116 -1, /* stack_growth_direction */
117 17, /* num_output_registers */
118 NULL
, /* stack_alignment */
119 rtos_threadx_arm926ejs_stack_offsets_solicited
/* register_offsets */
122 ARM926EJS_REGISTERS_SIZE_INTERRUPT
, /* stack_registers_size */
123 -1, /* stack_growth_direction */
124 17, /* num_output_registers */
125 NULL
, /* stack_alignment */
126 rtos_threadx_arm926ejs_stack_offsets_interrupt
/* register_offsets */
130 struct ThreadX_params
{
131 const char *target_name
;
132 unsigned char pointer_width
;
133 unsigned char thread_stack_offset
;
134 unsigned char thread_name_offset
;
135 unsigned char thread_state_offset
;
136 unsigned char thread_next_offset
;
137 const struct rtos_register_stacking
*stacking_info
;
138 size_t stacking_info_nb
;
139 const struct rtos_register_stacking
* (*fn_get_stacking_info
)(const struct rtos
*rtos
, int64_t stack_ptr
);
140 int (*fn_is_thread_id_valid
)(const struct rtos
*rtos
, int64_t thread_id
);
143 static const struct ThreadX_params ThreadX_params_list
[] = {
145 "cortex_m", /* target_name */
146 4, /* pointer_width; */
147 8, /* thread_stack_offset; */
148 40, /* thread_name_offset; */
149 48, /* thread_state_offset; */
150 136, /* thread_next_offset */
151 &rtos_standard_Cortex_M3_stacking
, /* stacking_info */
152 1, /* stacking_info_nb */
153 NULL
, /* fn_get_stacking_info */
154 NULL
, /* fn_is_thread_id_valid */
157 "cortex_r4", /* target_name */
158 4, /* pointer_width; */
159 8, /* thread_stack_offset; */
160 40, /* thread_name_offset; */
161 48, /* thread_state_offset; */
162 136, /* thread_next_offset */
163 &rtos_standard_Cortex_R4_stacking
, /* stacking_info */
164 1, /* stacking_info_nb */
165 NULL
, /* fn_get_stacking_info */
166 NULL
, /* fn_is_thread_id_valid */
169 "arm926ejs", /* target_name */
170 4, /* pointer_width; */
171 8, /* thread_stack_offset; */
172 40, /* thread_name_offset; */
173 48, /* thread_state_offset; */
174 136, /* thread_next_offset */
175 rtos_threadx_arm926ejs_stacking
, /* stacking_info */
176 2, /* stacking_info_nb */
177 get_stacking_info_arm926ejs
, /* fn_get_stacking_info */
178 is_thread_id_valid_arm926ejs
, /* fn_is_thread_id_valid */
182 #define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params)))
184 enum ThreadX_symbol_values
{
185 ThreadX_VAL_tx_thread_current_ptr
= 0,
186 ThreadX_VAL_tx_thread_created_ptr
= 1,
187 ThreadX_VAL_tx_thread_created_count
= 2,
190 static const char * const ThreadX_symbol_list
[] = {
191 "_tx_thread_current_ptr",
192 "_tx_thread_created_ptr",
193 "_tx_thread_created_count",
197 const struct rtos_type ThreadX_rtos
= {
200 .detect_rtos
= ThreadX_detect_rtos
,
201 .create
= ThreadX_create
,
202 .update_threads
= ThreadX_update_threads
,
203 .get_thread_reg_list
= ThreadX_get_thread_reg_list
,
204 .get_symbol_list_to_lookup
= ThreadX_get_symbol_list_to_lookup
,
207 static const struct rtos_register_stacking
*get_stacking_info(const struct rtos
*rtos
, int64_t stack_ptr
)
209 const struct ThreadX_params
*param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
211 if (param
->fn_get_stacking_info
!= NULL
)
212 return param
->fn_get_stacking_info(rtos
, stack_ptr
);
214 return param
->stacking_info
+ 0;
217 static int is_thread_id_valid(const struct rtos
*rtos
, int64_t thread_id
)
219 const struct ThreadX_params
*param
;
221 if (rtos
->rtos_specific_params
== NULL
)
222 return 0; /* invalid */
224 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
226 if (param
->fn_is_thread_id_valid
!= NULL
)
227 return param
->fn_is_thread_id_valid(rtos
, thread_id
);
229 return (thread_id
!= 0);
232 static const struct rtos_register_stacking
*get_stacking_info_arm926ejs(const struct rtos
*rtos
, int64_t stack_ptr
)
234 const struct ThreadX_params
*param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
238 retval
= target_read_buffer(rtos
->target
,
242 if (retval
!= ERROR_OK
) {
243 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64
, stack_ptr
);
248 LOG_DEBUG(" solicited stack");
249 return param
->stacking_info
+ 0;
251 LOG_DEBUG(" interrupt stack: %" PRIu32
, flag
);
252 return param
->stacking_info
+ 1;
256 static int is_thread_id_valid_arm926ejs(const struct rtos
*rtos
, int64_t thread_id
)
258 return (thread_id
!= 0 && thread_id
!= 1);
261 static int ThreadX_update_threads(struct rtos
*rtos
)
265 int thread_list_size
= 0;
266 const struct ThreadX_params
*param
;
271 if (rtos
->rtos_specific_params
== NULL
)
274 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
276 if (rtos
->symbols
== NULL
) {
277 LOG_ERROR("No symbols for ThreadX");
281 if (rtos
->symbols
[ThreadX_VAL_tx_thread_created_count
].address
== 0) {
282 LOG_ERROR("Don't have the number of threads in ThreadX");
286 /* read the number of threads */
287 retval
= target_read_buffer(rtos
->target
,
288 rtos
->symbols
[ThreadX_VAL_tx_thread_created_count
].address
,
290 (uint8_t *)&thread_list_size
);
292 if (retval
!= ERROR_OK
) {
293 LOG_ERROR("Could not read ThreadX thread count from target");
297 /* wipe out previous thread details if any */
298 rtos_free_threadlist(rtos
);
300 /* read the current thread id */
301 retval
= target_read_buffer(rtos
->target
,
302 rtos
->symbols
[ThreadX_VAL_tx_thread_current_ptr
].address
,
304 (uint8_t *)&rtos
->current_thread
);
306 if (retval
!= ERROR_OK
) {
307 LOG_ERROR("Could not read ThreadX current thread from target");
311 if ((thread_list_size
== 0) || (rtos
->current_thread
== 0)) {
312 /* Either : No RTOS threads - there is always at least the current execution though */
313 /* OR : No current thread - all threads suspended - show the current execution
315 char tmp_str
[] = "Current Execution";
318 rtos
->thread_details
= malloc(
319 sizeof(struct thread_detail
) * thread_list_size
);
320 rtos
->thread_details
->threadid
= 1;
321 rtos
->thread_details
->exists
= true;
322 rtos
->thread_details
->extra_info_str
= NULL
;
323 rtos
->thread_details
->thread_name_str
= malloc(sizeof(tmp_str
));
324 strcpy(rtos
->thread_details
->thread_name_str
, tmp_str
);
326 if (thread_list_size
== 0) {
327 rtos
->thread_count
= 1;
331 /* create space for new thread details */
332 rtos
->thread_details
= malloc(
333 sizeof(struct thread_detail
) * thread_list_size
);
336 /* Read the pointer to the first thread */
337 int64_t thread_ptr
= 0;
338 retval
= target_read_buffer(rtos
->target
,
339 rtos
->symbols
[ThreadX_VAL_tx_thread_created_ptr
].address
,
340 param
->pointer_width
,
341 (uint8_t *)&thread_ptr
);
342 if (retval
!= ERROR_OK
) {
343 LOG_ERROR("Could not read ThreadX thread location from target");
347 /* loop over all threads */
348 int64_t prev_thread_ptr
= 0;
349 while ((thread_ptr
!= prev_thread_ptr
) && (tasks_found
< thread_list_size
)) {
351 #define THREADX_THREAD_NAME_STR_SIZE (200)
352 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
354 int64_t name_ptr
= 0;
356 /* Save the thread pointer */
357 rtos
->thread_details
[tasks_found
].threadid
= thread_ptr
;
359 /* read the name pointer */
360 retval
= target_read_buffer(rtos
->target
,
361 thread_ptr
+ param
->thread_name_offset
,
362 param
->pointer_width
,
363 (uint8_t *)&name_ptr
);
364 if (retval
!= ERROR_OK
) {
365 LOG_ERROR("Could not read ThreadX thread name pointer from target");
369 /* Read the thread name */
371 target_read_buffer(rtos
->target
,
373 THREADX_THREAD_NAME_STR_SIZE
,
374 (uint8_t *)&tmp_str
);
375 if (retval
!= ERROR_OK
) {
376 LOG_ERROR("Error reading thread name from ThreadX target");
379 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
381 if (tmp_str
[0] == '\x00')
382 strcpy(tmp_str
, "No Name");
384 rtos
->thread_details
[tasks_found
].thread_name_str
=
385 malloc(strlen(tmp_str
)+1);
386 strcpy(rtos
->thread_details
[tasks_found
].thread_name_str
, tmp_str
);
388 /* Read the thread status */
389 int64_t thread_status
= 0;
390 retval
= target_read_buffer(rtos
->target
,
391 thread_ptr
+ param
->thread_state_offset
,
393 (uint8_t *)&thread_status
);
394 if (retval
!= ERROR_OK
) {
395 LOG_ERROR("Error reading thread state from ThreadX target");
399 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
400 (ThreadX_thread_states
[i
].value
!= thread_status
); i
++) {
404 const char *state_desc
;
405 if (i
< THREADX_NUM_STATES
)
406 state_desc
= ThreadX_thread_states
[i
].desc
;
408 state_desc
= "Unknown state";
410 rtos
->thread_details
[tasks_found
].extra_info_str
= malloc(strlen(
412 sprintf(rtos
->thread_details
[tasks_found
].extra_info_str
, "State: %s", state_desc
);
414 rtos
->thread_details
[tasks_found
].exists
= true;
417 prev_thread_ptr
= thread_ptr
;
419 /* Get the location of the next thread structure. */
421 retval
= target_read_buffer(rtos
->target
,
422 prev_thread_ptr
+ param
->thread_next_offset
,
423 param
->pointer_width
,
424 (uint8_t *) &thread_ptr
);
425 if (retval
!= ERROR_OK
) {
426 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
431 rtos
->thread_count
= tasks_found
;
436 static int ThreadX_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
437 struct rtos_reg
**reg_list
, int *num_regs
)
440 const struct ThreadX_params
*param
;
445 if (!is_thread_id_valid(rtos
, thread_id
))
448 if (rtos
->rtos_specific_params
== NULL
)
451 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
453 /* Read the stack pointer */
454 int64_t stack_ptr
= 0;
455 retval
= target_read_buffer(rtos
->target
,
456 thread_id
+ param
->thread_stack_offset
,
457 param
->pointer_width
,
458 (uint8_t *)&stack_ptr
);
459 if (retval
!= ERROR_OK
) {
460 LOG_ERROR("Error reading stack frame from ThreadX thread");
464 LOG_INFO("thread: 0x%" PRIx64
", stack_ptr=0x%" PRIx64
, (uint64_t)thread_id
, (uint64_t)stack_ptr
);
466 if (stack_ptr
== 0) {
467 LOG_ERROR("null stack pointer in thread");
471 const struct rtos_register_stacking
*stacking_info
=
472 get_stacking_info(rtos
, stack_ptr
);
474 if (stacking_info
== NULL
) {
475 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64
, (uint64_t)thread_id
);
479 return rtos_generic_stack_read(rtos
->target
, stacking_info
, stack_ptr
, reg_list
, num_regs
);
482 static int ThreadX_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
485 *symbol_list
= calloc(
486 ARRAY_SIZE(ThreadX_symbol_list
), sizeof(struct symbol_table_elem
));
488 for (i
= 0; i
< ARRAY_SIZE(ThreadX_symbol_list
); i
++)
489 (*symbol_list
)[i
].symbol_name
= ThreadX_symbol_list
[i
];
494 static bool ThreadX_detect_rtos(struct target
*target
)
496 if ((target
->rtos
->symbols
!= NULL
) &&
497 (target
->rtos
->symbols
[ThreadX_VAL_tx_thread_created_ptr
].address
!= 0)) {
498 /* looks like ThreadX */
506 static int ThreadX_set_current_thread(struct rtos
*rtos
, threadid_t thread_id
)
511 static int ThreadX_get_thread_detail(struct rtos
*rtos
,
512 threadid_t thread_id
,
513 struct thread_detail
*detail
)
518 #define THREADX_THREAD_NAME_STR_SIZE (200)
519 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
521 const struct ThreadX_params
*param
;
529 if (rtos
->rtos_specific_params
== NULL
)
532 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
534 if (rtos
->symbols
== NULL
) {
535 LOG_ERROR("No symbols for ThreadX");
539 detail
->threadid
= thread_id
;
541 int64_t name_ptr
= 0;
542 /* read the name pointer */
543 retval
= target_read_buffer(rtos
->target
,
544 thread_id
+ param
->thread_name_offset
,
545 param
->pointer_width
,
546 (uint8_t *)&name_ptr
);
547 if (retval
!= ERROR_OK
) {
548 LOG_ERROR("Could not read ThreadX thread name pointer from target");
552 /* Read the thread name */
553 retval
= target_read_buffer(rtos
->target
,
555 THREADX_THREAD_NAME_STR_SIZE
,
556 (uint8_t *)&tmp_str
);
557 if (retval
!= ERROR_OK
) {
558 LOG_ERROR("Error reading thread name from ThreadX target");
561 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
563 if (tmp_str
[0] == '\x00')
564 strcpy(tmp_str
, "No Name");
566 detail
->thread_name_str
= malloc(strlen(tmp_str
)+1);
568 /* Read the thread status */
569 int64_t thread_status
= 0;
571 target_read_buffer(rtos
->target
,
572 thread_id
+ param
->thread_state_offset
,
574 (uint8_t *)&thread_status
);
575 if (retval
!= ERROR_OK
) {
576 LOG_ERROR("Error reading thread state from ThreadX target");
580 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
581 (ThreadX_thread_states
[i
].value
!= thread_status
); i
++) {
586 if (i
< THREADX_NUM_STATES
)
587 state_desc
= ThreadX_thread_states
[i
].desc
;
589 state_desc
= "Unknown state";
591 detail
->extra_info_str
= malloc(strlen(state_desc
)+1);
593 detail
->exists
= true;
600 static int ThreadX_create(struct target
*target
)
603 while ((i
< THREADX_NUM_PARAMS
) &&
604 (0 != strcmp(ThreadX_params_list
[i
].target_name
, target
->type
->name
))) {
607 if (i
>= THREADX_NUM_PARAMS
) {
608 LOG_ERROR("Could not find target in ThreadX compatibility list");
612 target
->rtos
->rtos_specific_params
= (void *) &ThreadX_params_list
[i
];
613 target
->rtos
->current_thread
= 0;
614 target
->rtos
->thread_details
= NULL
;
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)