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

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)