build: fix memory leaks
[openocd.git] / src / rtos / rtos.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 "rtos.h"
26 #include "target/target.h"
27 #include "helper/log.h"
28 #include "server/gdb_server.h"
29
30 static void hex_to_str(char *dst, char *hex_src);
31
32 /* RTOSs */
33 extern struct rtos_type FreeRTOS_rtos;
34 extern struct rtos_type ThreadX_rtos;
35 extern struct rtos_type eCos_rtos;
36 extern struct rtos_type Linux_os;
37
38 static struct rtos_type *rtos_types[] = {
39 &ThreadX_rtos,
40 &FreeRTOS_rtos,
41 &eCos_rtos,
42 &Linux_os,
43 NULL
44 };
45
46 int rtos_thread_packet(struct connection *connection, char *packet, int packet_size);
47
48 int rtos_smp_init(struct target *target)
49 {
50 if (target->rtos->type->smp_init)
51 return target->rtos->type->smp_init(target);
52 return ERROR_TARGET_INIT_FAILED;
53 }
54
55 int rtos_create(Jim_GetOptInfo *goi, struct target *target)
56 {
57 int x;
58 char *cp;
59 if (!goi->isconfigure) {
60 if (goi->argc != 0) {
61 if (goi->argc != 0) {
62 Jim_WrongNumArgs(goi->interp,
63 goi->argc, goi->argv,
64 "NO PARAMS");
65 return JIM_ERR;
66 }
67
68 Jim_SetResultString(goi->interp,
69 target_type_name(target), -1);
70 }
71 }
72
73 if (target->rtos)
74 free((void *)(target->rtos));
75 /* e = Jim_GetOpt_String(goi,
76 * &cp, NULL); */
77 /* target->rtos = strdup(cp); */
78
79 Jim_GetOpt_String(goi, &cp, NULL);
80 /* now does target type exist */
81
82 if (0 == strcmp(cp, "auto")) {
83 /* auto detection of RTOS */
84 target->rtos_auto_detect = true;
85 x = 0;
86 } else {
87
88 for (x = 0; rtos_types[x]; x++) {
89 if (0 == strcmp(cp, rtos_types[x]->name)) {
90 /* found */
91 break;
92 }
93 }
94 if (rtos_types[x] == NULL) {
95 Jim_SetResultFormatted(goi->interp, "Unknown rtos type %s, try one of ",
96 cp);
97 for (x = 0; rtos_types[x]; x++) {
98 if (rtos_types[x + 1]) {
99 Jim_AppendStrings(goi->interp,
100 Jim_GetResult(goi->interp),
101 rtos_types[x]->name,
102 ", ", NULL);
103 } else {
104 Jim_AppendStrings(goi->interp,
105 Jim_GetResult(goi->interp),
106 " or ",
107 rtos_types[x]->name, NULL);
108 }
109 }
110 return JIM_ERR;
111 }
112 }
113 /* Create it */
114 target->rtos = calloc(1, sizeof(struct rtos));
115 target->rtos->type = rtos_types[x];
116 target->rtos->current_threadid = -1;
117 target->rtos->current_thread = 0;
118 target->rtos->symbols = NULL;
119 target->rtos->target = target;
120 /* put default thread handler in linux usecase it is overloaded*/
121 target->rtos->gdb_thread_packet = rtos_thread_packet;
122
123 if (0 != strcmp(cp, "auto"))
124 target->rtos->type->create(target);
125
126 return JIM_OK;
127 }
128
129 int gdb_thread_packet(struct connection *connection, char *packet, int packet_size)
130 {
131 struct target *target = get_target_from_connection(connection);
132 if (target->rtos == NULL)
133 return rtos_thread_packet(connection, packet, packet_size); /* thread not
134 *found*/
135 return target->rtos->gdb_thread_packet(connection, packet, packet_size);
136 }
137 /* return -1 if no rtos defined, 0 if rtos and symbol to be asked, 1 if all
138 * symbol have been asked*/
139 int rtos_qsymbol(struct connection *connection, char *packet, int packet_size)
140 {
141 struct target *target = get_target_from_connection(connection);
142 if (target->rtos != NULL) {
143 int next_symbol_num = -1;
144 if (target->rtos->symbols == NULL)
145 target->rtos->type->get_symbol_list_to_lookup(&target->rtos->symbols);
146 if (0 == strcmp("qSymbol::", packet))
147 /* first query - */
148 next_symbol_num = 0;
149 else {
150 int64_t value = 0;
151 char *hex_name_str = malloc(strlen(packet));
152 char *name_str;
153 int symbol_num;
154
155 char *found = strstr(packet, "qSymbol::");
156 if (0 == found)
157 sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str);
158 else
159 /* No value returned by GDB - symbol was not found*/
160 sscanf(packet, "qSymbol::%s", hex_name_str);
161 name_str = (char *) malloc(1 + strlen(hex_name_str) / 2);
162
163 hex_to_str(name_str, hex_name_str);
164 symbol_num = 0;
165 while ((target->rtos->symbols[symbol_num].symbol_name != NULL) &&
166 (0 != strcmp(target->rtos->symbols[symbol_num].symbol_name, name_str)))
167 symbol_num++;
168
169 if (target->rtos->symbols[symbol_num].symbol_name == NULL) {
170 LOG_OUTPUT("ERROR: unknown symbol\r\n");
171 gdb_put_packet(connection, "OK", 2);
172 free(hex_name_str);
173 free(name_str);
174 return ERROR_OK;
175 }
176
177 target->rtos->symbols[symbol_num].address = value;
178
179 next_symbol_num = symbol_num+1;
180 free(hex_name_str);
181 free(name_str);
182 }
183
184 int symbols_done = 0;
185 if (target->rtos->symbols[next_symbol_num].symbol_name == NULL) {
186 if ((target->rtos_auto_detect == false) ||
187 (1 == target->rtos->type->detect_rtos(target))) {
188 /* Found correct RTOS or not autodetecting */
189 if (target->rtos_auto_detect == true)
190 LOG_OUTPUT("Auto-detected RTOS: %s\r\n",
191 target->rtos->type->name);
192 symbols_done = 1;
193 } else {
194 /* Auto detecting RTOS and currently not found */
195 if (1 != rtos_try_next(target))
196 /* No more RTOS's to try */
197 symbols_done = 1;
198 else {
199 next_symbol_num = 0;
200 target->rtos->type->get_symbol_list_to_lookup(
201 &target->rtos->symbols);
202 }
203 }
204 }
205 if (symbols_done == 1)
206 return symbols_done;
207 else {
208 char *symname = target->rtos->symbols[next_symbol_num].symbol_name;
209 char qsymstr[] = "qSymbol:";
210 char *opstring = (char *)malloc(sizeof(qsymstr)+strlen(symname)*2+1);
211 char *posptr = opstring;
212 posptr += sprintf(posptr, "%s", qsymstr);
213 str_to_hex(posptr, symname);
214 gdb_put_packet(connection, opstring, strlen(opstring));
215 free(opstring);
216 return symbols_done;
217 }
218 }
219 gdb_put_packet(connection, "OK", 2);
220 return -1;
221 }
222
223 int rtos_thread_packet(struct connection *connection, char *packet, int packet_size)
224 {
225 struct target *target = get_target_from_connection(connection);
226
227 if (strstr(packet, "qThreadExtraInfo,")) {
228 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) &&
229 (target->rtos->thread_count != 0)) {
230 threadid_t threadid = 0;
231 int found = -1;
232 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
233
234 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
235 int thread_num;
236 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
237 if (target->rtos->thread_details[thread_num].threadid == threadid) {
238 if (target->rtos->thread_details[thread_num].exists)
239 found = thread_num;
240 }
241 }
242 }
243 if (found == -1) {
244 gdb_put_packet(connection, "E01", 3); /* thread not found */
245 return ERROR_OK;
246 }
247
248 struct thread_detail *detail = &target->rtos->thread_details[found];
249
250 int str_size = 0;
251 if (detail->display_str != NULL)
252 str_size += strlen(detail->display_str);
253 if (detail->thread_name_str != NULL)
254 str_size += strlen(detail->thread_name_str);
255 if (detail->extra_info_str != NULL)
256 str_size += strlen(detail->extra_info_str);
257
258 char *tmp_str = (char *) malloc(str_size + 7);
259 char *tmp_str_ptr = tmp_str;
260
261 if (detail->display_str != NULL)
262 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->display_str);
263 if (detail->thread_name_str != NULL) {
264 if (tmp_str_ptr != tmp_str)
265 tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
266 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str);
267 }
268 if (detail->extra_info_str != NULL) {
269 if (tmp_str_ptr != tmp_str)
270 tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
271 tmp_str_ptr +=
272 sprintf(tmp_str_ptr, " : %s", detail->extra_info_str);
273 }
274
275 assert(strlen(tmp_str) ==
276 (size_t) (tmp_str_ptr - tmp_str));
277
278 char *hex_str = (char *) malloc(strlen(tmp_str)*2 + 1);
279 str_to_hex(hex_str, tmp_str);
280
281 gdb_put_packet(connection, hex_str, strlen(hex_str));
282 free(hex_str);
283 free(tmp_str);
284 return ERROR_OK;
285
286 }
287 gdb_put_packet(connection, "", 0);
288 return ERROR_OK;
289 } else if (strstr(packet, "qSymbol")) {
290 if (rtos_qsymbol(connection, packet, packet_size) == 1) {
291 target->rtos_auto_detect = false;
292 target->rtos->type->create(target);
293 target->rtos->type->update_threads(target->rtos);
294 /* No more symbols needed */
295 gdb_put_packet(connection, "OK", 2);
296 }
297 return ERROR_OK;
298 } else if (strstr(packet, "qfThreadInfo")) {
299 int i;
300 if ((target->rtos != NULL) && (target->rtos->thread_count != 0)) {
301
302 char *out_str = (char *) malloc(17 * target->rtos->thread_count + 5);
303 char *tmp_str = out_str;
304 tmp_str += sprintf(tmp_str, "m");
305 for (i = 0; i < target->rtos->thread_count; i++) {
306 if (i != 0)
307 tmp_str += sprintf(tmp_str, ",");
308 tmp_str += sprintf(tmp_str, "%016" PRIx64,
309 target->rtos->thread_details[i].threadid);
310 }
311 tmp_str[0] = 0;
312 gdb_put_packet(connection, out_str, strlen(out_str));
313 } else
314 gdb_put_packet(connection, "", 0);
315
316 return ERROR_OK;
317 } else if (strstr(packet, "qsThreadInfo")) {
318 gdb_put_packet(connection, "l", 1);
319 return ERROR_OK;
320 } else if (strstr(packet, "qAttached")) {
321 gdb_put_packet(connection, "1", 1);
322 return ERROR_OK;
323 } else if (strstr(packet, "qOffsets")) {
324 char offsets[] = "Text=0;Data=0;Bss=0";
325 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
326 return ERROR_OK;
327 } else if (strstr(packet, "qC")) {
328 if (target->rtos != NULL) {
329 char buffer[15];
330 int size;
331 size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread);
332 gdb_put_packet(connection, buffer, size);
333 } else
334 gdb_put_packet(connection, "QC0", 3);
335 return ERROR_OK;
336 } else if (packet[0] == 'T') { /* Is thread alive? */
337 threadid_t threadid;
338 int found = -1;
339 sscanf(packet, "T%" SCNx64, &threadid);
340 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
341 int thread_num;
342 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
343 if (target->rtos->thread_details[thread_num].threadid == threadid) {
344 if (target->rtos->thread_details[thread_num].exists)
345 found = thread_num;
346 }
347 }
348 }
349 if (found != -1)
350 gdb_put_packet(connection, "OK", 2); /* thread alive */
351 else
352 gdb_put_packet(connection, "E01", 3); /* thread not found */
353 return ERROR_OK;
354 } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
355 * all other operations ) */
356 if ((packet[1] == 'g') && (target->rtos != NULL))
357 sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
358 gdb_put_packet(connection, "OK", 2);
359 return ERROR_OK;
360 }
361
362 return GDB_THREAD_PACKET_NOT_CONSUMED;
363 }
364
365 int rtos_get_gdb_reg_list(struct connection *connection)
366 {
367 struct target *target = get_target_from_connection(connection);
368 int64_t current_threadid = target->rtos->current_threadid;
369 if ((target->rtos != NULL) && (current_threadid != -1) &&
370 (current_threadid != 0) &&
371 ((current_threadid != target->rtos->current_thread) ||
372 (target->smp))) { /* in smp several current thread are possible */
373 char *hex_reg_list;
374 target->rtos->type->get_thread_reg_list(target->rtos,
375 current_threadid,
376 &hex_reg_list);
377
378 if (hex_reg_list != NULL) {
379 gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
380 free(hex_reg_list);
381 return ERROR_OK;
382 }
383 }
384 return ERROR_FAIL;
385 }
386
387 int rtos_generic_stack_read(struct target *target,
388 const struct rtos_register_stacking *stacking,
389 int64_t stack_ptr,
390 char **hex_reg_list)
391 {
392 int list_size = 0;
393 char *tmp_str_ptr;
394 int64_t new_stack_ptr;
395 int i;
396 int retval;
397
398 if (stack_ptr == 0) {
399 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
400 return -5;
401 }
402 /* Read the stack */
403 uint8_t *stack_data = (uint8_t *) malloc(stacking->stack_registers_size);
404 uint32_t address = stack_ptr;
405
406 if (stacking->stack_growth_direction == 1)
407 address -= stacking->stack_registers_size;
408 retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
409 if (retval != ERROR_OK) {
410 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
411 return retval;
412 }
413 #if 0
414 LOG_OUTPUT("Stack Data :");
415 for (i = 0; i < stacking->stack_registers_size; i++)
416 LOG_OUTPUT("%02X", stack_data[i]);
417 LOG_OUTPUT("\r\n");
418 #endif
419 for (i = 0; i < stacking->num_output_registers; i++)
420 list_size += stacking->register_offsets[i].width_bits/8;
421 *hex_reg_list = (char *)malloc(list_size*2 + 1);
422 tmp_str_ptr = *hex_reg_list;
423 new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
424 stacking->stack_registers_size;
425 if (stacking->stack_alignment != 0) {
426 /* Align new stack pointer to x byte boundary */
427 new_stack_ptr =
428 (new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) +
429 ((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0);
430 }
431 for (i = 0; i < stacking->num_output_registers; i++) {
432 int j;
433 for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) {
434 if (stacking->register_offsets[i].offset == -1)
435 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0);
436 else if (stacking->register_offsets[i].offset == -2)
437 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
438 ((uint8_t *)&new_stack_ptr)[j]);
439 else
440 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
441 stack_data[stacking->register_offsets[i].offset + j]);
442 }
443 }
444 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
445 return ERROR_OK;
446 }
447
448 int rtos_try_next(struct target *target)
449 {
450 int x;
451
452 if (target->rtos == NULL)
453 return -1;
454
455 for (x = 0; rtos_types[x]; x++) {
456 if (target->rtos->type == rtos_types[x]) {
457 /* found */
458 if (rtos_types[x+1] != NULL) {
459 target->rtos->type = rtos_types[x+1];
460 if (target->rtos->symbols != NULL)
461 free(target->rtos->symbols);
462 return 1;
463 } else {
464 /* No more rtos types */
465 return 0;
466 }
467
468 }
469 }
470 return 0;
471
472 }
473
474 static void hex_to_str(char *dst, char *hex_src)
475 {
476 int src_pos = 0;
477 int dst_pos = 0;
478
479 while (hex_src[src_pos] != '\x00') {
480 char hex_char = hex_src[src_pos];
481 char hex_digit_val =
482 (hex_char >=
483 'a') ? hex_char-'a'+
484 10 : (hex_char >= 'A') ? hex_char-'A'+10 : hex_char-'0';
485 if (0 == (src_pos & 0x01)) {
486 dst[dst_pos] = hex_digit_val;
487 dst[dst_pos+1] = 0;
488 } else {
489 ((unsigned char *)dst)[dst_pos] <<= 4;
490 ((unsigned char *)dst)[dst_pos] += hex_digit_val;
491 dst_pos++;
492 }
493 src_pos++;
494 }
495
496 }
497
498 int str_to_hex(char *hex_dst, char *src)
499 {
500 char *posptr = hex_dst;
501 unsigned i;
502 for (i = 0; i < strlen(src); i++)
503 posptr += sprintf(posptr, "%02x", (unsigned char)src[i]);
504 return posptr - hex_dst;
505 }
506
507 int rtos_update_threads(struct target *target)
508 {
509 if ((target->rtos != NULL) && (target->rtos->type != NULL))
510 target->rtos->type->update_threads(target->rtos);
511 return ERROR_OK;
512 }

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)