rtos: fix segfault in FreeRTOS handling
[openocd.git] / src / rtos / FreeRTOS.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 "rtos_standard_stackings.h"
32
33 #define FreeRTOS_STRUCT(int_type, ptr_type, list_prev_offset)
34
35 struct FreeRTOS_params {
36 const char *target_name;
37 const unsigned char thread_count_width;
38 const unsigned char pointer_width;
39 const unsigned char list_next_offset;
40 const unsigned char list_width;
41 const unsigned char list_elem_next_offset;
42 const unsigned char list_elem_content_offset;
43 const unsigned char thread_stack_offset;
44 const unsigned char thread_name_offset;
45 const struct rtos_register_stacking *stacking_info;
46 };
47
48 const struct FreeRTOS_params FreeRTOS_params_list[] = {
49 {
50 "cortex_m3", /* target_name */
51 4, /* thread_count_width; */
52 4, /* pointer_width; */
53 16, /* list_next_offset; */
54 20, /* list_width; */
55 8, /* list_elem_next_offset; */
56 12, /* list_elem_content_offset */
57 0, /* thread_stack_offset; */
58 52, /* thread_name_offset; */
59 &rtos_standard_Cortex_M3_stacking, /* stacking_info */
60 }
61 };
62
63 #define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params)))
64
65 static int FreeRTOS_detect_rtos(struct target *target);
66 static int FreeRTOS_create(struct target *target);
67 static int FreeRTOS_update_threads(struct rtos *rtos);
68 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
69 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
70
71 struct rtos_type FreeRTOS_rtos = {
72 .name = "FreeRTOS",
73
74 .detect_rtos = FreeRTOS_detect_rtos,
75 .create = FreeRTOS_create,
76 .update_threads = FreeRTOS_update_threads,
77 .get_thread_reg_list = FreeRTOS_get_thread_reg_list,
78 .get_symbol_list_to_lookup = FreeRTOS_get_symbol_list_to_lookup,
79 };
80
81 enum FreeRTOS_symbol_values {
82 FreeRTOS_VAL_pxCurrentTCB = 0,
83 FreeRTOS_VAL_pxReadyTasksLists = 1,
84 FreeRTOS_VAL_xDelayedTaskList1 = 2,
85 FreeRTOS_VAL_xDelayedTaskList2 = 3,
86 FreeRTOS_VAL_pxDelayedTaskList = 4,
87 FreeRTOS_VAL_pxOverflowDelayedTaskList = 5,
88 FreeRTOS_VAL_xPendingReadyList = 6,
89 FreeRTOS_VAL_xTasksWaitingTermination = 7,
90 FreeRTOS_VAL_xSuspendedTaskList = 8,
91 FreeRTOS_VAL_uxCurrentNumberOfTasks = 9,
92 FreeRTOS_VAL_uxTopUsedPriority = 10,
93 };
94
95 static char *FreeRTOS_symbol_list[] = {
96 "pxCurrentTCB",
97 "pxReadyTasksLists",
98 "xDelayedTaskList1",
99 "xDelayedTaskList2",
100 "pxDelayedTaskList",
101 "pxOverflowDelayedTaskList",
102 "xPendingReadyList",
103 "xTasksWaitingTermination",
104 "xSuspendedTaskList",
105 "uxCurrentNumberOfTasks",
106 "uxTopUsedPriority",
107 NULL
108 };
109
110 #define FREERTOS_NUM_SYMBOLS (sizeof(FreeRTOS_symbol_list)/sizeof(char *))
111
112 /* TODO: */
113 /* this is not safe for little endian yet */
114 /* may be problems reading if sizes are not 32 bit long integers. */
115 /* test mallocs for failure */
116
117 static int FreeRTOS_update_threads(struct rtos *rtos)
118 {
119 int i = 0;
120 int retval;
121 int tasks_found = 0;
122 const struct FreeRTOS_params *param;
123
124 if (rtos->rtos_specific_params == NULL)
125 return -1;
126
127 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
128
129 if (rtos->symbols == NULL) {
130 LOG_OUTPUT("No symbols for FreeRTOS\r\n");
131 return -3;
132 }
133
134 if (rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address == 0) {
135 LOG_OUTPUT("Don't have the number of threads in FreeRTOS \r\n");
136 return -2;
137 }
138
139 int thread_list_size = 0;
140 retval = target_read_buffer(rtos->target,
141 rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
142 param->thread_count_width,
143 (uint8_t *)&thread_list_size);
144
145 if (retval != ERROR_OK) {
146 LOG_OUTPUT("Could not read FreeRTOS thread count from target\r\n");
147 return retval;
148 }
149
150 /* wipe out previous thread details if any */
151 if (rtos->thread_details != NULL) {
152 int j;
153 for (j = 0; j < rtos->thread_count; j++) {
154 if (rtos->thread_details[j].display_str != NULL) {
155 free(rtos->thread_details[j].display_str);
156 rtos->thread_details[j].display_str = NULL;
157 }
158 if (rtos->thread_details[j].thread_name_str != NULL) {
159 free(rtos->thread_details[j].thread_name_str);
160 rtos->thread_details[j].thread_name_str = NULL;
161 }
162 if (rtos->thread_details[j].extra_info_str != NULL) {
163 free(rtos->thread_details[j].extra_info_str);
164 rtos->thread_details[j].extra_info_str = NULL;
165 }
166 }
167 free(rtos->thread_details);
168 rtos->thread_details = NULL;
169 }
170
171 /* read the current thread */
172 retval = target_read_buffer(rtos->target,
173 rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
174 param->pointer_width,
175 (uint8_t *)&rtos->current_thread);
176 if (retval != ERROR_OK) {
177 LOG_OUTPUT("Error reading current thread in FreeRTOS thread list\r\n");
178 return retval;
179 }
180
181 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
182 /* Either : No RTOS threads - there is always at least the current execution though */
183 /* OR : No current thread - all threads suspended - show the current execution
184 * of idling */
185 char tmp_str[] = "Current Execution";
186 thread_list_size++;
187 tasks_found++;
188 rtos->thread_details = (struct thread_detail *) malloc(
189 sizeof(struct thread_detail) * thread_list_size);
190 if (!rtos->thread_details) {
191 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
192 return ERROR_FAIL;
193 }
194 rtos->thread_details->threadid = 1;
195 rtos->thread_details->exists = true;
196 rtos->thread_details->display_str = NULL;
197 rtos->thread_details->extra_info_str = NULL;
198 rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str));
199 strcpy(rtos->thread_details->thread_name_str, tmp_str);
200
201 if (thread_list_size == 1) {
202 rtos->thread_count = 1;
203 return ERROR_OK;
204 }
205 } else {
206 /* create space for new thread details */
207 rtos->thread_details = (struct thread_detail *) malloc(
208 sizeof(struct thread_detail) * thread_list_size);
209 if (!rtos->thread_details) {
210 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
211 return ERROR_FAIL;
212 }
213 }
214
215 /* Find out how many lists are needed to be read from pxReadyTasksLists, */
216 int64_t max_used_priority = 0;
217 retval = target_read_buffer(rtos->target,
218 rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
219 param->pointer_width,
220 (uint8_t *)&max_used_priority);
221 if (retval != ERROR_OK)
222 return retval;
223
224 symbol_address_t *list_of_lists =
225 (symbol_address_t *)malloc(sizeof(symbol_address_t) *
226 (max_used_priority+1 + 5));
227 if (!list_of_lists) {
228 LOG_ERROR("Error allocating memory for %" PRId64 " priorities", max_used_priority);
229 return ERROR_FAIL;
230 }
231
232 int num_lists;
233 for (num_lists = 0; num_lists <= max_used_priority; num_lists++)
234 list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address +
235 num_lists * param->list_width;
236
237 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address;
238 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address;
239 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xPendingReadyList].address;
240 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address;
241 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address;
242
243 for (i = 0; i < num_lists; i++) {
244 if (list_of_lists[i] == 0)
245 continue;
246
247 /* Read the number of threads in this list */
248 int64_t list_thread_count = 0;
249 retval = target_read_buffer(rtos->target,
250 list_of_lists[i],
251 param->thread_count_width,
252 (uint8_t *)&list_thread_count);
253 if (retval != ERROR_OK) {
254 LOG_OUTPUT("Error reading number of threads in FreeRTOS thread list\r\n");
255 return retval;
256 }
257
258 if (list_thread_count == 0)
259 continue;
260
261 /* Read the location of first list item */
262 uint64_t prev_list_elem_ptr = -1;
263 uint64_t list_elem_ptr = 0;
264 retval = target_read_buffer(rtos->target,
265 list_of_lists[i] + param->list_next_offset,
266 param->pointer_width,
267 (uint8_t *)&list_elem_ptr);
268 if (retval != ERROR_OK) {
269 LOG_OUTPUT(
270 "Error reading first thread item location in FreeRTOS thread list\r\n");
271 return retval;
272 }
273
274 while ((list_thread_count > 0) && (list_elem_ptr != 0) &&
275 (list_elem_ptr != prev_list_elem_ptr) &&
276 (tasks_found < thread_list_size)) {
277 /* Get the location of the thread structure. */
278 rtos->thread_details[tasks_found].threadid = 0;
279 retval = target_read_buffer(rtos->target,
280 list_elem_ptr + param->list_elem_content_offset,
281 param->pointer_width,
282 (uint8_t *)&(rtos->thread_details[tasks_found].threadid));
283 if (retval != ERROR_OK) {
284 LOG_OUTPUT(
285 "Error reading thread list item object in FreeRTOS thread list\r\n");
286 return retval;
287 }
288
289 /* get thread name */
290
291 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
292 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
293
294 /* Read the thread name */
295 retval = target_read_buffer(rtos->target,
296 rtos->thread_details[tasks_found].threadid + param->thread_name_offset,
297 FREERTOS_THREAD_NAME_STR_SIZE,
298 (uint8_t *)&tmp_str);
299 if (retval != ERROR_OK) {
300 LOG_OUTPUT(
301 "Error reading first thread item location in FreeRTOS thread list\r\n");
302 return retval;
303 }
304 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
305
306 if (tmp_str[0] == '\x00')
307 strcpy(tmp_str, "No Name");
308
309 rtos->thread_details[tasks_found].thread_name_str =
310 (char *)malloc(strlen(tmp_str)+1);
311 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
312 rtos->thread_details[tasks_found].display_str = NULL;
313 rtos->thread_details[tasks_found].exists = true;
314
315 if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) {
316 char running_str[] = "Running";
317 rtos->thread_details[tasks_found].extra_info_str = (char *) malloc(
318 sizeof(running_str));
319 strcpy(rtos->thread_details[tasks_found].extra_info_str,
320 running_str);
321 } else
322 rtos->thread_details[tasks_found].extra_info_str = NULL;
323
324 tasks_found++;
325 list_thread_count--;
326
327 prev_list_elem_ptr = list_elem_ptr;
328 list_elem_ptr = 0;
329 retval = target_read_buffer(rtos->target,
330 prev_list_elem_ptr + param->list_elem_next_offset,
331 param->pointer_width,
332 (uint8_t *)&list_elem_ptr);
333 if (retval != ERROR_OK) {
334 LOG_OUTPUT(
335 "Error reading next thread item location in FreeRTOS thread list\r\n");
336 return retval;
337 }
338 }
339 }
340 free(list_of_lists);
341 rtos->thread_count = tasks_found;
342 return 0;
343 }
344
345 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
346 {
347 int retval;
348 const struct FreeRTOS_params *param;
349 int64_t stack_ptr = 0;
350
351 *hex_reg_list = NULL;
352 if (rtos == NULL)
353 return -1;
354
355 if (thread_id == 0)
356 return -2;
357
358 if (rtos->rtos_specific_params == NULL)
359 return -1;
360
361 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
362
363 /* Read the stack pointer */
364 retval = target_read_buffer(rtos->target,
365 thread_id + param->thread_stack_offset,
366 param->pointer_width,
367 (uint8_t *)&stack_ptr);
368 if (retval != ERROR_OK) {
369 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
370 return retval;
371 }
372
373 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
374
375 }
376
377 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
378 {
379 unsigned int i;
380 *symbol_list = (symbol_table_elem_t *) malloc(
381 sizeof(symbol_table_elem_t) * FREERTOS_NUM_SYMBOLS);
382
383 for (i = 0; i < FREERTOS_NUM_SYMBOLS; i++)
384 (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i];
385
386 return 0;
387 }
388
389 #if 0
390
391 static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id)
392 {
393 return 0;
394 }
395
396 static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info)
397 {
398 int retval;
399 const struct FreeRTOS_params *param;
400
401 if (rtos == NULL)
402 return -1;
403
404 if (thread_id == 0)
405 return -2;
406
407 if (rtos->rtos_specific_params == NULL)
408 return -3;
409
410 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
411
412 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
413 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
414
415 /* Read the thread name */
416 retval = target_read_buffer(rtos->target,
417 thread_id + param->thread_name_offset,
418 FREERTOS_THREAD_NAME_STR_SIZE,
419 (uint8_t *)&tmp_str);
420 if (retval != ERROR_OK) {
421 LOG_OUTPUT("Error reading first thread item location in FreeRTOS thread list\r\n");
422 return retval;
423 }
424 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
425
426 if (tmp_str[0] == '\x00')
427 strcpy(tmp_str, "No Name");
428
429 *info = (char *)malloc(strlen(tmp_str)+1);
430 strcpy(*info, tmp_str);
431 return 0;
432 }
433
434 #endif
435
436 static int FreeRTOS_detect_rtos(struct target *target)
437 {
438 if ((target->rtos->symbols != NULL) &&
439 (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) {
440 /* looks like FreeRTOS */
441 return 1;
442 }
443 return 0;
444 }
445
446 static int FreeRTOS_create(struct target *target)
447 {
448 int i = 0;
449 while ((i < FREERTOS_NUM_PARAMS) &&
450 (0 != strcmp(FreeRTOS_params_list[i].target_name, target->type->name))) {
451 i++;
452 }
453 if (i >= FREERTOS_NUM_PARAMS) {
454 LOG_OUTPUT("Could not find target in FreeRTOS compatibility list\r\n");
455 return -1;
456 }
457
458 target->rtos->rtos_specific_params = (void *) &FreeRTOS_params_list[i];
459 return 0;
460 }

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)