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

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)