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

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)