rtos: Use ARRAY_SIZE instead of coding it by hand
[openocd.git] / src / rtos / ThreadX.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.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, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
29 #include "rtos.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "rtos_standard_stackings.h"
33
34 static int ThreadX_detect_rtos(struct target *target);
35 static int ThreadX_create(struct target *target);
36 static int ThreadX_update_threads(struct rtos *rtos);
37 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
38 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
39
40 struct ThreadX_thread_state {
41 int value;
42 char *desc;
43 };
44
45 struct ThreadX_thread_state ThreadX_thread_states[] = {
46 { 0, "Ready" },
47 { 1, "Completed" },
48 { 2, "Terminated" },
49 { 3, "Suspended" },
50 { 4, "Sleeping" },
51 { 5, "Waiting - Queue" },
52 { 6, "Waiting - Semaphore" },
53 { 7, "Waiting - Event flag" },
54 { 8, "Waiting - Memory" },
55 { 9, "Waiting - Memory" },
56 { 10, "Waiting - I/O" },
57 { 11, "Waiting - Filesystem" },
58 { 12, "Waiting - Network" },
59 { 13, "Waiting - Mutex" },
60 };
61
62 #define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state))
63
64 struct ThreadX_params {
65 char *target_name;
66 unsigned char pointer_width;
67 unsigned char thread_stack_offset;
68 unsigned char thread_name_offset;
69 unsigned char thread_state_offset;
70 unsigned char thread_next_offset;
71 const struct rtos_register_stacking *stacking_info;
72 };
73
74 const struct ThreadX_params ThreadX_params_list[] = {
75 {
76 "cortex_m3", /* target_name */
77 4, /* pointer_width; */
78 8, /* thread_stack_offset; */
79 40, /* thread_name_offset; */
80 48, /* thread_state_offset; */
81 136, /* thread_next_offset */
82 &rtos_standard_Cortex_M3_stacking, /* stacking_info */
83 }
84 };
85
86 #define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params)))
87
88 enum ThreadX_symbol_values {
89 ThreadX_VAL_tx_thread_current_ptr = 0,
90 ThreadX_VAL_tx_thread_created_ptr = 1,
91 ThreadX_VAL_tx_thread_created_count = 2,
92 };
93
94 static char *ThreadX_symbol_list[] = {
95 "_tx_thread_current_ptr",
96 "_tx_thread_created_ptr",
97 "_tx_thread_created_count",
98 NULL
99 };
100
101 const struct rtos_type ThreadX_rtos = {
102 .name = "ThreadX",
103
104 .detect_rtos = ThreadX_detect_rtos,
105 .create = ThreadX_create,
106 .update_threads = ThreadX_update_threads,
107 .get_thread_reg_list = ThreadX_get_thread_reg_list,
108 .get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup,
109
110 };
111
112 static int ThreadX_update_threads(struct rtos *rtos)
113 {
114 int retval;
115 int tasks_found = 0;
116 int thread_list_size = 0;
117 const struct ThreadX_params *param;
118
119 if (rtos == NULL)
120 return -1;
121
122 if (rtos->rtos_specific_params == NULL)
123 return -3;
124
125 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
126
127 if (rtos->symbols == NULL) {
128 LOG_OUTPUT("No symbols for ThreadX\r\n");
129 return -4;
130 }
131
132 if (rtos->symbols[ThreadX_VAL_tx_thread_created_count].address == 0) {
133 LOG_OUTPUT("Don't have the number of threads in ThreadX \r\n");
134 return -2;
135 }
136
137 /* read the number of threads */
138 retval = target_read_buffer(rtos->target,
139 rtos->symbols[ThreadX_VAL_tx_thread_created_count].address,
140 4,
141 (uint8_t *)&thread_list_size);
142
143 if (retval != ERROR_OK) {
144 LOG_OUTPUT("Could not read ThreadX thread count from target\r\n");
145 return retval;
146 }
147
148 /* wipe out previous thread details if any */
149 if (rtos->thread_details != NULL) {
150 int j;
151 for (j = 0; j < rtos->thread_count; j++) {
152 if (rtos->thread_details[j].display_str != NULL) {
153 free(rtos->thread_details[j].display_str);
154 rtos->thread_details[j].display_str = NULL;
155 }
156 if (rtos->thread_details[j].thread_name_str != NULL) {
157 free(rtos->thread_details[j].thread_name_str);
158 rtos->thread_details[j].thread_name_str = NULL;
159 }
160 if (rtos->thread_details[j].extra_info_str != NULL) {
161 free(rtos->thread_details[j].extra_info_str);
162 rtos->thread_details[j].extra_info_str = NULL;
163 }
164 }
165 free(rtos->thread_details);
166 rtos->thread_details = NULL;
167 }
168
169 /* read the current thread id */
170 retval = target_read_buffer(rtos->target,
171 rtos->symbols[ThreadX_VAL_tx_thread_current_ptr].address,
172 4,
173 (uint8_t *)&rtos->current_thread);
174
175 if (retval != ERROR_OK) {
176 LOG_OUTPUT("Could not read ThreadX current thread from target\r\n");
177 return retval;
178 }
179
180 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
181 /* Either : No RTOS threads - there is always at least the current execution though */
182 /* OR : No current thread - all threads suspended - show the current execution
183 * of idling */
184 char tmp_str[] = "Current Execution";
185 thread_list_size++;
186 tasks_found++;
187 rtos->thread_details = (struct thread_detail *) malloc(
188 sizeof(struct thread_detail) * thread_list_size);
189 rtos->thread_details->threadid = 1;
190 rtos->thread_details->exists = true;
191 rtos->thread_details->display_str = NULL;
192 rtos->thread_details->extra_info_str = NULL;
193 rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str));
194 strcpy(rtos->thread_details->thread_name_str, tmp_str);
195
196 if (thread_list_size == 0) {
197 rtos->thread_count = 1;
198 return ERROR_OK;
199 }
200 } else {
201 /* create space for new thread details */
202 rtos->thread_details = (struct thread_detail *) malloc(
203 sizeof(struct thread_detail) * thread_list_size);
204 }
205
206 /* Read the pointer to the first thread */
207 int64_t thread_ptr = 0;
208 retval = target_read_buffer(rtos->target,
209 rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address,
210 param->pointer_width,
211 (uint8_t *)&thread_ptr);
212 if (retval != ERROR_OK) {
213 LOG_OUTPUT("Could not read ThreadX thread location from target\r\n");
214 return retval;
215 }
216
217 /* loop over all threads */
218 int64_t prev_thread_ptr = 0;
219 while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
220
221 #define THREADX_THREAD_NAME_STR_SIZE (200)
222 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
223 unsigned int i = 0;
224 int64_t name_ptr = 0;
225
226 /* Save the thread pointer */
227 rtos->thread_details[tasks_found].threadid = thread_ptr;
228
229 /* read the name pointer */
230 retval = target_read_buffer(rtos->target,
231 thread_ptr + param->thread_name_offset,
232 param->pointer_width,
233 (uint8_t *)&name_ptr);
234 if (retval != ERROR_OK) {
235 LOG_OUTPUT("Could not read ThreadX thread name pointer from target\r\n");
236 return retval;
237 }
238
239 /* Read the thread name */
240 retval =
241 target_read_buffer(rtos->target,
242 name_ptr,
243 THREADX_THREAD_NAME_STR_SIZE,
244 (uint8_t *)&tmp_str);
245 if (retval != ERROR_OK) {
246 LOG_OUTPUT("Error reading thread name from ThreadX target\r\n");
247 return retval;
248 }
249 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
250
251 if (tmp_str[0] == '\x00')
252 strcpy(tmp_str, "No Name");
253
254 rtos->thread_details[tasks_found].thread_name_str =
255 (char *)malloc(strlen(tmp_str)+1);
256 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
257
258 /* Read the thread status */
259 int64_t thread_status = 0;
260 retval = target_read_buffer(rtos->target,
261 thread_ptr + param->thread_state_offset,
262 4,
263 (uint8_t *)&thread_status);
264 if (retval != ERROR_OK) {
265 LOG_OUTPUT("Error reading thread state from ThreadX target\r\n");
266 return retval;
267 }
268
269 for (i = 0; (i < THREADX_NUM_STATES) &&
270 (ThreadX_thread_states[i].value != thread_status); i++) {
271 /* empty */
272 }
273
274 char *state_desc;
275 if (i < THREADX_NUM_STATES)
276 state_desc = ThreadX_thread_states[i].desc;
277 else
278 state_desc = "Unknown state";
279
280 rtos->thread_details[tasks_found].extra_info_str = (char *)malloc(strlen(
281 state_desc)+1);
282 strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc);
283
284 rtos->thread_details[tasks_found].exists = true;
285
286 rtos->thread_details[tasks_found].display_str = NULL;
287
288 tasks_found++;
289 prev_thread_ptr = thread_ptr;
290
291 /* Get the location of the next thread structure. */
292 thread_ptr = 0;
293 retval = target_read_buffer(rtos->target,
294 prev_thread_ptr + param->thread_next_offset,
295 param->pointer_width,
296 (uint8_t *) &thread_ptr);
297 if (retval != ERROR_OK) {
298 LOG_OUTPUT("Error reading next thread pointer in ThreadX thread list\r\n");
299 return retval;
300 }
301 }
302
303 rtos->thread_count = tasks_found;
304
305 return 0;
306 }
307
308 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
309 {
310 int retval;
311 const struct ThreadX_params *param;
312
313 *hex_reg_list = NULL;
314
315 if (rtos == NULL)
316 return -1;
317
318 if (thread_id == 0)
319 return -2;
320
321 if (rtos->rtos_specific_params == NULL)
322 return -3;
323
324 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
325
326 /* Read the stack pointer */
327 int64_t stack_ptr = 0;
328 retval = target_read_buffer(rtos->target,
329 thread_id + param->thread_stack_offset,
330 param->pointer_width,
331 (uint8_t *)&stack_ptr);
332 if (retval != ERROR_OK) {
333 LOG_OUTPUT("Error reading stack frame from ThreadX thread\r\n");
334 return retval;
335 }
336
337 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
338 }
339
340 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
341 {
342 unsigned int i;
343 *symbol_list = (symbol_table_elem_t *) malloc(
344 sizeof(symbol_table_elem_t) * ARRAY_SIZE(ThreadX_symbol_list));
345
346 for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++)
347 (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i];
348
349 return 0;
350 }
351
352 static int ThreadX_detect_rtos(struct target *target)
353 {
354 if ((target->rtos->symbols != NULL) &&
355 (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) {
356 /* looks like ThreadX */
357 return 1;
358 }
359 return 0;
360 }
361
362 #if 0
363
364 static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id)
365 {
366 return 0;
367 }
368
369 static int ThreadX_get_thread_detail(struct rtos *rtos,
370 threadid_t thread_id,
371 struct thread_detail *detail)
372 {
373 unsigned int i = 0;
374 int retval;
375
376 #define THREADX_THREAD_NAME_STR_SIZE (200)
377 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
378
379 const struct ThreadX_params *param;
380
381 if (rtos == NULL)
382 return -1;
383
384 if (thread_id == 0)
385 return -2;
386
387 if (rtos->rtos_specific_params == NULL)
388 return -3;
389
390 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
391
392 if (rtos->symbols == NULL) {
393 LOG_OUTPUT("No symbols for ThreadX\r\n");
394 return -3;
395 }
396
397 detail->threadid = thread_id;
398
399 int64_t name_ptr = 0;
400 /* read the name pointer */
401 retval = target_read_buffer(rtos->target,
402 thread_id + param->thread_name_offset,
403 param->pointer_width,
404 (uint8_t *)&name_ptr);
405 if (retval != ERROR_OK) {
406 LOG_OUTPUT("Could not read ThreadX thread name pointer from target\r\n");
407 return retval;
408 }
409
410 /* Read the thread name */
411 retval = target_read_buffer(rtos->target,
412 name_ptr,
413 THREADX_THREAD_NAME_STR_SIZE,
414 (uint8_t *)&tmp_str);
415 if (retval != ERROR_OK) {
416 LOG_OUTPUT("Error reading thread name from ThreadX target\r\n");
417 return retval;
418 }
419 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
420
421 if (tmp_str[0] == '\x00')
422 strcpy(tmp_str, "No Name");
423
424 detail->thread_name_str = (char *)malloc(strlen(tmp_str)+1);
425
426 /* Read the thread status */
427 int64_t thread_status = 0;
428 retval =
429 target_read_buffer(rtos->target,
430 thread_id + param->thread_state_offset,
431 4,
432 (uint8_t *)&thread_status);
433 if (retval != ERROR_OK) {
434 LOG_OUTPUT("Error reading thread state from ThreadX target\r\n");
435 return retval;
436 }
437
438 for (i = 0; (i < THREADX_NUM_STATES) &&
439 (ThreadX_thread_states[i].value != thread_status); i++) {
440 /* empty */
441 }
442
443 char *state_desc;
444 if (i < THREADX_NUM_STATES)
445 state_desc = ThreadX_thread_states[i].desc;
446 else
447 state_desc = "Unknown state";
448
449 detail->extra_info_str = (char *)malloc(strlen(state_desc)+1);
450
451 detail->exists = true;
452
453 detail->display_str = NULL;
454
455 return 0;
456 }
457
458 #endif
459
460 static int ThreadX_create(struct target *target)
461 {
462 int i = 0;
463 while ((i < THREADX_NUM_PARAMS) &&
464 (0 != strcmp(ThreadX_params_list[i].target_name, target->type->name))) {
465 i++;
466 }
467 if (i >= THREADX_NUM_PARAMS) {
468 LOG_OUTPUT("Could not find target in ThreadX compatibility list\r\n");
469 return -1;
470 }
471
472 target->rtos->rtos_specific_params = (void *) &ThreadX_params_list[i];
473 target->rtos->current_thread = 0;
474 target->rtos->thread_details = NULL;
475 return 0;
476 }

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)