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, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "rtos_standard_stackings.h"
34 static const struct rtos_register_stacking
*get_stacking_info(const struct rtos
*rtos
, int64_t stack_ptr
);
35 static const struct rtos_register_stacking
*get_stacking_info_arm926ejs(const struct rtos
*rtos
, int64_t stack_ptr
);
37 static int is_thread_id_valid(const struct rtos
*rtos
, int64_t thread_id
);
38 static int is_thread_id_valid_arm926ejs(const struct rtos
*rtos
, int64_t thread_id
);
40 static int ThreadX_detect_rtos(struct target
*target
);
41 static int ThreadX_create(struct target
*target
);
42 static int ThreadX_update_threads(struct rtos
*rtos
);
43 static int ThreadX_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
);
44 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[]);
48 struct ThreadX_thread_state
{
53 static const struct ThreadX_thread_state ThreadX_thread_states
[] = {
59 { 5, "Waiting - Queue" },
60 { 6, "Waiting - Semaphore" },
61 { 7, "Waiting - Event flag" },
62 { 8, "Waiting - Memory" },
63 { 9, "Waiting - Memory" },
64 { 10, "Waiting - I/O" },
65 { 11, "Waiting - Filesystem" },
66 { 12, "Waiting - Network" },
67 { 13, "Waiting - Mutex" },
70 #define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state))
72 #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
73 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited
[] = {
78 { 0x08, 32 }, /* r4 */
79 { 0x0C, 32 }, /* r5 */
80 { 0x10, 32 }, /* r6 */
81 { 0x14, 32 }, /* r7 */
82 { 0x18, 32 }, /* r8 */
83 { 0x1C, 32 }, /* r9 */
84 { 0x20, 32 }, /* r10 */
85 { 0x24, 32 }, /* r11 */
87 { -2, 32 }, /* sp (r13) */
88 { 0x28, 32 }, /* lr (r14) */
89 { -1, 32 }, /* pc (r15) */
90 /*{ -1, 32 },*/ /* lr (r14) */
91 /*{ 0x28, 32 },*/ /* pc (r15) */
92 { 0x04, 32 }, /* xPSR */
94 #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
95 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt
[] = {
96 { 0x08, 32 }, /* r0 */
97 { 0x0C, 32 }, /* r1 */
98 { 0x10, 32 }, /* r2 */
99 { 0x14, 32 }, /* r3 */
100 { 0x18, 32 }, /* r4 */
101 { 0x1C, 32 }, /* r5 */
102 { 0x20, 32 }, /* r6 */
103 { 0x24, 32 }, /* r7 */
104 { 0x28, 32 }, /* r8 */
105 { 0x2C, 32 }, /* r9 */
106 { 0x30, 32 }, /* r10 */
107 { 0x34, 32 }, /* r11 */
108 { 0x38, 32 }, /* r12 */
109 { -2, 32 }, /* sp (r13) */
110 { 0x3C, 32 }, /* lr (r14) */
111 { 0x40, 32 }, /* pc (r15) */
112 { 0x04, 32 }, /* xPSR */
115 const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking
[] = {
117 ARM926EJS_REGISTERS_SIZE_SOLICITED
, /* stack_registers_size */
118 -1, /* stack_growth_direction */
119 17, /* num_output_registers */
120 0, /* stack_alignment */
121 rtos_threadx_arm926ejs_stack_offsets_solicited
/* register_offsets */
124 ARM926EJS_REGISTERS_SIZE_INTERRUPT
, /* stack_registers_size */
125 -1, /* stack_growth_direction */
126 17, /* num_output_registers */
127 0, /* stack_alignment */
128 rtos_threadx_arm926ejs_stack_offsets_interrupt
/* register_offsets */
132 struct ThreadX_params
{
133 const char *target_name
;
134 unsigned char pointer_width
;
135 unsigned char thread_stack_offset
;
136 unsigned char thread_name_offset
;
137 unsigned char thread_state_offset
;
138 unsigned char thread_next_offset
;
139 const struct rtos_register_stacking
*stacking_info
;
140 size_t stacking_info_nb
;
141 const struct rtos_register_stacking
* (*fn_get_stacking_info
)(const struct rtos
*rtos
, int64_t stack_ptr
);
142 int (*fn_is_thread_id_valid
)(const struct rtos
*rtos
, int64_t thread_id
);
145 static const struct ThreadX_params ThreadX_params_list
[] = {
147 "cortex_m", /* target_name */
148 4, /* pointer_width; */
149 8, /* thread_stack_offset; */
150 40, /* thread_name_offset; */
151 48, /* thread_state_offset; */
152 136, /* thread_next_offset */
153 &rtos_standard_Cortex_M3_stacking
, /* stacking_info */
154 1, /* stacking_info_nb */
155 NULL
, /* fn_get_stacking_info */
156 NULL
, /* fn_is_thread_id_valid */
159 "cortex_r4", /* target_name */
160 4, /* pointer_width; */
161 8, /* thread_stack_offset; */
162 40, /* thread_name_offset; */
163 48, /* thread_state_offset; */
164 136, /* thread_next_offset */
165 &rtos_standard_Cortex_R4_stacking
, /* stacking_info */
166 1, /* stacking_info_nb */
167 NULL
, /* fn_get_stacking_info */
168 NULL
, /* fn_is_thread_id_valid */
171 "arm926ejs", /* target_name */
172 4, /* pointer_width; */
173 8, /* thread_stack_offset; */
174 40, /* thread_name_offset; */
175 48, /* thread_state_offset; */
176 136, /* thread_next_offset */
177 rtos_threadx_arm926ejs_stacking
, /* stacking_info */
178 2, /* stacking_info_nb */
179 get_stacking_info_arm926ejs
, /* fn_get_stacking_info */
180 is_thread_id_valid_arm926ejs
, /* fn_is_thread_id_valid */
184 #define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params)))
186 enum ThreadX_symbol_values
{
187 ThreadX_VAL_tx_thread_current_ptr
= 0,
188 ThreadX_VAL_tx_thread_created_ptr
= 1,
189 ThreadX_VAL_tx_thread_created_count
= 2,
192 static const char * const ThreadX_symbol_list
[] = {
193 "_tx_thread_current_ptr",
194 "_tx_thread_created_ptr",
195 "_tx_thread_created_count",
199 const struct rtos_type ThreadX_rtos
= {
202 .detect_rtos
= ThreadX_detect_rtos
,
203 .create
= ThreadX_create
,
204 .update_threads
= ThreadX_update_threads
,
205 .get_thread_reg_list
= ThreadX_get_thread_reg_list
,
206 .get_symbol_list_to_lookup
= ThreadX_get_symbol_list_to_lookup
,
209 static const struct rtos_register_stacking
*get_stacking_info(const struct rtos
*rtos
, int64_t stack_ptr
)
211 const struct ThreadX_params
*param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
213 if (param
->fn_get_stacking_info
!= NULL
)
214 return param
->fn_get_stacking_info(rtos
, stack_ptr
);
216 return param
->stacking_info
+ 0;
219 static int is_thread_id_valid(const struct rtos
*rtos
, int64_t thread_id
)
221 const struct ThreadX_params
*param
;
223 if (rtos
->rtos_specific_params
== NULL
)
224 return 0; /* invalid */
226 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
228 if (param
->fn_is_thread_id_valid
!= NULL
)
229 return param
->fn_is_thread_id_valid(rtos
, thread_id
);
231 return (thread_id
!= 0);
234 static const struct rtos_register_stacking
*get_stacking_info_arm926ejs(const struct rtos
*rtos
, int64_t stack_ptr
)
236 const struct ThreadX_params
*param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
240 retval
= target_read_buffer(rtos
->target
,
244 if (retval
!= ERROR_OK
) {
245 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64
, stack_ptr
);
250 LOG_DEBUG(" solicited stack");
251 return param
->stacking_info
+ 0;
253 LOG_DEBUG(" interrupt stack: %u", flag
);
254 return param
->stacking_info
+ 1;
258 static int is_thread_id_valid_arm926ejs(const struct rtos
*rtos
, int64_t thread_id
)
260 return (thread_id
!= 0 && thread_id
!= 1);
263 static int ThreadX_update_threads(struct rtos
*rtos
)
267 int thread_list_size
= 0;
268 const struct ThreadX_params
*param
;
273 if (rtos
->rtos_specific_params
== NULL
)
276 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
278 if (rtos
->symbols
== NULL
) {
279 LOG_ERROR("No symbols for ThreadX");
283 if (rtos
->symbols
[ThreadX_VAL_tx_thread_created_count
].address
== 0) {
284 LOG_ERROR("Don't have the number of threads in ThreadX");
288 /* read the number of threads */
289 retval
= target_read_buffer(rtos
->target
,
290 rtos
->symbols
[ThreadX_VAL_tx_thread_created_count
].address
,
292 (uint8_t *)&thread_list_size
);
294 if (retval
!= ERROR_OK
) {
295 LOG_ERROR("Could not read ThreadX thread count from target");
299 /* wipe out previous thread details if any */
300 rtos_free_threadlist(rtos
);
302 /* read the current thread id */
303 retval
= target_read_buffer(rtos
->target
,
304 rtos
->symbols
[ThreadX_VAL_tx_thread_current_ptr
].address
,
306 (uint8_t *)&rtos
->current_thread
);
308 if (retval
!= ERROR_OK
) {
309 LOG_ERROR("Could not read ThreadX current thread from target");
313 if ((thread_list_size
== 0) || (rtos
->current_thread
== 0)) {
314 /* Either : No RTOS threads - there is always at least the current execution though */
315 /* OR : No current thread - all threads suspended - show the current execution
317 char tmp_str
[] = "Current Execution";
320 rtos
->thread_details
= malloc(
321 sizeof(struct thread_detail
) * thread_list_size
);
322 rtos
->thread_details
->threadid
= 1;
323 rtos
->thread_details
->exists
= true;
324 rtos
->thread_details
->display_str
= NULL
;
325 rtos
->thread_details
->extra_info_str
= NULL
;
326 rtos
->thread_details
->thread_name_str
= malloc(sizeof(tmp_str
));
327 strcpy(rtos
->thread_details
->thread_name_str
, tmp_str
);
329 if (thread_list_size
== 0) {
330 rtos
->thread_count
= 1;
334 /* create space for new thread details */
335 rtos
->thread_details
= malloc(
336 sizeof(struct thread_detail
) * thread_list_size
);
339 /* Read the pointer to the first thread */
340 int64_t thread_ptr
= 0;
341 retval
= target_read_buffer(rtos
->target
,
342 rtos
->symbols
[ThreadX_VAL_tx_thread_created_ptr
].address
,
343 param
->pointer_width
,
344 (uint8_t *)&thread_ptr
);
345 if (retval
!= ERROR_OK
) {
346 LOG_ERROR("Could not read ThreadX thread location from target");
350 /* loop over all threads */
351 int64_t prev_thread_ptr
= 0;
352 while ((thread_ptr
!= prev_thread_ptr
) && (tasks_found
< thread_list_size
)) {
354 #define THREADX_THREAD_NAME_STR_SIZE (200)
355 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
357 int64_t name_ptr
= 0;
359 /* Save the thread pointer */
360 rtos
->thread_details
[tasks_found
].threadid
= thread_ptr
;
362 /* read the name pointer */
363 retval
= target_read_buffer(rtos
->target
,
364 thread_ptr
+ param
->thread_name_offset
,
365 param
->pointer_width
,
366 (uint8_t *)&name_ptr
);
367 if (retval
!= ERROR_OK
) {
368 LOG_ERROR("Could not read ThreadX thread name pointer from target");
372 /* Read the thread name */
374 target_read_buffer(rtos
->target
,
376 THREADX_THREAD_NAME_STR_SIZE
,
377 (uint8_t *)&tmp_str
);
378 if (retval
!= ERROR_OK
) {
379 LOG_ERROR("Error reading thread name from ThreadX target");
382 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
384 if (tmp_str
[0] == '\x00')
385 strcpy(tmp_str
, "No Name");
387 rtos
->thread_details
[tasks_found
].thread_name_str
=
388 malloc(strlen(tmp_str
)+1);
389 strcpy(rtos
->thread_details
[tasks_found
].thread_name_str
, tmp_str
);
391 /* Read the thread status */
392 int64_t thread_status
= 0;
393 retval
= target_read_buffer(rtos
->target
,
394 thread_ptr
+ param
->thread_state_offset
,
396 (uint8_t *)&thread_status
);
397 if (retval
!= ERROR_OK
) {
398 LOG_ERROR("Error reading thread state from ThreadX target");
402 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
403 (ThreadX_thread_states
[i
].value
!= thread_status
); i
++) {
407 const char *state_desc
;
408 if (i
< THREADX_NUM_STATES
)
409 state_desc
= ThreadX_thread_states
[i
].desc
;
411 state_desc
= "Unknown state";
413 rtos
->thread_details
[tasks_found
].extra_info_str
= malloc(strlen(
415 strcpy(rtos
->thread_details
[tasks_found
].extra_info_str
, state_desc
);
417 rtos
->thread_details
[tasks_found
].exists
= true;
419 rtos
->thread_details
[tasks_found
].display_str
= NULL
;
422 prev_thread_ptr
= thread_ptr
;
424 /* Get the location of the next thread structure. */
426 retval
= target_read_buffer(rtos
->target
,
427 prev_thread_ptr
+ param
->thread_next_offset
,
428 param
->pointer_width
,
429 (uint8_t *) &thread_ptr
);
430 if (retval
!= ERROR_OK
) {
431 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
436 rtos
->thread_count
= tasks_found
;
441 static int ThreadX_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
)
444 const struct ThreadX_params
*param
;
446 *hex_reg_list
= NULL
;
451 if (!is_thread_id_valid(rtos
, thread_id
))
454 if (rtos
->rtos_specific_params
== NULL
)
457 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
459 /* Read the stack pointer */
460 int64_t stack_ptr
= 0;
461 retval
= target_read_buffer(rtos
->target
,
462 thread_id
+ param
->thread_stack_offset
,
463 param
->pointer_width
,
464 (uint8_t *)&stack_ptr
);
465 if (retval
!= ERROR_OK
) {
466 LOG_ERROR("Error reading stack frame from ThreadX thread");
470 LOG_INFO("thread: 0x%" PRIx64
", stack_ptr=0x%" PRIx64
, (uint64_t)thread_id
, (uint64_t)stack_ptr
);
472 if (stack_ptr
== 0) {
473 LOG_ERROR("null stack pointer in thread");
477 const struct rtos_register_stacking
*stacking_info
=
478 get_stacking_info(rtos
, stack_ptr
);
480 if (stacking_info
== NULL
) {
481 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64
, (uint64_t)thread_id
);
485 return rtos_generic_stack_read(rtos
->target
, stacking_info
, stack_ptr
, hex_reg_list
);
488 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
491 *symbol_list
= calloc(
492 ARRAY_SIZE(ThreadX_symbol_list
), sizeof(symbol_table_elem_t
));
494 for (i
= 0; i
< ARRAY_SIZE(ThreadX_symbol_list
); i
++)
495 (*symbol_list
)[i
].symbol_name
= ThreadX_symbol_list
[i
];
500 static int ThreadX_detect_rtos(struct target
*target
)
502 if ((target
->rtos
->symbols
!= NULL
) &&
503 (target
->rtos
->symbols
[ThreadX_VAL_tx_thread_created_ptr
].address
!= 0)) {
504 /* looks like ThreadX */
512 static int ThreadX_set_current_thread(struct rtos
*rtos
, threadid_t thread_id
)
517 static int ThreadX_get_thread_detail(struct rtos
*rtos
,
518 threadid_t thread_id
,
519 struct thread_detail
*detail
)
524 #define THREADX_THREAD_NAME_STR_SIZE (200)
525 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
527 const struct ThreadX_params
*param
;
535 if (rtos
->rtos_specific_params
== NULL
)
538 param
= (const struct ThreadX_params
*) rtos
->rtos_specific_params
;
540 if (rtos
->symbols
== NULL
) {
541 LOG_ERROR("No symbols for ThreadX");
545 detail
->threadid
= thread_id
;
547 int64_t name_ptr
= 0;
548 /* read the name pointer */
549 retval
= target_read_buffer(rtos
->target
,
550 thread_id
+ param
->thread_name_offset
,
551 param
->pointer_width
,
552 (uint8_t *)&name_ptr
);
553 if (retval
!= ERROR_OK
) {
554 LOG_ERROR("Could not read ThreadX thread name pointer from target");
558 /* Read the thread name */
559 retval
= target_read_buffer(rtos
->target
,
561 THREADX_THREAD_NAME_STR_SIZE
,
562 (uint8_t *)&tmp_str
);
563 if (retval
!= ERROR_OK
) {
564 LOG_ERROR("Error reading thread name from ThreadX target");
567 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
569 if (tmp_str
[0] == '\x00')
570 strcpy(tmp_str
, "No Name");
572 detail
->thread_name_str
= malloc(strlen(tmp_str
)+1);
574 /* Read the thread status */
575 int64_t thread_status
= 0;
577 target_read_buffer(rtos
->target
,
578 thread_id
+ param
->thread_state_offset
,
580 (uint8_t *)&thread_status
);
581 if (retval
!= ERROR_OK
) {
582 LOG_ERROR("Error reading thread state from ThreadX target");
586 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
587 (ThreadX_thread_states
[i
].value
!= thread_status
); i
++) {
592 if (i
< THREADX_NUM_STATES
)
593 state_desc
= ThreadX_thread_states
[i
].desc
;
595 state_desc
= "Unknown state";
597 detail
->extra_info_str
= malloc(strlen(state_desc
)+1);
599 detail
->exists
= true;
601 detail
->display_str
= NULL
;
608 static int ThreadX_create(struct target
*target
)
611 while ((i
< THREADX_NUM_PARAMS
) &&
612 (0 != strcmp(ThreadX_params_list
[i
].target_name
, target
->type
->name
))) {
615 if (i
>= THREADX_NUM_PARAMS
) {
616 LOG_ERROR("Could not find target in ThreadX compatibility list");
620 target
->rtos
->rtos_specific_params
= (void *) &ThreadX_params_list
[i
];
621 target
->rtos
->current_thread
= 0;
622 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)