8591007c202b8e240c7247c04b77eebffdc08150
[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 static int64_t current_threadid = -1;
33
34 static void hex_to_str( char* dst, char * hex_src );
35 static int str_to_hex( char* hex_dst, char* src );
36
37
38 /* RTOSs */
39 extern struct rtos_type FreeRTOS_rtos;
40 extern struct rtos_type ThreadX_rtos;
41 extern struct rtos_type eCos_rtos;
42
43 static struct rtos_type *rtos_types[] =
44 {
45 &ThreadX_rtos,
46 &FreeRTOS_rtos,
47 &eCos_rtos,
48 NULL
49 };
50
51
52 int rtos_create(Jim_GetOptInfo *goi, struct target * target)
53 {
54 int x;
55 char *cp;
56
57 if (! goi->isconfigure) {
58 if (goi->argc != 0) {
59 if (goi->argc != 0) {
60 Jim_WrongNumArgs(goi->interp,
61 goi->argc, goi->argv,
62 "NO PARAMS");
63 return JIM_ERR;
64 }
65
66 Jim_SetResultString(goi->interp,
67 target_type_name(target), -1);
68 }
69 }
70
71 if (target->rtos) {
72 free((void *)(target->rtos));
73 }
74 // e = Jim_GetOpt_String(goi, &cp, NULL);
75 // target->rtos = strdup(cp);
76
77 Jim_GetOpt_String(goi, &cp, NULL);
78 /* now does target type exist */
79
80 if ( 0 == strcmp( cp, "auto") )
81 {
82 // auto detection of RTOS
83 target->rtos_auto_detect = true;
84 x = 0;
85 }
86 else
87 {
88
89 for (x = 0 ; rtos_types[x] ; x++) {
90 if (0 == strcmp(cp, rtos_types[x]->name)) {
91 /* found */
92 break;
93 }
94 }
95 if (rtos_types[x] == NULL) {
96 Jim_SetResultFormatted(goi->interp, "Unknown rtos type %s, try one of ", cp);
97 for (x = 0 ; rtos_types[x] ; x++) {
98 if (rtos_types[x + 1]) {
99 Jim_AppendStrings(goi->interp,
100 Jim_GetResult(goi->interp),
101 rtos_types[x]->name,
102 ", ", NULL);
103 } else {
104 Jim_AppendStrings(goi->interp,
105 Jim_GetResult(goi->interp),
106 " or ",
107 rtos_types[x]->name,NULL);
108 }
109 }
110 return JIM_ERR;
111 }
112 }
113 /* Create it */
114 target->rtos = calloc(1,sizeof(struct rtos));
115 target->rtos->type = rtos_types[x];
116 target->rtos->current_thread = 0;
117 target->rtos->symbols = NULL;
118 target->rtos->target = target;
119
120 if ( 0 != strcmp( cp, "auto") )
121 {
122 target->rtos->type->create( target );
123 }
124
125 return JIM_OK;
126 }
127
128
129
130
131 int gdb_thread_packet(struct connection *connection, char *packet, int packet_size)
132 {
133 struct target *target = get_target_from_connection(connection);
134
135 if (strstr(packet, "qP"))
136 {
137 #define TAG_THREADID 1 /* Echo the thread identifier */
138 #define TAG_EXISTS 2 /* Is this process defined enough to
139 fetch registers and its stack */
140 #define TAG_DISPLAY 4 /* A short thing maybe to put on a window */
141 #define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */
142 #define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about */
143
144 // TODO: need to scanf the mode variable (or it with the tags), and the threadid
145
146 unsigned long mode;
147 threadid_t threadid = 0;
148 struct thread_detail* detail;
149 sscanf(packet, "qP%8lx%16" SCNx64, &mode, &threadid);
150
151
152 int found = -1;
153
154 if ((target->rtos != NULL) && (target->rtos->thread_details
155 != NULL)) {
156 int thread_num;
157 for (thread_num = 0; thread_num
158 < target->rtos->thread_count; thread_num++) {
159 if (target->rtos->thread_details[thread_num].threadid
160 == threadid) {
161 if (target->rtos->thread_details[thread_num].exists) {
162 found = thread_num;
163 }
164 }
165 }
166 }
167 if (found == -1) {
168 gdb_put_packet(connection, "E01", 3); // thread not found
169 return ERROR_OK;
170 }
171
172 detail = &target->rtos->thread_details[found];
173
174 if ( detail->display_str != NULL )
175 {
176 mode &= TAG_DISPLAY;
177 }
178 if ( detail->thread_name_str != NULL )
179 {
180 mode &= TAG_THREADNAME;
181 }
182 if ( detail->extra_info_str != NULL )
183 {
184 mode &= TAG_MOREDISPLAY;
185 }
186
187
188 mode &= TAG_THREADID | TAG_EXISTS;
189
190 char thread_str[1000];
191
192 sprintf(thread_str, "%08lx", mode);
193 sprintf(thread_str, "%016" PRIx64, threadid);
194
195
196 if (mode & TAG_THREADID) {
197 sprintf(thread_str, "%08" PRIx32 "10%016" PRIx64, TAG_THREADID, threadid);
198 }
199 if (mode & TAG_EXISTS) {
200 sprintf(thread_str, "%08" PRIx32 "08%08" PRIx32, TAG_EXISTS, (detail->exists==true)?1:0);
201 }
202 if (mode & TAG_DISPLAY) {
203 sprintf(thread_str, "%08" PRIx32 "%02x%s", TAG_DISPLAY, (unsigned char)strlen(detail->display_str), detail->display_str );
204 }
205 if (mode & TAG_MOREDISPLAY) {
206 sprintf(thread_str, "%08" PRIx32 "%02x%s", TAG_MOREDISPLAY, (unsigned char)strlen(detail->extra_info_str), detail->extra_info_str );
207 }
208 if (mode & TAG_THREADNAME) {
209 sprintf(thread_str, "%08" PRIx32 "%02x%s", TAG_THREADNAME, (unsigned char)strlen(detail->thread_name_str), detail->thread_name_str );
210 }
211
212 //gdb_put_packet(connection, tmpstr, sizeof(tmpstr)-1);
213 gdb_put_packet(connection, thread_str, strlen(thread_str));
214
215 // gdb_put_packet(connection, "", 0);
216 // gdb_put_packet(connection, "OK", 2); // all threads alive
217 return ERROR_OK;
218 }
219 else if (strstr(packet, "qThreadExtraInfo,"))
220 {
221 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0))
222 {
223 threadid_t threadid = 0;
224 int found = -1;
225 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid );
226
227 if ((target->rtos != NULL) && (target->rtos->thread_details
228 != NULL)) {
229 int thread_num;
230 for (thread_num = 0; thread_num
231 < target->rtos->thread_count; thread_num++) {
232 if (target->rtos->thread_details[thread_num].threadid
233 == threadid) {
234 if (target->rtos->thread_details[thread_num].exists) {
235 found = thread_num;
236 }
237 }
238 }
239 }
240 if (found == -1) {
241 gdb_put_packet(connection, "E01", 3); // thread not found
242 return ERROR_OK;
243 }
244
245 struct thread_detail* detail = &target->rtos->thread_details[found];
246
247 int str_size = 0;
248 if ( detail->display_str != NULL )
249 {
250 str_size += strlen(detail->display_str);
251 }
252 if ( detail->thread_name_str != NULL )
253 {
254 str_size += strlen(detail->thread_name_str);
255 }
256 if ( detail->extra_info_str != NULL )
257 {
258 str_size += strlen(detail->extra_info_str);
259 }
260
261 char * tmp_str = (char*) malloc( str_size + 7 );
262 char* tmp_str_ptr = tmp_str;
263
264 if ( detail->display_str != NULL )
265 {
266 tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->display_str );
267 }
268 if ( detail->thread_name_str != NULL )
269 {
270 if ( tmp_str_ptr != tmp_str )
271 {
272 tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
273 }
274 tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->thread_name_str );
275 }
276 if ( detail->extra_info_str != NULL )
277 {
278 if ( tmp_str_ptr != tmp_str )
279 {
280 tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
281 }
282 tmp_str_ptr += sprintf( tmp_str_ptr, " : %s", detail->extra_info_str );
283 }
284
285 char * hex_str = (char*) malloc( strlen(tmp_str)*2 +1 );
286 str_to_hex( hex_str, tmp_str );
287
288 gdb_put_packet(connection, hex_str, strlen(hex_str));
289 free(hex_str);
290 free(tmp_str);
291 return ERROR_OK;
292
293 }
294 gdb_put_packet(connection, "", 0);
295 return ERROR_OK;
296 }
297 else if (strstr(packet, "qSymbol"))
298 {
299 if ( target->rtos != NULL )
300 {
301 int next_symbol_num = -1;
302 if (target->rtos->symbols == NULL)
303 {
304 target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols );
305 }
306 if (0 == strcmp( "qSymbol::", packet ) )
307 {
308 // first query -
309 next_symbol_num = 0;
310 }
311 else
312 {
313 int64_t value = 0;
314 char * hex_name_str = malloc( strlen(packet));
315 char * name_str;
316 int symbol_num;
317
318 char* found = strstr( packet, "qSymbol::" );
319 if (0 == found )
320 {
321 sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str);
322 }
323 else
324 {
325 // No value returned by GDB - symbol was not found
326 sscanf(packet, "qSymbol::%s", hex_name_str);
327 }
328 name_str = (char*) malloc( 1+ strlen(hex_name_str) / 2 );
329
330 hex_to_str( name_str, hex_name_str );
331
332
333 symbol_num = 0;
334 while ( ( target->rtos->symbols[ symbol_num ].symbol_name != NULL ) && ( 0 != strcmp( target->rtos->symbols[ symbol_num ].symbol_name, name_str ) ) )
335 {
336 symbol_num++;
337 }
338
339
340 if ( target->rtos->symbols[ symbol_num ].symbol_name == NULL )
341 {
342 LOG_OUTPUT("ERROR: unknown symbol\r\n");
343 gdb_put_packet(connection, "OK", 2);
344 return ERROR_OK;
345 }
346
347 target->rtos->symbols[ symbol_num ].address = value;
348
349 next_symbol_num = symbol_num+1;
350 free( hex_name_str );
351 free( name_str );
352
353 }
354
355 int symbols_done = 0;
356 if ( target->rtos->symbols[ next_symbol_num ].symbol_name == NULL )
357 {
358 if ( ( target->rtos_auto_detect == false ) ||
359 ( 1 == target->rtos->type->detect_rtos( target ) ) )
360 {
361 // Found correct RTOS or not autodetecting
362 if ( target->rtos_auto_detect == true )
363 {
364 LOG_OUTPUT( "Auto-detected RTOS: %s\r\n",target->rtos->type->name );
365 }
366 symbols_done = 1;
367 }
368 else
369 {
370 // Auto detecting RTOS and currently not found
371 if( 1 != rtos_try_next( target ) )
372 {
373 // No more RTOS's to try
374 symbols_done = 1;
375 }
376 else
377 {
378 next_symbol_num = 0;
379 target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols );
380 }
381
382 }
383 }
384
385
386 if ( symbols_done == 1 )
387 {
388 target->rtos_auto_detect = false;
389 target->rtos->type->create( target );
390 target->rtos->type->update_threads(target->rtos);
391 // No more symbols needed
392 gdb_put_packet(connection, "OK", 2);
393 return ERROR_OK;
394
395 }
396 else
397 {
398 char* symname = target->rtos->symbols[ next_symbol_num ].symbol_name;
399 char qsymstr[] = "qSymbol:";
400 char * opstring = (char*)malloc(sizeof(qsymstr)+strlen(symname)*2+1);
401 char * posptr = opstring;
402 posptr += sprintf( posptr, "%s", qsymstr );
403 str_to_hex( posptr, symname );
404 gdb_put_packet(connection, opstring, strlen(opstring));
405 free(opstring);
406 return ERROR_OK;
407 }
408
409 }
410 gdb_put_packet(connection, "OK", 2);
411 return ERROR_OK;
412 }
413 else if (strstr(packet, "qfThreadInfo"))
414 {
415 int i;
416 if ( ( target->rtos != NULL ) && ( target->rtos->thread_count != 0 ) )
417 {
418
419 char* out_str = (char*) malloc(17 * target->rtos->thread_count + 5);
420 char* tmp_str = out_str;
421 tmp_str += sprintf(tmp_str, "m");
422 for (i = 0; i < target->rtos->thread_count; i++) {
423 if (i != 0) {
424 tmp_str += sprintf(tmp_str, ",");
425 }
426 tmp_str += sprintf(tmp_str, "%016" PRIx64,
427 target->rtos->thread_details[i].threadid);
428 }
429 tmp_str[0] = 0;
430 gdb_put_packet(connection, out_str, strlen(out_str));
431 }
432 else
433 {
434 gdb_put_packet(connection, "", 0);
435 }
436
437 return ERROR_OK;
438 }
439 else if (strstr(packet, "qsThreadInfo"))
440 {
441 gdb_put_packet(connection, "l", 1);
442 return ERROR_OK;
443 }
444 else if (strstr(packet, "qAttached"))
445 {
446 gdb_put_packet(connection, "1", 1);
447 return ERROR_OK;
448 }
449 else if (strstr(packet, "qOffsets"))
450 {
451 char offsets[] = "Text=0;Data=0;Bss=0";
452 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
453 return ERROR_OK;
454 }
455 else if (strstr(packet, "qC"))
456 {
457 if( target->rtos!=NULL )
458 {
459 char buffer[15];
460 int size;
461 size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread);
462 gdb_put_packet(connection, buffer, size);
463 }
464 else
465 {
466 gdb_put_packet(connection, "QC0", 3);
467 }
468 return ERROR_OK;
469 }
470 else if ( packet[0] == 'T' ) // Is thread alive?
471 {
472 threadid_t threadid;
473 int found = -1;
474 sscanf(packet, "T%" SCNx64, &threadid);
475 if ((target->rtos != NULL) && (target->rtos->thread_details
476 != NULL)) {
477 int thread_num;
478 for (thread_num = 0; thread_num
479 < target->rtos->thread_count; thread_num++) {
480 if (target->rtos->thread_details[thread_num].threadid
481 == threadid) {
482 if (target->rtos->thread_details[thread_num].exists) {
483 found = thread_num;
484 }
485 }
486 }
487 }
488 if (found != -1) {
489 gdb_put_packet(connection, "OK", 2); // thread alive
490 } else {
491 gdb_put_packet(connection, "E01", 3); // thread not found
492 }
493 return ERROR_OK;
494 }
495 else if ( packet[0] == 'H') // Set current thread ( 'c' for step and continue, 'g' for all other operations )
496 {
497 if (packet[1] == 'g')
498 {
499 sscanf(packet, "Hg%16" SCNx64, &current_threadid);
500 }
501 gdb_put_packet(connection, "OK", 2);
502 return ERROR_OK;
503 }
504
505 return GDB_THREAD_PACKET_NOT_CONSUMED;
506 }
507
508 int rtos_get_gdb_reg_list(struct connection *connection, struct reg **reg_list[], int *reg_list_size)
509 {
510 struct target *target = get_target_from_connection(connection);
511
512 if ( ( target->rtos != NULL ) &&
513 ( current_threadid != -1 ) &&
514 ( current_threadid != 0 ) &&
515 ( current_threadid != target->rtos->current_thread ) )
516 {
517 char * hex_reg_list;
518 target->rtos->type->get_thread_reg_list( target->rtos, current_threadid, &hex_reg_list );
519
520 if ( hex_reg_list != NULL )
521 {
522 gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
523 free(hex_reg_list);
524 return ERROR_OK;
525 }
526 }
527 return ERROR_FAIL;
528 }
529
530
531
532 int rtos_generic_stack_read( struct target * target, const struct rtos_register_stacking* stacking, int64_t stack_ptr, char ** hex_reg_list )
533 {
534 int list_size = 0;
535 char * tmp_str_ptr;
536 int64_t new_stack_ptr;
537 int i;
538 int retval;
539
540 if ( stack_ptr == 0)
541 {
542 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
543 return -5;
544 }
545 // Read the stack
546 uint8_t * stack_data = (uint8_t*) malloc( stacking->stack_registers_size );
547 uint32_t address = stack_ptr;
548
549 if ( stacking->stack_growth_direction == 1 )
550 {
551 address -= stacking->stack_registers_size;
552 }
553 retval = target_read_buffer( target, address, stacking->stack_registers_size, stack_data);
554 if ( retval != ERROR_OK )
555 {
556 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
557 return retval;
558 }
559 /*
560 LOG_OUTPUT("Stack Data :");
561 for(i = 0; i < stacking->stack_registers_size; i++ )
562 {
563 LOG_OUTPUT("%02X",stack_data[i]);
564 }
565 LOG_OUTPUT("\r\n");
566 */
567 for( i = 0; i < stacking->num_output_registers; i++ )
568 {
569 list_size += stacking->register_offsets[i].width_bits/8;
570 }
571 *hex_reg_list = (char*)malloc( list_size*2 +1 );
572 tmp_str_ptr = *hex_reg_list;
573 new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size;
574 for( i = 0; i < stacking->num_output_registers; i++ )
575 {
576 int j;
577 for ( j = 0; j < stacking->register_offsets[i].width_bits/8; j++ )
578 {
579 if ( stacking->register_offsets[i].offset == -1 )
580 {
581 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", 0 );
582 }
583 else if ( stacking->register_offsets[i].offset == -2 )
584 {
585 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", ((uint8_t*)&new_stack_ptr)[j] );
586 }
587 else
588 {
589 tmp_str_ptr += sprintf( tmp_str_ptr,"%02x", stack_data[ stacking->register_offsets[i].offset + j ] );
590 }
591 }
592 }
593 // LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list);
594 return ERROR_OK;
595 }
596
597 int rtos_try_next( struct target * target )
598 {
599 int x;
600
601 if ( target->rtos == NULL )
602 {
603 return -1;
604 }
605
606 for (x = 0 ; rtos_types[x] ; x++) {
607 if (target->rtos->type == rtos_types[x] ) {
608 /* found */
609 if ( rtos_types[x+1] != NULL )
610 {
611 target->rtos->type = rtos_types[x+1];
612 if ( target->rtos->symbols != NULL )
613 {
614 free( target->rtos->symbols );
615 }
616 return 1;
617 }
618 else
619 {
620 // No more rtos types
621 return 0;
622 }
623
624 }
625 }
626 return 0;
627
628 }
629
630 static void hex_to_str( char* dst, char * hex_src )
631 {
632 int src_pos = 0;
633 int dst_pos = 0;
634
635 while ( hex_src[src_pos] != '\x00' )
636 {
637 char hex_char = hex_src[src_pos];
638 char hex_digit_val = (hex_char>='a')?hex_char-'a'+10:(hex_char>='A')?hex_char-'A'+10:hex_char-'0';
639 if ( 0 == (src_pos & 0x01) )
640 {
641 dst[dst_pos] = hex_digit_val;
642 dst[dst_pos+1] = 0;
643 }
644 else
645 {
646 ((unsigned char*)dst)[dst_pos] <<= 4;
647 ((unsigned char*)dst)[dst_pos] += hex_digit_val;
648 dst_pos++;
649 }
650 src_pos++;
651 }
652
653 }
654
655 static int str_to_hex( char* hex_dst, char* src )
656 {
657 char * posptr = hex_dst;
658 unsigned i;
659 for( i = 0; i < strlen(src); i++)
660 {
661 posptr += sprintf( posptr, "%02x", (unsigned char)src[i] );
662 }
663 return (posptr-hex_dst);
664 }
665
666
667 int rtos_update_threads( struct target* target )
668 {
669 if ((target->rtos != NULL) && (target->rtos->type != NULL))
670 {
671 target->rtos->type->update_threads(target->rtos);
672 }
673 return ERROR_OK;
674 }

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)