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

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)