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

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)