rtos : create qsymbol interface and add str_to_hex interface
[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
26 #include "rtos.h"
27 #include "target/target.h"
28 #include "helper/log.h"
29 #include "server/gdb_server.h"
30
31
32
33 static void hex_to_str( char* dst, char * hex_src );
34
35
36 /* RTOSs */
37 extern struct rtos_type FreeRTOS_rtos;
38 extern struct rtos_type ThreadX_rtos;
39 extern struct rtos_type eCos_rtos;
40
41 static struct rtos_type *rtos_types[] =
42 {
43 &ThreadX_rtos,
44 &FreeRTOS_rtos,
45 &eCos_rtos,
46 NULL
47 };
48
49 int rtos_thread_packet(struct connection *connection, 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
59 int rtos_create(Jim_GetOptInfo *goi, struct target * target)
60 {
61 int x;
62 char *cp;
63 if (! goi->isconfigure) {
64 if (goi->argc != 0) {
65 if (goi->argc != 0) {
66 Jim_WrongNumArgs(goi->interp,
67 goi->argc, goi->argv,
68 "NO PARAMS");
69 return JIM_ERR;
70 }
71
72 Jim_SetResultString(goi->interp,
73 target_type_name(target), -1);
74 }
75 }
76
77 if (target->rtos) {
78 free((void *)(target->rtos));
79 }
80 // e = Jim_GetOpt_String(goi, &cp, NULL);
81 // target->rtos = strdup(cp);
82
83 Jim_GetOpt_String(goi, &cp, NULL);
84 /* now does target type exist */
85
86 if ( 0 == strcmp( cp, "auto") )
87 {
88 // auto detection of RTOS
89 target->rtos_auto_detect = true;
90 x = 0;
91 }
92 else
93 {
94
95 for (x = 0 ; rtos_types[x] ; x++) {
96 if (0 == strcmp(cp, rtos_types[x]->name)) {
97 /* found */
98 break;
99 }
100 }
101 if (rtos_types[x] == NULL) {
102 Jim_SetResultFormatted(goi->interp, "Unknown rtos type %s, try one of ", cp);
103 for (x = 0 ; rtos_types[x] ; x++) {
104 if (rtos_types[x + 1]) {
105 Jim_AppendStrings(goi->interp,
106 Jim_GetResult(goi->interp),
107 rtos_types[x]->name,
108 ", ", NULL);
109 } else {
110 Jim_AppendStrings(goi->interp,
111 Jim_GetResult(goi->interp),
112 " or ",
113 rtos_types[x]->name,NULL);
114 }
115 }
116 return JIM_ERR;
117 }
118 }
119 /* Create it */
120 target->rtos = calloc(1,sizeof(struct rtos));
121 target->rtos->type = rtos_types[x];
122 target->rtos->current_threadid = -1;
123 target->rtos->current_thread = 0;
124 target->rtos->symbols = NULL;
125 target->rtos->target = target;
126 /* put default thread handler in linux usecase it is overloaded*/
127 target->rtos->gdb_thread_packet = rtos_thread_packet;
128
129 if ( 0 != strcmp( cp, "auto") )
130 {
131 target->rtos->type->create( target );
132 }
133
134 return JIM_OK;
135 }
136
137 int gdb_thread_packet(struct connection *connection, char *packet, int packet_size)
138 {
139 struct target *target = get_target_from_connection(connection);
140 if (target->rtos == NULL)
141 return rtos_thread_packet(connection, packet, packet_size); /* thread not found*/
142 return target->rtos->gdb_thread_packet(connection, packet, packet_size);
143 }
144 /* return -1 if no rtos defined, 0 if rtos and symbol to be asked, 1 if all
145 * symbol have been asked*/
146 int rtos_qsymbol(struct connection *connection, char *packet, int packet_size)
147 {
148 struct target *target = get_target_from_connection(connection);
149 if (target->rtos != NULL) {
150 int next_symbol_num = -1;
151 if (target->rtos->symbols == NULL)
152 target->rtos->type->get_symbol_list_to_lookup(&target->rtos->symbols);
153 if (0 == strcmp("qSymbol::", packet))
154 /* first query - */
155 next_symbol_num = 0;
156 else {
157 int64_t value = 0;
158 char *hex_name_str = malloc(strlen(packet));
159 char *name_str;
160 int symbol_num;
161
162 char *found = strstr(packet, "qSymbol::");
163 if (0 == found)
164 sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str);
165 else
166 /* No value returned by GDB - symbol was not found*/
167 sscanf(packet, "qSymbol::%s", hex_name_str);
168 name_str = (char *) malloc(1 + strlen(hex_name_str) / 2);
169
170 hex_to_str(name_str, hex_name_str);
171 symbol_num = 0;
172 while ((target->rtos->symbols[symbol_num].symbol_name != NULL)
173 && (0 != strcmp(target->rtos->symbols[symbol_num].symbol_name, name_str)))
174 symbol_num++;
175
176 if (target->rtos->symbols[symbol_num].symbol_name == NULL) {
177 LOG_OUTPUT("ERROR: unknown symbol\r\n");
178 gdb_put_packet(connection, "OK", 2);
179 return ERROR_OK;
180 }
181
182 target->rtos->symbols[symbol_num].address = value;
183
184 next_symbol_num = symbol_num+1;
185 free(hex_name_str);
186 free(name_str);
187 }
188
189 int symbols_done = 0;
190 if (target->rtos->symbols[next_symbol_num].symbol_name == NULL) {
191 if ((target->rtos_auto_detect == false) ||
192 (1 == target->rtos->type->detect_rtos(target))) {
193 /* Found correct RTOS or not autodetecting */
194 if (target->rtos_auto_detect == true)
195 LOG_OUTPUT("Auto-detected RTOS: %s\r\n", target->rtos->type->name);
196 symbols_done = 1;
197 } else {
198 /* Auto detecting RTOS and currently not found */
199 if (1 != rtos_try_next(target))
200 /* No more RTOS's to try */
201 symbols_done = 1;
202 else {
203 next_symbol_num = 0;
204 target->rtos->type->get_symbol_list_to_lookup(&target->rtos->symbols);
205 }
206 }
207 }
208 if (symbols_done == 1)
209 return symbols_done;
210 else {
211 char *symname = target->rtos->symbols[next_symbol_num].symbol_name;
212 char qsymstr[] = "qSymbol:";
213 char *opstring = (char *)malloc(sizeof(qsymstr)+strlen(symname)*2+1);
214 char *posptr = opstring;
215 posptr += sprintf(posptr, "%s", qsymstr);
216 str_to_hex(posptr, symname);
217 gdb_put_packet(connection, opstring, strlen(opstring));
218 free(opstring);
219 return symbols_done;
220 }
221 }
222 gdb_put_packet(connection, "OK", 2);
223 return -1;
224 }
225
226
227 int rtos_thread_packet(struct connection *connection, char *packet, int packet_size)
228 {
229 struct target *target = get_target_from_connection(connection);
230
231 if (strstr(packet, "qThreadExtraInfo,"))
232 {
233 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0))
234 {
235 threadid_t threadid = 0;
236 int found = -1;
237 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid );
238
239 if ((target->rtos != NULL) && (target->rtos->thread_details
240 != NULL)) {
241 int thread_num;
242 for (thread_num = 0; thread_num
243 < target->rtos->thread_count; thread_num++) {
244 if (target->rtos->thread_details[thread_num].threadid
245 == threadid) {
246 if (target->rtos->thread_details[thread_num].exists) {
247 found = thread_num;
248 }
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 {
262 str_size += strlen(detail->display_str);
263 }
264 if ( detail->thread_name_str != NULL )
265 {
266 str_size += strlen(detail->thread_name_str);
267 }
268 if ( detail->extra_info_str != NULL )
269 {
270 str_size += strlen(detail->extra_info_str);
271 }
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 {
278 tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->display_str );
279 }
280 if ( detail->thread_name_str != NULL )
281 {
282 if ( tmp_str_ptr != tmp_str )
283 {
284 tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
285 }
286 tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->thread_name_str );
287 }
288 if ( detail->extra_info_str != NULL )
289 {
290 if ( tmp_str_ptr != tmp_str )
291 {
292 tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
293 }
294 tmp_str_ptr += sprintf( tmp_str_ptr, " : %s", detail->extra_info_str );
295 }
296
297 assert(strlen(tmp_str) ==
298 (size_t) (tmp_str_ptr - tmp_str));
299
300 char * hex_str = (char*) malloc( strlen(tmp_str)*2 +1 );
301 str_to_hex( hex_str, tmp_str );
302
303 gdb_put_packet(connection, hex_str, strlen(hex_str));
304 free(hex_str);
305 free(tmp_str);
306 return ERROR_OK;
307
308 }
309 gdb_put_packet(connection, "", 0);
310 return ERROR_OK;
311 }
312 else if (strstr(packet, "qSymbol"))
313 {
314 if (rtos_qsymbol(connection, packet, packet_size) == 1)
315 {
316 target->rtos_auto_detect = false;
317 target->rtos->type->create(target);
318 target->rtos->type->update_threads(target->rtos);
319 /* No more symbols needed */
320 gdb_put_packet(connection, "OK", 2);
321 }
322 return ERROR_OK;
323 }
324 else if (strstr(packet, "qfThreadInfo"))
325 {
326 int i;
327 if ( ( target->rtos != NULL ) && ( target->rtos->thread_count != 0 ) )
328 {
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 }
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 }
343 else
344 {
345 gdb_put_packet(connection, "", 0);
346 }
347
348 return ERROR_OK;
349 }
350 else if (strstr(packet, "qsThreadInfo"))
351 {
352 gdb_put_packet(connection, "l", 1);
353 return ERROR_OK;
354 }
355 else if (strstr(packet, "qAttached"))
356 {
357 gdb_put_packet(connection, "1", 1);
358 return ERROR_OK;
359 }
360 else if (strstr(packet, "qOffsets"))
361 {
362 char offsets[] = "Text=0;Data=0;Bss=0";
363 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
364 return ERROR_OK;
365 }
366 else if (strstr(packet, "qC"))
367 {
368 if( target->rtos!=NULL )
369 {
370 char buffer[15];
371 int size;
372 size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread);
373 gdb_put_packet(connection, buffer, size);
374 }
375 else
376 {
377 gdb_put_packet(connection, "QC0", 3);
378 }
379 return ERROR_OK;
380 }
381 else if ( packet[0] == 'T' ) // Is thread alive?
382 {
383 threadid_t threadid;
384 int found = -1;
385 sscanf(packet, "T%" SCNx64, &threadid);
386 if ((target->rtos != NULL) && (target->rtos->thread_details
387 != NULL)) {
388 int thread_num;
389 for (thread_num = 0; thread_num
390 < target->rtos->thread_count; thread_num++) {
391 if (target->rtos->thread_details[thread_num].threadid
392 == threadid) {
393 if (target->rtos->thread_details[thread_num].exists) {
394 found = thread_num;
395 }
396 }
397 }
398 }
399 if (found != -1) {
400 gdb_put_packet(connection, "OK", 2); // thread alive
401 } else {
402 gdb_put_packet(connection, "E01", 3); // thread not found
403 }
404 return ERROR_OK;
405 }
406 else if ( packet[0] == 'H') // Set current thread ( 'c' for step and continue, 'g' for all other operations )
407 {
408 if ((packet[1] == 'g') && (target->rtos != NULL))
409 sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
410 gdb_put_packet(connection, "OK", 2);
411 return ERROR_OK;
412 }
413
414 return GDB_THREAD_PACKET_NOT_CONSUMED;
415 }
416
417 int rtos_get_gdb_reg_list(struct connection *connection)
418 {
419 struct target *target = get_target_from_connection(connection);
420 int64_t current_threadid = target->rtos->current_threadid;
421 if ((target->rtos != NULL) &&
422 (current_threadid != -1) &&
423 (current_threadid != 0) &&
424 ((current_threadid != target->rtos->current_thread) ||
425 (target->smp))) /* in smp several current thread are possible */
426 {
427 char * hex_reg_list;
428 target->rtos->type->get_thread_reg_list( target->rtos, current_threadid, &hex_reg_list );
429
430 if ( hex_reg_list != NULL )
431 {
432 gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
433 free(hex_reg_list);
434 return ERROR_OK;
435 }
436 }
437 return ERROR_FAIL;
438 }
439
440
441
442 int rtos_generic_stack_read( struct target * target, const struct rtos_register_stacking* stacking, int64_t stack_ptr, char ** hex_reg_list )
443 {
444 int list_size = 0;
445 char * tmp_str_ptr;
446 int64_t new_stack_ptr;
447 int i;
448 int retval;
449
450 if ( stack_ptr == 0)
451 {
452 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
453 return -5;
454 }
455 // Read the stack
456 uint8_t * stack_data = (uint8_t*) malloc( stacking->stack_registers_size );
457 uint32_t address = stack_ptr;
458
459 if ( stacking->stack_growth_direction == 1 )
460 {
461 address -= stacking->stack_registers_size;
462 }
463 retval = target_read_buffer( target, address, stacking->stack_registers_size, stack_data);
464 if ( retval != ERROR_OK )
465 {
466 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
467 return retval;
468 }
469 /*
470 LOG_OUTPUT("Stack Data :");
471 for(i = 0; i < stacking->stack_registers_size; i++ )
472 {
473 LOG_OUTPUT("%02X",stack_data[i]);
474 }
475 LOG_OUTPUT("\r\n");
476 */
477 for( i = 0; i < stacking->num_output_registers; i++ )
478 {
479 list_size += stacking->register_offsets[i].width_bits/8;
480 }
481 *hex_reg_list = (char*)malloc( list_size*2 +1 );
482 tmp_str_ptr = *hex_reg_list;
483 new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size;
484 if (stacking->stack_alignment != 0) {
485 /* Align new stack pointer to x byte boundary */
486 new_stack_ptr =
487 (new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) +
488 ((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0);
489 }
490 for( i = 0; i < stacking->num_output_registers; i++ )
491 {
492 int j;
493 for ( j = 0; j < stacking->register_offsets[i].width_bits/8; j++ )
494 {
495 if ( stacking->register_offsets[i].offset == -1 )
496 {
497 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", 0 );
498 }
499 else if ( stacking->register_offsets[i].offset == -2 )
500 {
501 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", ((uint8_t*)&new_stack_ptr)[j] );
502 }
503 else
504 {
505 tmp_str_ptr += sprintf( tmp_str_ptr,"%02x", stack_data[ stacking->register_offsets[i].offset + j ] );
506 }
507 }
508 }
509 // LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list);
510 return ERROR_OK;
511 }
512
513 int rtos_try_next( struct target * target )
514 {
515 int x;
516
517 if ( target->rtos == NULL )
518 {
519 return -1;
520 }
521
522 for (x = 0 ; rtos_types[x] ; x++) {
523 if (target->rtos->type == rtos_types[x] ) {
524 /* found */
525 if ( rtos_types[x+1] != NULL )
526 {
527 target->rtos->type = rtos_types[x+1];
528 if ( target->rtos->symbols != NULL )
529 {
530 free( target->rtos->symbols );
531 }
532 return 1;
533 }
534 else
535 {
536 // No more rtos types
537 return 0;
538 }
539
540 }
541 }
542 return 0;
543
544 }
545
546 static void hex_to_str( char* dst, char * hex_src )
547 {
548 int src_pos = 0;
549 int dst_pos = 0;
550
551 while ( hex_src[src_pos] != '\x00' )
552 {
553 char hex_char = hex_src[src_pos];
554 char hex_digit_val = (hex_char>='a')?hex_char-'a'+10:(hex_char>='A')?hex_char-'A'+10:hex_char-'0';
555 if ( 0 == (src_pos & 0x01) )
556 {
557 dst[dst_pos] = hex_digit_val;
558 dst[dst_pos+1] = 0;
559 }
560 else
561 {
562 ((unsigned char*)dst)[dst_pos] <<= 4;
563 ((unsigned char*)dst)[dst_pos] += hex_digit_val;
564 dst_pos++;
565 }
566 src_pos++;
567 }
568
569 }
570
571 int str_to_hex(char *hex_dst, char *src)
572 {
573 char * posptr = hex_dst;
574 unsigned i;
575 for( i = 0; i < strlen(src); i++)
576 {
577 posptr += sprintf( posptr, "%02x", (unsigned char)src[i] );
578 }
579 return (posptr-hex_dst);
580 }
581
582
583 int rtos_update_threads( struct target* target )
584 {
585 if ((target->rtos != NULL) && (target->rtos->type != NULL))
586 {
587 target->rtos->type->update_threads(target->rtos);
588 }
589 return ERROR_OK;
590 }

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)