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

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)