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
, char **hex_reg_list
);
42 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t
*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
[] = {
76 { 0x08, 32 }, /* r4 */
77 { 0x0C, 32 }, /* r5 */
78 { 0x10, 32 }, /* r6 */
79 { 0x14, 32 }, /* r7 */
80 { 0x18, 32 }, /* r8 */
81 { 0x1C, 32 }, /* r9 */
82 { 0x20, 32 }, /* r10 */
83 { 0x24, 32 }, /* r11 */
85 { -2, 32 }, /* sp (r13) */
86 { 0x28, 32 }, /* lr (r14) */
87 { -1, 32 }, /* pc (r15) */
88 /*{ -1, 32 },*/ /* lr (r14) */
89 /*{ 0x28, 32 },*/ /* pc (r15) */
90 { 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 { 0x08, 32 }, /* r0 */
95 { 0x0C, 32 }, /* r1 */
96 { 0x10, 32 }, /* r2 */
97 { 0x14, 32 }, /* r3 */
98 { 0x18, 32 }, /* r4 */
99 { 0x1C, 32 }, /* r5 */
100 { 0x20, 32 }, /* r6 */
101 { 0x24, 32 }, /* r7 */
102 { 0x28, 32 }, /* r8 */
103 { 0x2C, 32 }, /* r9 */
104 { 0x30, 32 }, /* r10 */
105 { 0x34, 32 }, /* r11 */
106 { 0x38, 32 }, /* r12 */
107 { -2, 32 }, /* sp (r13) */
108 { 0x3C, 32 }, /* lr (r14) */
109 { 0x40, 32 }, /* pc (r15) */
110 { 0x04, 32 }, /* xPSR */
113 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: %u", 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
, char **hex_reg_list
)
439 const struct ThreadX_params
*param
;
441 *hex_reg_list
= NULL
;
446 if (!is_thread_id_valid(rtos
, thread_id
))
449 if (rtos
->rtos_specific_params
== NULL
)
452 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
454 /* Read the stack pointer */
455 int64_t stack_ptr
= 0;
456 retval
= target_read_buffer(rtos
->target
,
457 thread_id
+ param
->thread_stack_offset
,
458 param
->pointer_width
,
459 (uint8_t *)&stack_ptr
);
460 if (retval
!= ERROR_OK
) {
461 LOG_ERROR("Error reading stack frame from ThreadX thread");
465 LOG_INFO("thread: 0x%" PRIx64
", stack_ptr=0x%" PRIx64
, (uint64_t)thread_id
, (uint64_t)stack_ptr
);
467 if (stack_ptr
== 0) {
468 LOG_ERROR("null stack pointer in thread");
472 const struct rtos_register_stacking
*stacking_info
=
473 get_stacking_info(rtos
, stack_ptr
);
475 if (stacking_info
== NULL
) {
476 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64
, (uint64_t)thread_id
);
480 return rtos_generic_stack_read(rtos
->target
, stacking_info
, stack_ptr
, hex_reg_list
);
483 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
486 *symbol_list
= calloc(
487 ARRAY_SIZE(ThreadX_symbol_list
), sizeof(symbol_table_elem_t
));
489 for (i
= 0; i
< ARRAY_SIZE(ThreadX_symbol_list
); i
++)
490 (*symbol_list
)[i
].symbol_name
= ThreadX_symbol_list
[i
];
495 static bool ThreadX_detect_rtos(struct target
*target
)
497 if ((target
->rtos
->symbols
!= NULL
) &&
498 (target
->rtos
->symbols
[ThreadX_VAL_tx_thread_created_ptr
].address
!= 0)) {
499 /* looks like ThreadX */
507 static int ThreadX_set_current_thread(struct rtos
*rtos
, threadid_t thread_id
)
512 static int ThreadX_get_thread_detail(struct rtos
*rtos
,
513 threadid_t thread_id
,
514 struct thread_detail
*detail
)
519 #define THREADX_THREAD_NAME_STR_SIZE (200)
520 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
522 const struct ThreadX_params
*param
;
530 if (rtos
->rtos_specific_params
== NULL
)
533 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
535 if (rtos
->symbols
== NULL
) {
536 LOG_ERROR("No symbols for ThreadX");
540 detail
->threadid
= thread_id
;
542 int64_t name_ptr
= 0;
543 /* read the name pointer */
544 retval
= target_read_buffer(rtos
->target
,
545 thread_id
+ param
->thread_name_offset
,
546 param
->pointer_width
,
547 (uint8_t *)&name_ptr
);
548 if (retval
!= ERROR_OK
) {
549 LOG_ERROR("Could not read ThreadX thread name pointer from target");
553 /* Read the thread name */
554 retval
= target_read_buffer(rtos
->target
,
556 THREADX_THREAD_NAME_STR_SIZE
,
557 (uint8_t *)&tmp_str
);
558 if (retval
!= ERROR_OK
) {
559 LOG_ERROR("Error reading thread name from ThreadX target");
562 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
564 if (tmp_str
[0] == '\x00')
565 strcpy(tmp_str
, "No Name");
567 detail
->thread_name_str
= malloc(strlen(tmp_str
)+1);
569 /* Read the thread status */
570 int64_t thread_status
= 0;
572 target_read_buffer(rtos
->target
,
573 thread_id
+ param
->thread_state_offset
,
575 (uint8_t *)&thread_status
);
576 if (retval
!= ERROR_OK
) {
577 LOG_ERROR("Error reading thread state from ThreadX target");
581 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
582 (ThreadX_thread_states
[i
].value
!= thread_status
); i
++) {
587 if (i
< THREADX_NUM_STATES
)
588 state_desc
= ThreadX_thread_states
[i
].desc
;
590 state_desc
= "Unknown state";
592 detail
->extra_info_str
= malloc(strlen(state_desc
)+1);
594 detail
->exists
= true;
601 static int ThreadX_create(struct target
*target
)
604 while ((i
< THREADX_NUM_PARAMS
) &&
605 (0 != strcmp(ThreadX_params_list
[i
].target_name
, target
->type
->name
))) {
608 if (i
>= THREADX_NUM_PARAMS
) {
609 LOG_ERROR("Could not find target in ThreadX compatibility list");
613 target
->rtos
->rtos_specific_params
= (void *) &ThreadX_params_list
[i
];
614 target
->rtos
->current_thread
= 0;
615 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)