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

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)