RTOS: Add logging to FreeRTOS and general RTOS
[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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "helper/binarybuffer.h"
29 #include "server/gdb_server.h"
30
31 /* RTOSs */
32 extern struct rtos_type FreeRTOS_rtos;
33 extern struct rtos_type ThreadX_rtos;
34 extern struct rtos_type eCos_rtos;
35 extern struct rtos_type Linux_os;
36 extern struct rtos_type ChibiOS_rtos;
37 extern struct rtos_type embKernel_rtos;
38 extern struct rtos_type mqx_rtos;
39
40 static struct rtos_type *rtos_types[] = {
41 &ThreadX_rtos,
42 &FreeRTOS_rtos,
43 &eCos_rtos,
44 &Linux_os,
45 &ChibiOS_rtos,
46 &embKernel_rtos,
47 &mqx_rtos,
48 NULL
49 };
50
51 int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
52
53 int rtos_smp_init(struct target *target)
54 {
55 if (target->rtos->type->smp_init)
56 return target->rtos->type->smp_init(target);
57 return ERROR_TARGET_INIT_FAILED;
58 }
59
60 static int os_alloc(struct target *target, struct rtos_type *ostype)
61 {
62 struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos));
63
64 if (!os)
65 return JIM_ERR;
66
67 os->type = ostype;
68 os->current_threadid = -1;
69 os->current_thread = 0;
70 os->symbols = NULL;
71 os->target = target;
72
73 /* RTOS drivers can override the packet handler in _create(). */
74 os->gdb_thread_packet = rtos_thread_packet;
75
76 return JIM_OK;
77 }
78
79 static void os_free(struct target *target)
80 {
81 if (!target->rtos)
82 return;
83
84 if (target->rtos->symbols)
85 free(target->rtos->symbols);
86
87 free(target->rtos);
88 target->rtos = NULL;
89 }
90
91 static int os_alloc_create(struct target *target, struct rtos_type *ostype)
92 {
93 int ret = os_alloc(target, ostype);
94
95 if (JIM_OK == ret) {
96 ret = target->rtos->type->create(target);
97 if (ret != JIM_OK)
98 os_free(target);
99 }
100
101 return ret;
102 }
103
104 int rtos_create(Jim_GetOptInfo *goi, struct target *target)
105 {
106 int x;
107 char *cp;
108 struct Jim_Obj *res;
109
110 if (!goi->isconfigure && goi->argc != 0) {
111 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
112 return JIM_ERR;
113 }
114
115 os_free(target);
116
117 Jim_GetOpt_String(goi, &cp, NULL);
118
119 if (0 == strcmp(cp, "auto")) {
120 /* Auto detect tries to look up all symbols for each RTOS,
121 * and runs the RTOS driver's _detect() function when GDB
122 * finds all symbols for any RTOS. See rtos_qsymbol(). */
123 target->rtos_auto_detect = true;
124
125 /* rtos_qsymbol() will iterate over all RTOSes. Allocate
126 * target->rtos here, and set it to the first RTOS type. */
127 return os_alloc(target, rtos_types[0]);
128 }
129
130 for (x = 0; rtos_types[x]; x++)
131 if (0 == strcmp(cp, rtos_types[x]->name))
132 return os_alloc_create(target, rtos_types[x]);
133
134 Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp);
135 res = Jim_GetResult(goi->interp);
136 for (x = 0; rtos_types[x]; x++)
137 Jim_AppendStrings(goi->interp, res, rtos_types[x]->name, ", ", NULL);
138 Jim_AppendStrings(goi->interp, res, " or auto", NULL);
139
140 return JIM_ERR;
141 }
142
143 int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size)
144 {
145 struct target *target = get_target_from_connection(connection);
146 if (target->rtos == NULL)
147 return rtos_thread_packet(connection, packet, packet_size); /* thread not
148 *found*/
149 return target->rtos->gdb_thread_packet(connection, packet, packet_size);
150 }
151
152 static symbol_table_elem_t *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr)
153 {
154 symbol_table_elem_t *s;
155
156 if (!os->symbols)
157 os->type->get_symbol_list_to_lookup(&os->symbols);
158
159 if (!cur_symbol[0])
160 return &os->symbols[0];
161
162 for (s = os->symbols; s->symbol_name; s++)
163 if (!strcmp(s->symbol_name, cur_symbol)) {
164 s->address = cur_addr;
165 s++;
166 return s;
167 }
168
169 return NULL;
170 }
171
172 /* searches for 'symbol' in the lookup table for 'os' and returns TRUE,
173 * if 'symbol' is not declared optional */
174 static bool is_symbol_mandatory(const struct rtos *os, const char *symbol)
175 {
176 for (symbol_table_elem_t *s = os->symbols; s->symbol_name; ++s) {
177 if (!strcmp(s->symbol_name, symbol))
178 return !s->optional;
179 }
180 return false;
181 }
182
183 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
184 *
185 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
186 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
187 *
188 * If the qSymbol packet has no address that means GDB did not find the
189 * symbol, in which case auto-detect will move on to try the next RTOS.
190 *
191 * rtos_qsymbol() then calls the next_symbol() helper function, which
192 * iterates over symbol names for the current RTOS until it finds the
193 * symbol in the received GDB packet, and then returns the next entry
194 * in the list of symbols.
195 *
196 * If GDB replied about the last symbol for the RTOS and the RTOS was
197 * specified explicitly, then no further symbol lookup is done. When
198 * auto-detecting, the RTOS driver _detect() function must return success.
199 *
200 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
201 */
202 int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size)
203 {
204 int rtos_detected = 0;
205 uint64_t addr = 0;
206 size_t reply_len;
207 char reply[GDB_BUFFER_SIZE], cur_sym[GDB_BUFFER_SIZE / 2] = "";
208 symbol_table_elem_t *next_sym = NULL;
209 struct target *target = get_target_from_connection(connection);
210 struct rtos *os = target->rtos;
211
212 reply_len = sprintf(reply, "OK");
213
214 if (!os)
215 goto done;
216
217 /* Decode any symbol name in the packet*/
218 int len = unhexify(cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1));
219 cur_sym[len] = 0;
220
221 if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
222 (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr)) && /* GDB did not find an address for a symbol */
223 is_symbol_mandatory(os, cur_sym)) { /* the symbol is mandatory for this RTOS */
224
225 /* GDB could not find an address for the previous symbol */
226 if (!target->rtos_auto_detect) {
227 LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym);
228 goto done;
229 } else {
230 /* Autodetecting RTOS - try next RTOS */
231 if (!rtos_try_next(target)) {
232 LOG_WARNING("No RTOS could be auto-detected!");
233 goto done;
234 }
235
236 /* Next RTOS selected - invalidate current symbol */
237 cur_sym[0] = '\x00';
238 }
239 }
240 next_sym = next_symbol(os, cur_sym, addr);
241
242 if (!next_sym->symbol_name) {
243 /* No more symbols need looking up */
244
245 if (!target->rtos_auto_detect) {
246 rtos_detected = 1;
247 goto done;
248 }
249
250 if (os->type->detect_rtos(target)) {
251 LOG_INFO("Auto-detected RTOS: %s", os->type->name);
252 rtos_detected = 1;
253 goto done;
254 } else {
255 LOG_WARNING("No RTOS could be auto-detected!");
256 goto done;
257 }
258 }
259
260 if (8 + (strlen(next_sym->symbol_name) * 2) + 1 > sizeof(reply)) {
261 LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym->symbol_name);
262 goto done;
263 }
264
265 reply_len = snprintf(reply, sizeof(reply), "qSymbol:");
266 reply_len += hexify(reply + reply_len, next_sym->symbol_name, 0, sizeof(reply) - reply_len);
267
268 done:
269 gdb_put_packet(connection, reply, reply_len);
270 return rtos_detected;
271 }
272
273 int rtos_thread_packet(struct connection *connection, char const *packet, int packet_size)
274 {
275 struct target *target = get_target_from_connection(connection);
276
277 if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) {
278 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) &&
279 (target->rtos->thread_count != 0)) {
280 threadid_t threadid = 0;
281 int found = -1;
282 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
283
284 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
285 int thread_num;
286 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
287 if (target->rtos->thread_details[thread_num].threadid == threadid) {
288 if (target->rtos->thread_details[thread_num].exists)
289 found = thread_num;
290 }
291 }
292 }
293 if (found == -1) {
294 gdb_put_packet(connection, "E01", 3); /* thread not found */
295 return ERROR_OK;
296 }
297
298 struct thread_detail *detail = &target->rtos->thread_details[found];
299
300 int str_size = 0;
301 if (detail->display_str != NULL)
302 str_size += strlen(detail->display_str);
303 if (detail->thread_name_str != NULL)
304 str_size += strlen(detail->thread_name_str);
305 if (detail->extra_info_str != NULL)
306 str_size += strlen(detail->extra_info_str);
307
308 char *tmp_str = calloc(str_size + 7, sizeof(char));
309 char *tmp_str_ptr = tmp_str;
310
311 if (detail->display_str != NULL)
312 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->display_str);
313 if (detail->thread_name_str != NULL) {
314 if (tmp_str_ptr != tmp_str)
315 tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
316 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str);
317 }
318 if (detail->extra_info_str != NULL) {
319 if (tmp_str_ptr != tmp_str)
320 tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
321 tmp_str_ptr +=
322 sprintf(tmp_str_ptr, " : %s", detail->extra_info_str);
323 }
324
325 assert(strlen(tmp_str) ==
326 (size_t) (tmp_str_ptr - tmp_str));
327
328 char *hex_str = malloc(strlen(tmp_str) * 2 + 1);
329 int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1);
330
331 gdb_put_packet(connection, hex_str, pkt_len);
332 free(hex_str);
333 free(tmp_str);
334 return ERROR_OK;
335
336 }
337 gdb_put_packet(connection, "", 0);
338 return ERROR_OK;
339 } else if (strncmp(packet, "qSymbol", 7) == 0) {
340 if (rtos_qsymbol(connection, packet, packet_size) == 1) {
341 target->rtos_auto_detect = false;
342 target->rtos->type->create(target);
343 target->rtos->type->update_threads(target->rtos);
344 }
345 return ERROR_OK;
346 } else if (strncmp(packet, "qfThreadInfo", 12) == 0) {
347 int i;
348 if (target->rtos != NULL) {
349 if (target->rtos->thread_count == 0) {
350 gdb_put_packet(connection, "l", 1);
351 } else {
352 /*thread id are 16 char +1 for ',' */
353 char *out_str = malloc(17 * target->rtos->thread_count + 1);
354 char *tmp_str = out_str;
355 for (i = 0; i < target->rtos->thread_count; i++) {
356 tmp_str += sprintf(tmp_str, "%c%016" PRIx64, i == 0 ? 'm' : ',',
357 target->rtos->thread_details[i].threadid);
358 }
359 gdb_put_packet(connection, out_str, strlen(out_str));
360 free(out_str);
361 }
362 } else
363 gdb_put_packet(connection, "l", 1);
364
365 return ERROR_OK;
366 } else if (strncmp(packet, "qsThreadInfo", 12) == 0) {
367 gdb_put_packet(connection, "l", 1);
368 return ERROR_OK;
369 } else if (strncmp(packet, "qAttached", 9) == 0) {
370 gdb_put_packet(connection, "1", 1);
371 return ERROR_OK;
372 } else if (strncmp(packet, "qOffsets", 8) == 0) {
373 char offsets[] = "Text=0;Data=0;Bss=0";
374 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
375 return ERROR_OK;
376 } else if (strncmp(packet, "qCRC:", 5) == 0) {
377 /* make sure we check this before "qC" packet below
378 * otherwise it gets incorrectly handled */
379 return GDB_THREAD_PACKET_NOT_CONSUMED;
380 } else if (strncmp(packet, "qC", 2) == 0) {
381 if (target->rtos != NULL) {
382 char buffer[19];
383 int size;
384 size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread);
385 gdb_put_packet(connection, buffer, size);
386 } else
387 gdb_put_packet(connection, "QC0", 3);
388 return ERROR_OK;
389 } else if (packet[0] == 'T') { /* Is thread alive? */
390 threadid_t threadid;
391 int found = -1;
392 sscanf(packet, "T%" SCNx64, &threadid);
393 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
394 int thread_num;
395 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
396 if (target->rtos->thread_details[thread_num].threadid == threadid) {
397 if (target->rtos->thread_details[thread_num].exists)
398 found = thread_num;
399 }
400 }
401 }
402 if (found != -1)
403 gdb_put_packet(connection, "OK", 2); /* thread alive */
404 else
405 gdb_put_packet(connection, "E01", 3); /* thread not found */
406 return ERROR_OK;
407 } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
408 * all other operations ) */
409 if ((packet[1] == 'g') && (target->rtos != NULL)) {
410 sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
411 LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64 "\r\n",
412 target->rtos->current_threadid);
413 }
414 gdb_put_packet(connection, "OK", 2);
415 return ERROR_OK;
416 }
417
418 return GDB_THREAD_PACKET_NOT_CONSUMED;
419 }
420
421 int rtos_get_gdb_reg_list(struct connection *connection)
422 {
423 struct target *target = get_target_from_connection(connection);
424 int64_t current_threadid = target->rtos->current_threadid;
425 if ((target->rtos != NULL) && (current_threadid != -1) &&
426 (current_threadid != 0) &&
427 ((current_threadid != target->rtos->current_thread) ||
428 (target->smp))) { /* in smp several current thread are possible */
429 char *hex_reg_list;
430
431 LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
432 ", target->rtos->current_thread=0x%" PRIx64 "\r\n",
433 current_threadid,
434 target->rtos->current_thread);
435
436 target->rtos->type->get_thread_reg_list(target->rtos,
437 current_threadid,
438 &hex_reg_list);
439
440 if (hex_reg_list != NULL) {
441 gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
442 free(hex_reg_list);
443 return ERROR_OK;
444 }
445 }
446 return ERROR_FAIL;
447 }
448
449 int rtos_generic_stack_read(struct target *target,
450 const struct rtos_register_stacking *stacking,
451 int64_t stack_ptr,
452 char **hex_reg_list)
453 {
454 int list_size = 0;
455 char *tmp_str_ptr;
456 int64_t new_stack_ptr;
457 int i;
458 int retval;
459
460 if (stack_ptr == 0) {
461 LOG_ERROR("Error: null stack pointer in thread");
462 return -5;
463 }
464 /* Read the stack */
465 uint8_t *stack_data = malloc(stacking->stack_registers_size);
466 uint32_t address = stack_ptr;
467
468 if (stacking->stack_growth_direction == 1)
469 address -= stacking->stack_registers_size;
470 retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
471 if (retval != ERROR_OK) {
472 free(stack_data);
473 LOG_ERROR("Error reading stack frame from thread");
474 return retval;
475 }
476 LOG_DEBUG("RTOS: Read stack frame at 0x%x\r\n", address);
477
478 #if 0
479 LOG_OUTPUT("Stack Data :");
480 for (i = 0; i < stacking->stack_registers_size; i++)
481 LOG_OUTPUT("%02X", stack_data[i]);
482 LOG_OUTPUT("\r\n");
483 #endif
484 for (i = 0; i < stacking->num_output_registers; i++)
485 list_size += stacking->register_offsets[i].width_bits/8;
486 *hex_reg_list = malloc(list_size*2 + 1);
487 tmp_str_ptr = *hex_reg_list;
488 new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
489 stacking->stack_registers_size;
490 if (stacking->stack_alignment != 0) {
491 /* Align new stack pointer to x byte boundary */
492 new_stack_ptr =
493 (new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) +
494 ((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0);
495 }
496 for (i = 0; i < stacking->num_output_registers; i++) {
497 int j;
498 for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) {
499 if (stacking->register_offsets[i].offset == -1)
500 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0);
501 else if (stacking->register_offsets[i].offset == -2)
502 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
503 ((uint8_t *)&new_stack_ptr)[j]);
504 else
505 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
506 stack_data[stacking->register_offsets[i].offset + j]);
507 }
508 }
509 free(stack_data);
510 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
511 return ERROR_OK;
512 }
513
514 int rtos_try_next(struct target *target)
515 {
516 struct rtos *os = target->rtos;
517 struct rtos_type **type = rtos_types;
518
519 if (!os)
520 return 0;
521
522 while (*type && os->type != *type)
523 type++;
524
525 if (!*type || !*(++type))
526 return 0;
527
528 os->type = *type;
529 if (os->symbols) {
530 free(os->symbols);
531 os->symbols = NULL;
532 }
533
534 return 1;
535 }
536
537 int rtos_update_threads(struct target *target)
538 {
539 if ((target->rtos != NULL) && (target->rtos->type != NULL))
540 target->rtos->type->update_threads(target->rtos);
541 return ERROR_OK;
542 }
543
544 void rtos_free_threadlist(struct rtos *rtos)
545 {
546 if (rtos->thread_details) {
547 int j;
548
549 for (j = 0; j < rtos->thread_count; j++) {
550 struct thread_detail *current_thread = &rtos->thread_details[j];
551 free(current_thread->display_str);
552 free(current_thread->thread_name_str);
553 free(current_thread->extra_info_str);
554 }
555 free(rtos->thread_details);
556 rtos->thread_details = NULL;
557 rtos->thread_count = 0;
558 }
559 }

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)