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

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)