build: cleanup src/rtos directory
[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                                 return ERROR_OK;
173                         }
174
175                         target->rtos->symbols[symbol_num].address = value;
176
177                         next_symbol_num = symbol_num+1;
178                         free(hex_name_str);
179                         free(name_str);
180                 }
181
182                 int symbols_done = 0;
183                 if (target->rtos->symbols[next_symbol_num].symbol_name == NULL) {
184                         if ((target->rtos_auto_detect == false) ||
185                                         (1 == target->rtos->type->detect_rtos(target))) {
186                                 /* Found correct RTOS or not autodetecting */
187                                 if (target->rtos_auto_detect == true)
188                                         LOG_OUTPUT("Auto-detected RTOS: %s\r\n",
189                                                 target->rtos->type->name);
190                                 symbols_done = 1;
191                         } else {
192                                 /* Auto detecting RTOS and currently not found */
193                                 if (1 != rtos_try_next(target))
194                                         /* No more RTOS's to try */
195                                         symbols_done = 1;
196                                 else {
197                                         next_symbol_num = 0;
198                                         target->rtos->type->get_symbol_list_to_lookup(
199                                                 &target->rtos->symbols);
200                                 }
201                         }
202                 }
203                 if (symbols_done == 1)
204                         return symbols_done;
205                 else {
206                         char *symname = target->rtos->symbols[next_symbol_num].symbol_name;
207                         char qsymstr[] = "qSymbol:";
208                         char *opstring = (char *)malloc(sizeof(qsymstr)+strlen(symname)*2+1);
209                         char *posptr = opstring;
210                         posptr += sprintf(posptr, "%s", qsymstr);
211                         str_to_hex(posptr, symname);
212                         gdb_put_packet(connection, opstring, strlen(opstring));
213                         free(opstring);
214                         return symbols_done;
215                 }
216         }
217         gdb_put_packet(connection, "OK", 2);
218         return -1;
219 }
220
221 int rtos_thread_packet(struct connection *connection, char *packet, int packet_size)
222 {
223         struct target *target = get_target_from_connection(connection);
224
225         if (strstr(packet, "qThreadExtraInfo,")) {
226                 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) &&
227                                 (target->rtos->thread_count != 0)) {
228                         threadid_t threadid = 0;
229                         int found = -1;
230                         sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
231
232                         if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
233                                 int thread_num;
234                                 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
235                                         if (target->rtos->thread_details[thread_num].threadid == threadid) {
236                                                 if (target->rtos->thread_details[thread_num].exists)
237                                                         found = thread_num;
238                                         }
239                                 }
240                         }
241                         if (found == -1) {
242                                 gdb_put_packet(connection, "E01", 3);   /* thread not found */
243                                 return ERROR_OK;
244                         }
245
246                         struct thread_detail *detail = &target->rtos->thread_details[found];
247
248                         int str_size = 0;
249                         if (detail->display_str != NULL)
250                                 str_size += strlen(detail->display_str);
251                         if (detail->thread_name_str != NULL)
252                                 str_size += strlen(detail->thread_name_str);
253                         if (detail->extra_info_str != NULL)
254                                 str_size += strlen(detail->extra_info_str);
255
256                         char *tmp_str = (char *) malloc(str_size + 7);
257                         char *tmp_str_ptr = tmp_str;
258
259                         if (detail->display_str != NULL)
260                                 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->display_str);
261                         if (detail->thread_name_str != NULL) {
262                                 if (tmp_str_ptr != tmp_str)
263                                         tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
264                                 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str);
265                         }
266                         if (detail->extra_info_str != NULL) {
267                                 if (tmp_str_ptr != tmp_str)
268                                         tmp_str_ptr += sprintf(tmp_str_ptr, " : ");
269                                 tmp_str_ptr +=
270                                         sprintf(tmp_str_ptr, " : %s", detail->extra_info_str);
271                         }
272
273                         assert(strlen(tmp_str) ==
274                                 (size_t) (tmp_str_ptr - tmp_str));
275
276                         char *hex_str = (char *) malloc(strlen(tmp_str)*2 + 1);
277                         str_to_hex(hex_str, tmp_str);
278
279                         gdb_put_packet(connection, hex_str, strlen(hex_str));
280                         free(hex_str);
281                         free(tmp_str);
282                         return ERROR_OK;
283
284                 }
285                 gdb_put_packet(connection, "", 0);
286                 return ERROR_OK;
287         } else if (strstr(packet, "qSymbol")) {
288                 if (rtos_qsymbol(connection, packet, packet_size) == 1) {
289                         target->rtos_auto_detect = false;
290                         target->rtos->type->create(target);
291                         target->rtos->type->update_threads(target->rtos);
292                         /* No more symbols needed */
293                         gdb_put_packet(connection, "OK", 2);
294                 }
295                 return ERROR_OK;
296         } else if (strstr(packet, "qfThreadInfo")) {
297                 int i;
298                 if ((target->rtos != NULL) && (target->rtos->thread_count != 0)) {
299
300                         char *out_str = (char *) malloc(17 * target->rtos->thread_count + 5);
301                         char *tmp_str = out_str;
302                         tmp_str += sprintf(tmp_str, "m");
303                         for (i = 0; i < target->rtos->thread_count; i++) {
304                                 if (i != 0)
305                                         tmp_str += sprintf(tmp_str, ",");
306                                 tmp_str += sprintf(tmp_str, "%016" PRIx64,
307                                                 target->rtos->thread_details[i].threadid);
308                         }
309                         tmp_str[0] = 0;
310                         gdb_put_packet(connection, out_str, strlen(out_str));
311                 } else
312                         gdb_put_packet(connection, "", 0);
313
314                 return ERROR_OK;
315         } else if (strstr(packet, "qsThreadInfo")) {
316                 gdb_put_packet(connection, "l", 1);
317                 return ERROR_OK;
318         } else if (strstr(packet, "qAttached")) {
319                 gdb_put_packet(connection, "1", 1);
320                 return ERROR_OK;
321         } else if (strstr(packet, "qOffsets")) {
322                 char offsets[] = "Text=0;Data=0;Bss=0";
323                 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
324                 return ERROR_OK;
325         } else if (strstr(packet, "qC")) {
326                 if (target->rtos != NULL) {
327                         char buffer[15];
328                         int size;
329                         size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread);
330                         gdb_put_packet(connection, buffer, size);
331                 } else
332                         gdb_put_packet(connection, "QC0", 3);
333                 return ERROR_OK;
334         } else if (packet[0] == 'T') {  /* Is thread alive? */
335                 threadid_t threadid;
336                 int found = -1;
337                 sscanf(packet, "T%" SCNx64, &threadid);
338                 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) {
339                         int thread_num;
340                         for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
341                                 if (target->rtos->thread_details[thread_num].threadid == threadid) {
342                                         if (target->rtos->thread_details[thread_num].exists)
343                                                 found = thread_num;
344                                 }
345                         }
346                 }
347                 if (found != -1)
348                         gdb_put_packet(connection, "OK", 2);    /* thread alive */
349                 else
350                         gdb_put_packet(connection, "E01", 3);   /* thread not found */
351                 return ERROR_OK;
352         } else if (packet[0] == 'H') {  /* Set current thread ( 'c' for step and continue, 'g' for
353                                          * all other operations ) */
354                 if ((packet[1] == 'g') && (target->rtos != NULL))
355                         sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
356                 gdb_put_packet(connection, "OK", 2);
357                 return ERROR_OK;
358         }
359
360         return GDB_THREAD_PACKET_NOT_CONSUMED;
361 }
362
363 int rtos_get_gdb_reg_list(struct connection *connection)
364 {
365         struct target *target = get_target_from_connection(connection);
366         int64_t current_threadid = target->rtos->current_threadid;
367         if ((target->rtos != NULL) && (current_threadid != -1) &&
368                         (current_threadid != 0) &&
369                         ((current_threadid != target->rtos->current_thread) ||
370                         (target->smp))) {       /* in smp several current thread are possible */
371                 char *hex_reg_list;
372                 target->rtos->type->get_thread_reg_list(target->rtos,
373                         current_threadid,
374                         &hex_reg_list);
375
376                 if (hex_reg_list != NULL) {
377                         gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
378                         free(hex_reg_list);
379                         return ERROR_OK;
380                 }
381         }
382         return ERROR_FAIL;
383 }
384
385 int rtos_generic_stack_read(struct target *target,
386         const struct rtos_register_stacking *stacking,
387         int64_t stack_ptr,
388         char **hex_reg_list)
389 {
390         int list_size = 0;
391         char *tmp_str_ptr;
392         int64_t new_stack_ptr;
393         int i;
394         int retval;
395
396         if (stack_ptr == 0) {
397                 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
398                 return -5;
399         }
400         /* Read the stack */
401         uint8_t *stack_data = (uint8_t *) malloc(stacking->stack_registers_size);
402         uint32_t address = stack_ptr;
403
404         if (stacking->stack_growth_direction == 1)
405                 address -= stacking->stack_registers_size;
406         retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
407         if (retval != ERROR_OK) {
408                 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
409                 return retval;
410         }
411 #if 0
412                 LOG_OUTPUT("Stack Data :");
413                 for (i = 0; i < stacking->stack_registers_size; i++)
414                         LOG_OUTPUT("%02X", stack_data[i]);
415                 LOG_OUTPUT("\r\n");
416 #endif
417         for (i = 0; i < stacking->num_output_registers; i++)
418                 list_size += stacking->register_offsets[i].width_bits/8;
419         *hex_reg_list = (char *)malloc(list_size*2 + 1);
420         tmp_str_ptr = *hex_reg_list;
421         new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
422                 stacking->stack_registers_size;
423         if (stacking->stack_alignment != 0) {
424                 /* Align new stack pointer to x byte boundary */
425                 new_stack_ptr =
426                         (new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) +
427                         ((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0);
428         }
429         for (i = 0; i < stacking->num_output_registers; i++) {
430                 int j;
431                 for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) {
432                         if (stacking->register_offsets[i].offset == -1)
433                                 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0);
434                         else if (stacking->register_offsets[i].offset == -2)
435                                 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
436                                                 ((uint8_t *)&new_stack_ptr)[j]);
437                         else
438                                 tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
439                                                 stack_data[stacking->register_offsets[i].offset + j]);
440                 }
441         }
442 /*      LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
443         return ERROR_OK;
444 }
445
446 int rtos_try_next(struct target *target)
447 {
448         int x;
449
450         if (target->rtos == NULL)
451                 return -1;
452
453         for (x = 0; rtos_types[x]; x++) {
454                 if (target->rtos->type == rtos_types[x]) {
455                         /* found */
456                         if (rtos_types[x+1] != NULL) {
457                                 target->rtos->type = rtos_types[x+1];
458                                 if (target->rtos->symbols != NULL)
459                                         free(target->rtos->symbols);
460                                 return 1;
461                         } else {
462                                 /* No more rtos types */
463                                 return 0;
464                         }
465
466                 }
467         }
468         return 0;
469
470 }
471
472 static void hex_to_str(char *dst, char *hex_src)
473 {
474         int src_pos = 0;
475         int dst_pos = 0;
476
477         while (hex_src[src_pos] != '\x00') {
478                 char hex_char = hex_src[src_pos];
479                 char hex_digit_val =
480                         (hex_char >=
481                          'a') ? hex_char-'a'+
482                         10 : (hex_char >= 'A') ? hex_char-'A'+10 : hex_char-'0';
483                 if (0 == (src_pos & 0x01)) {
484                         dst[dst_pos] = hex_digit_val;
485                         dst[dst_pos+1] = 0;
486                 } else {
487                         ((unsigned char *)dst)[dst_pos] <<= 4;
488                         ((unsigned char *)dst)[dst_pos] += hex_digit_val;
489                         dst_pos++;
490                 }
491                 src_pos++;
492         }
493
494 }
495
496 int str_to_hex(char *hex_dst, char *src)
497 {
498         char *posptr = hex_dst;
499         unsigned i;
500         for (i = 0; i < strlen(src); i++)
501                 posptr += sprintf(posptr, "%02x", (unsigned char)src[i]);
502         return posptr - hex_dst;
503 }
504
505 int rtos_update_threads(struct target *target)
506 {
507         if ((target->rtos != NULL) && (target->rtos->type != NULL))
508                 target->rtos->type->update_threads(target->rtos);
509         return ERROR_OK;
510 }