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

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)