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

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)