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

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)