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

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)