aa0976b5c5b2dede68dda6e3c4aef0413320269b
[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 /* return -1 if no rtos defined, 0 if rtos and symbol to be asked, 1 if all
147 * symbol have been asked*/
148 int rtos_qsymbol(struct connection *connection, char *packet, int packet_size)
149 {
150 struct target *target = get_target_from_connection(connection);
151 if (target->rtos != NULL) {
152 int next_symbol_num = -1;
153 if (target->rtos->symbols == NULL)
154 target->rtos->type->get_symbol_list_to_lookup(&target->rtos->symbols);
155 if (0 == strcmp("qSymbol::", packet))
156 /* first query - */
157 next_symbol_num = 0;
158 else {
159 int64_t value = 0;
160 char *hex_name_str = malloc(strlen(packet));
161 char *name_str;
162 int symbol_num;
163
164 char *found = strstr(packet, "qSymbol::");
165 if (0 == found)
166 sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str);
167 else
168 /* No value returned by GDB - symbol was not found*/
169 sscanf(packet, "qSymbol::%s", hex_name_str);
170 name_str = (char *) malloc(1 + strlen(hex_name_str) / 2);
171
172 hex_to_str(name_str, hex_name_str);
173 symbol_num = 0;
174 while ((target->rtos->symbols[symbol_num].symbol_name != NULL) &&
175 (0 != strcmp(target->rtos->symbols[symbol_num].symbol_name, name_str)))
176 symbol_num++;
177
178 if (target->rtos->symbols[symbol_num].symbol_name == NULL) {
179 LOG_OUTPUT("ERROR: unknown symbol\r\n");
180 gdb_put_packet(connection, "OK", 2);
181 free(hex_name_str);
182 free(name_str);
183 return ERROR_OK;
184 }
185
186 target->rtos->symbols[symbol_num].address = value;
187
188 next_symbol_num = symbol_num+1;
189 free(hex_name_str);
190 free(name_str);
191 }
192
193 int symbols_done = 0;
194 if (target->rtos->symbols[next_symbol_num].symbol_name == NULL) {
195 if ((target->rtos_auto_detect == false) ||
196 (1 == target->rtos->type->detect_rtos(target))) {
197 /* Found correct RTOS or not autodetecting */
198 if (target->rtos_auto_detect == true)
199 LOG_OUTPUT("Auto-detected RTOS: %s\r\n",
200 target->rtos->type->name);
201 symbols_done = 1;
202 } else {
203 /* Auto detecting RTOS and currently not found */
204 if (1 != rtos_try_next(target))
205 /* No more RTOS's to try */
206 symbols_done = 1;
207 else {
208 next_symbol_num = 0;
209 target->rtos->type->get_symbol_list_to_lookup(
210 &target->rtos->symbols);
211 }
212 }
213 }
214 if (symbols_done == 1)
215 return symbols_done;
216 else {
217 char *symname = target->rtos->symbols[next_symbol_num].symbol_name;
218 char qsymstr[] = "qSymbol:";
219 char *opstring = (char *)malloc(sizeof(qsymstr)+strlen(symname)*2+1);
220 char *posptr = opstring;
221 posptr += sprintf(posptr, "%s", qsymstr);
222 str_to_hex(posptr, symname);
223 gdb_put_packet(connection, opstring, strlen(opstring));
224 free(opstring);
225 return symbols_done;
226 }
227 }
228 gdb_put_packet(connection, "OK", 2);
229 return -1;
230 }
231
232 int rtos_thread_packet(struct connection *connection, char *packet, int packet_size)
233 {
234 struct target *target = get_target_from_connection(connection);
235
236 if (strstr(packet, "qThreadExtraInfo,")) {
237 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) &&
238 (target->rtos->thread_count != 0)) {
239 threadid_t threadid = 0;
240 int found = -1;
241 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
242
243 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
244 int thread_num;
245 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
246 if (target->rtos->thread_details[thread_num].threadid == threadid) {
247 if (target->rtos->thread_details[thread_num].exists)
248 found = thread_num;
249 }
250 }
251 }
252 if (found == -1) {
253 gdb_put_packet(connection, "E01", 3); /* thread not found */
254 return ERROR_OK;
255 }
256
257 struct thread_detail *detail = &target->rtos->thread_details[found];
258
259 int str_size = 0;
260 if (detail->display_str != NULL)
261 str_size += strlen(detail->display_str);
262 if (detail->thread_name_str != NULL)
263 str_size += strlen(detail->thread_name_str);
264 if (detail->extra_info_str != NULL)
265 str_size += strlen(detail->extra_info_str);
266
267 char *tmp_str = (char *) malloc(str_size + 7);
268 char *tmp_str_ptr = tmp_str;
269
270 if (detail->display_str != NULL)
271 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->display_str);
272 if (detail->thread_name_str != NULL) {
273 if (tmp_str_ptr != tmp_str)
274 tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
275 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str);
276 }
277 if (detail->extra_info_str != NULL) {
278 if (tmp_str_ptr != tmp_str)
279 tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
280 tmp_str_ptr +=
281 sprintf(tmp_str_ptr, " : %s", detail->extra_info_str);
282 }
283
284 assert(strlen(tmp_str) ==
285 (size_t) (tmp_str_ptr - tmp_str));
286
287 char *hex_str = (char *) malloc(strlen(tmp_str)*2 + 1);
288 str_to_hex(hex_str, tmp_str);
289
290 gdb_put_packet(connection, hex_str, strlen(hex_str));
291 free(hex_str);
292 free(tmp_str);
293 return ERROR_OK;
294
295 }
296 gdb_put_packet(connection, "", 0);
297 return ERROR_OK;
298 } else if (strstr(packet, "qSymbol")) {
299 if (rtos_qsymbol(connection, packet, packet_size) == 1) {
300 target->rtos_auto_detect = false;
301 target->rtos->type->create(target);
302 target->rtos->type->update_threads(target->rtos);
303 /* No more symbols needed */
304 gdb_put_packet(connection, "OK", 2);
305 }
306 return ERROR_OK;
307 } else if (strstr(packet, "qfThreadInfo")) {
308 int i;
309 if ((target->rtos != NULL) && (target->rtos->thread_count != 0)) {
310
311 char *out_str = (char *) malloc(17 * target->rtos->thread_count + 5);
312 char *tmp_str = out_str;
313 tmp_str += sprintf(tmp_str, "m");
314 for (i = 0; i < target->rtos->thread_count; i++) {
315 if (i != 0)
316 tmp_str += sprintf(tmp_str, ",");
317 tmp_str += sprintf(tmp_str, "%016" PRIx64,
318 target->rtos->thread_details[i].threadid);
319 }
320 tmp_str[0] = 0;
321 gdb_put_packet(connection, out_str, strlen(out_str));
322 } else
323 gdb_put_packet(connection, "", 0);
324
325 return ERROR_OK;
326 } else if (strstr(packet, "qsThreadInfo")) {
327 gdb_put_packet(connection, "l", 1);
328 return ERROR_OK;
329 } else if (strstr(packet, "qAttached")) {
330 gdb_put_packet(connection, "1", 1);
331 return ERROR_OK;
332 } else if (strstr(packet, "qOffsets")) {
333 char offsets[] = "Text=0;Data=0;Bss=0";
334 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
335 return ERROR_OK;
336 } else if (strstr(packet, "qC")) {
337 if (target->rtos != NULL) {
338 char buffer[15];
339 int size;
340 size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread);
341 gdb_put_packet(connection, buffer, size);
342 } else
343 gdb_put_packet(connection, "QC0", 3);
344 return ERROR_OK;
345 } else if (packet[0] == 'T') { /* Is thread alive? */
346 threadid_t threadid;
347 int found = -1;
348 sscanf(packet, "T%" SCNx64, &threadid);
349 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
350 int thread_num;
351 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
352 if (target->rtos->thread_details[thread_num].threadid == threadid) {
353 if (target->rtos->thread_details[thread_num].exists)
354 found = thread_num;
355 }
356 }
357 }
358 if (found != -1)
359 gdb_put_packet(connection, "OK", 2); /* thread alive */
360 else
361 gdb_put_packet(connection, "E01", 3); /* thread not found */
362 return ERROR_OK;
363 } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
364 * all other operations ) */
365 if ((packet[1] == 'g') && (target->rtos != NULL))
366 sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
367 gdb_put_packet(connection, "OK", 2);
368 return ERROR_OK;
369 }
370
371 return GDB_THREAD_PACKET_NOT_CONSUMED;
372 }
373
374 int rtos_get_gdb_reg_list(struct connection *connection)
375 {
376 struct target *target = get_target_from_connection(connection);
377 int64_t current_threadid = target->rtos->current_threadid;
378 if ((target->rtos != NULL) && (current_threadid != -1) &&
379 (current_threadid != 0) &&
380 ((current_threadid != target->rtos->current_thread) ||
381 (target->smp))) { /* in smp several current thread are possible */
382 char *hex_reg_list;
383 target->rtos->type->get_thread_reg_list(target->rtos,
384 current_threadid,
385 &hex_reg_list);
386
387 if (hex_reg_list != NULL) {
388 gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
389 free(hex_reg_list);
390 return ERROR_OK;
391 }
392 }
393 return ERROR_FAIL;
394 }
395
396 int rtos_generic_stack_read(struct target *target,
397 const struct rtos_register_stacking *stacking,
398 int64_t stack_ptr,
399 char **hex_reg_list)
400 {
401 int list_size = 0;
402 char *tmp_str_ptr;
403 int64_t new_stack_ptr;
404 int i;
405 int retval;
406
407 if (stack_ptr == 0) {
408 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
409 return -5;
410 }
411 /* Read the stack */
412 uint8_t *stack_data = (uint8_t *) malloc(stacking->stack_registers_size);
413 uint32_t address = stack_ptr;
414
415 if (stacking->stack_growth_direction == 1)
416 address -= stacking->stack_registers_size;
417 retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
418 if (retval != ERROR_OK) {
419 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
420 return retval;
421 }
422 #if 0
423 LOG_OUTPUT("Stack Data :");
424 for (i = 0; i < stacking->stack_registers_size; i++)
425 LOG_OUTPUT("%02X", stack_data[i]);
426 LOG_OUTPUT("\r\n");
427 #endif
428 for (i = 0; i < stacking->num_output_registers; i++)
429 list_size += stacking->register_offsets[i].width_bits/8;
430 *hex_reg_list = (char *)malloc(list_size*2 + 1);
431 tmp_str_ptr = *hex_reg_list;
432 new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
433 stacking->stack_registers_size;
434 if (stacking->stack_alignment != 0) {
435 /* Align new stack pointer to x byte boundary */
436 new_stack_ptr =
437 (new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) +
438 ((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0);
439 }
440 for (i = 0; i < stacking->num_output_registers; i++) {
441 int j;
442 for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) {
443 if (stacking->register_offsets[i].offset == -1)
444 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0);
445 else if (stacking->register_offsets[i].offset == -2)
446 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
447 ((uint8_t *)&new_stack_ptr)[j]);
448 else
449 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
450 stack_data[stacking->register_offsets[i].offset + j]);
451 }
452 }
453 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
454 return ERROR_OK;
455 }
456
457 int rtos_try_next(struct target *target)
458 {
459 struct rtos *os = target->rtos;
460 struct rtos_type **type = rtos_types;
461
462 if (!os)
463 return 0;
464
465 while (*type && os->type != *type)
466 type++;
467
468 if (!*type || !*(++type))
469 return 0;
470
471 os->type = *type;
472 if (os->symbols) {
473 free(os->symbols);
474 os->symbols = NULL;
475 }
476
477 return 1;
478 }
479
480 static void hex_to_str(char *dst, char *hex_src)
481 {
482 int src_pos = 0;
483 int dst_pos = 0;
484
485 while (hex_src[src_pos] != '\x00') {
486 char hex_char = hex_src[src_pos];
487 char hex_digit_val =
488 (hex_char >=
489 'a') ? hex_char-'a'+
490 10 : (hex_char >= 'A') ? hex_char-'A'+10 : hex_char-'0';
491 if (0 == (src_pos & 0x01)) {
492 dst[dst_pos] = hex_digit_val;
493 dst[dst_pos+1] = 0;
494 } else {
495 ((unsigned char *)dst)[dst_pos] <<= 4;
496 ((unsigned char *)dst)[dst_pos] += hex_digit_val;
497 dst_pos++;
498 }
499 src_pos++;
500 }
501
502 }
503
504 int str_to_hex(char *hex_dst, char *src)
505 {
506 char *posptr = hex_dst;
507 unsigned i;
508 for (i = 0; i < strlen(src); i++)
509 posptr += sprintf(posptr, "%02x", (unsigned char)src[i]);
510 return posptr - hex_dst;
511 }
512
513 int rtos_update_threads(struct target *target)
514 {
515 if ((target->rtos != NULL) && (target->rtos->type != NULL))
516 target->rtos->type->update_threads(target->rtos);
517 return ERROR_OK;
518 }

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)