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