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

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)