9eed08e0e1787ab05b1f890bb2de62ddc54a226c
[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 gdb_put_packet(connection, "QC0", 3);
457 return ERROR_OK;
458 }
459 else if ( packet[0] == 'T' ) // Is thread alive?
460 {
461 threadid_t threadid;
462 int found = -1;
463 sscanf(packet, "T%" SCNx64, &threadid);
464 if ((target->rtos != NULL) && (target->rtos->thread_details
465 != NULL)) {
466 int thread_num;
467 for (thread_num = 0; thread_num
468 < target->rtos->thread_count; thread_num++) {
469 if (target->rtos->thread_details[thread_num].threadid
470 == threadid) {
471 if (target->rtos->thread_details[thread_num].exists) {
472 found = thread_num;
473 }
474 }
475 }
476 }
477 if (found != -1) {
478 gdb_put_packet(connection, "OK", 2); // thread alive
479 } else {
480 gdb_put_packet(connection, "E01", 3); // thread not found
481 }
482 }
483 else if ( packet[0] == 'H') // Set current thread ( 'c' for step and continue, 'g' for all other operations )
484 {
485 if (packet[1] == 'g')
486 {
487 sscanf(packet, "Hg%16" SCNx64, &current_threadid);
488 }
489 gdb_put_packet(connection, "OK", 2);
490 }
491
492 return GDB_THREAD_PACKET_NOT_CONSUMED;
493 }
494
495 int rtos_get_gdb_reg_list(struct connection *connection, struct target *target, struct reg **reg_list[], int *reg_list_size)
496 {
497 if ( ( target->rtos != NULL ) &&
498 ( current_threadid != -1 ) &&
499 ( current_threadid != 0 ) &&
500 ( current_threadid != target->rtos->current_thread ) )
501 {
502 char * hex_reg_list;
503 target->rtos->type->get_thread_reg_list( target->rtos, current_threadid, &hex_reg_list );
504
505 if ( hex_reg_list != NULL )
506 {
507 gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
508 free(hex_reg_list);
509 return ERROR_OK;
510 }
511 }
512 return ERROR_FAIL;
513 }
514
515
516
517 int rtos_generic_stack_read( struct target * target, const struct rtos_register_stacking* stacking, int64_t stack_ptr, char ** hex_reg_list )
518 {
519 int list_size = 0;
520 char * tmp_str_ptr;
521 int64_t new_stack_ptr;
522 int i;
523 int retval;
524
525 if ( stack_ptr == 0)
526 {
527 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
528 return -5;
529 }
530 // Read the stack
531 uint8_t * stack_data = (uint8_t*) malloc( stacking->stack_registers_size );
532 uint32_t address = stack_ptr;
533
534 if ( stacking->stack_growth_direction == 1 )
535 {
536 address -= stacking->stack_registers_size;
537 }
538 retval = target_read_buffer( target, address, stacking->stack_registers_size, stack_data);
539 if ( retval != ERROR_OK )
540 {
541 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
542 return retval;
543 }
544 /*
545 LOG_OUTPUT("Stack Data :");
546 for(i = 0; i < stacking->stack_registers_size; i++ )
547 {
548 LOG_OUTPUT("%02X",stack_data[i]);
549 }
550 LOG_OUTPUT("\r\n");
551 */
552 for( i = 0; i < stacking->num_output_registers; i++ )
553 {
554 list_size += stacking->register_offsets[i].width_bits/8;
555 }
556 *hex_reg_list = (char*)malloc( list_size*2 +1 );
557 tmp_str_ptr = *hex_reg_list;
558 new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size;
559 for( i = 0; i < stacking->num_output_registers; i++ )
560 {
561 int j;
562 for ( j = 0; j < stacking->register_offsets[i].width_bits/8; j++ )
563 {
564 if ( stacking->register_offsets[i].offset == -1 )
565 {
566 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", 0 );
567 }
568 else if ( stacking->register_offsets[i].offset == -2 )
569 {
570 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", ((uint8_t*)&new_stack_ptr)[j] );
571 }
572 else
573 {
574 tmp_str_ptr += sprintf( tmp_str_ptr,"%02x", stack_data[ stacking->register_offsets[i].offset + j ] );
575 }
576 }
577 }
578 // LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list);
579 return ERROR_OK;
580 }
581
582 int rtos_try_next( struct target * target )
583 {
584 int x;
585
586 if ( target->rtos == NULL )
587 {
588 return -1;
589 }
590
591 for (x = 0 ; rtos_types[x] ; x++) {
592 if (target->rtos->type == rtos_types[x] ) {
593 /* found */
594 if ( rtos_types[x+1] != NULL )
595 {
596 target->rtos->type = rtos_types[x+1];
597 if ( target->rtos->symbols != NULL )
598 {
599 free( target->rtos->symbols );
600 }
601 return 1;
602 }
603 else
604 {
605 // No more rtos types
606 return 0;
607 }
608
609 }
610 }
611 return 0;
612
613 }
614
615 static void hex_to_str( char* dst, char * hex_src )
616 {
617 int src_pos = 0;
618 int dst_pos = 0;
619
620 while ( hex_src[src_pos] != '\x00' )
621 {
622 char hex_char = hex_src[src_pos];
623 char hex_digit_val = (hex_char>='a')?hex_char-'a'+10:(hex_char>='A')?hex_char-'A'+10:hex_char-'0';
624 if ( 0 == (src_pos & 0x01) )
625 {
626 dst[dst_pos] = hex_digit_val;
627 dst[dst_pos+1] = 0;
628 }
629 else
630 {
631 ((unsigned char*)dst)[dst_pos] <<= 4;
632 ((unsigned char*)dst)[dst_pos] += hex_digit_val;
633 dst_pos++;
634 }
635 src_pos++;
636 }
637
638 }
639
640 static int str_to_hex( char* hex_dst, char* src )
641 {
642 char * posptr = hex_dst;
643 unsigned i;
644 for( i = 0; i < strlen(src); i++)
645 {
646 posptr += sprintf( posptr, "%02x", (unsigned char)src[i] );
647 }
648 return (posptr-hex_dst);
649 }
650
651
652 int rtos_update_threads( struct target* target )
653 {
654 if ((target->rtos != NULL) && (target->rtos->type != NULL))
655 {
656 target->rtos->type->update_threads(target->rtos);
657 }
658 return ERROR_OK;
659 }

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)