rtos: constify symbol names and lists
[fw/openocd] / src / rtos / eCos.c
1 /***************************************************************************
2  *                                                                         *
3  *   This program is free software; you can redistribute it and/or modify  *
4  *   it under the terms of the GNU General Public License as published by  *
5  *   the Free Software Foundation; either version 2 of the License, or     *
6  *   (at your option) any later version.                                   *
7  *                                                                         *
8  *   This program is distributed in the hope that it will be useful,       *
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
11  *   GNU General Public License for more details.                          *
12  *                                                                         *
13  *   You should have received a copy of the GNU General Public License     *
14  *   along with this program; if not, write to the                         *
15  *   Free Software Foundation, Inc.,                                       *
16  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
17  ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <helper/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
27 #include "rtos.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "rtos_ecos_stackings.h"
31
32 static int eCos_detect_rtos(struct target *target);
33 static int eCos_create(struct target *target);
34 static int eCos_update_threads(struct rtos *rtos);
35 static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
36 static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
37
38 struct eCos_thread_state {
39         int value;
40         const char *desc;
41 };
42
43 static const struct eCos_thread_state eCos_thread_states[] = {
44         { 0, "Ready" },
45         { 1, "Sleeping" },
46         { 2, "Countsleep" },
47         { 4, "Suspended" },
48         { 8, "Creating" },
49         { 16, "Exited" }
50 };
51
52 #define ECOS_NUM_STATES (sizeof(eCos_thread_states)/sizeof(struct eCos_thread_state))
53
54 struct eCos_params {
55         const char *target_name;
56         unsigned char pointer_width;
57         unsigned char thread_stack_offset;
58         unsigned char thread_name_offset;
59         unsigned char thread_state_offset;
60         unsigned char thread_next_offset;
61         unsigned char thread_uniqueid_offset;
62         const struct rtos_register_stacking *stacking_info;
63 };
64
65 static const struct eCos_params eCos_params_list[] = {
66         {
67         "cortex_m",                     /* target_name */
68         4,                                              /* pointer_width; */
69         0x0c,                                   /* thread_stack_offset; */
70         0x9c,                                   /* thread_name_offset; */
71         0x3c,                                   /* thread_state_offset; */
72         0xa0,                                   /* thread_next_offset */
73         0x4c,                                   /* thread_uniqueid_offset */
74         &rtos_eCos_Cortex_M3_stacking   /* stacking_info */
75         }
76 };
77
78 #define ECOS_NUM_PARAMS ((int)(sizeof(eCos_params_list)/sizeof(struct eCos_params)))
79
80 enum eCos_symbol_values {
81         eCos_VAL_thread_list = 0,
82         eCos_VAL_current_thread_ptr = 1
83 };
84
85 static const char * const eCos_symbol_list[] = {
86         "Cyg_Thread::thread_list",
87         "Cyg_Scheduler_Base::current_thread",
88         NULL
89 };
90
91 const struct rtos_type eCos_rtos = {
92         .name = "eCos",
93
94         .detect_rtos = eCos_detect_rtos,
95         .create = eCos_create,
96         .update_threads = eCos_update_threads,
97         .get_thread_reg_list = eCos_get_thread_reg_list,
98         .get_symbol_list_to_lookup = eCos_get_symbol_list_to_lookup,
99
100 };
101
102 static int eCos_update_threads(struct rtos *rtos)
103 {
104         int retval;
105         int tasks_found = 0;
106         int thread_list_size = 0;
107         const struct eCos_params *param;
108
109         if (rtos == NULL)
110                 return -1;
111
112         if (rtos->rtos_specific_params == NULL)
113                 return -3;
114
115         param = (const struct eCos_params *) rtos->rtos_specific_params;
116
117         if (rtos->symbols == NULL) {
118                 LOG_ERROR("No symbols for eCos");
119                 return -4;
120         }
121
122         if (rtos->symbols[eCos_VAL_thread_list].address == 0) {
123                 LOG_ERROR("Don't have the thread list head");
124                 return -2;
125         }
126
127         /* wipe out previous thread details if any */
128         rtos_free_threadlist(rtos);
129
130         /* determine the number of current threads */
131         uint32_t thread_list_head = rtos->symbols[eCos_VAL_thread_list].address;
132         uint32_t thread_index;
133         target_read_buffer(rtos->target,
134                 thread_list_head,
135                 param->pointer_width,
136                 (uint8_t *) &thread_index);
137         uint32_t first_thread = thread_index;
138         do {
139                 thread_list_size++;
140                 retval = target_read_buffer(rtos->target,
141                                 thread_index + param->thread_next_offset,
142                                 param->pointer_width,
143                                 (uint8_t *) &thread_index);
144                 if (retval != ERROR_OK)
145                         return retval;
146         } while (thread_index != first_thread);
147
148         /* read the current thread id */
149         uint32_t current_thread_addr;
150         retval = target_read_buffer(rtos->target,
151                         rtos->symbols[eCos_VAL_current_thread_ptr].address,
152                         4,
153                         (uint8_t *)&current_thread_addr);
154         if (retval != ERROR_OK)
155                 return retval;
156         rtos->current_thread = 0;
157         retval = target_read_buffer(rtos->target,
158                         current_thread_addr + param->thread_uniqueid_offset,
159                         2,
160                         (uint8_t *)&rtos->current_thread);
161         if (retval != ERROR_OK) {
162                 LOG_ERROR("Could not read eCos current thread from target");
163                 return retval;
164         }
165
166         if ((thread_list_size  == 0) || (rtos->current_thread == 0)) {
167                 /* Either : No RTOS threads - there is always at least the current execution though */
168                 /* OR     : No current thread - all threads suspended - show the current execution
169                  * of idling */
170                 char tmp_str[] = "Current Execution";
171                 thread_list_size++;
172                 tasks_found++;
173                 rtos->thread_details = malloc(
174                                 sizeof(struct thread_detail) * thread_list_size);
175                 rtos->thread_details->threadid = 1;
176                 rtos->thread_details->exists = true;
177                 rtos->thread_details->display_str = NULL;
178                 rtos->thread_details->extra_info_str = NULL;
179                 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
180                 strcpy(rtos->thread_details->thread_name_str, tmp_str);
181
182                 if (thread_list_size == 0) {
183                         rtos->thread_count = 1;
184                         return ERROR_OK;
185                 }
186         } else {
187                 /* create space for new thread details */
188                 rtos->thread_details = malloc(
189                                 sizeof(struct thread_detail) * thread_list_size);
190         }
191
192         /* loop over all threads */
193         thread_index = first_thread;
194         do {
195
196                 #define ECOS_THREAD_NAME_STR_SIZE (200)
197                 char tmp_str[ECOS_THREAD_NAME_STR_SIZE];
198                 unsigned int i = 0;
199                 uint32_t name_ptr = 0;
200                 uint32_t prev_thread_ptr;
201
202                 /* Save the thread pointer */
203                 uint16_t thread_id;
204                 retval = target_read_buffer(rtos->target,
205                                 thread_index + param->thread_uniqueid_offset,
206                                 2,
207                                 (uint8_t *)&thread_id);
208                 if (retval != ERROR_OK) {
209                         LOG_ERROR("Could not read eCos thread id from target");
210                         return retval;
211                 }
212                 rtos->thread_details[tasks_found].threadid = thread_id;
213
214                 /* read the name pointer */
215                 retval = target_read_buffer(rtos->target,
216                                 thread_index + param->thread_name_offset,
217                                 param->pointer_width,
218                                 (uint8_t *)&name_ptr);
219                 if (retval != ERROR_OK) {
220                         LOG_ERROR("Could not read eCos thread name pointer from target");
221                         return retval;
222                 }
223
224                 /* Read the thread name */
225                 retval =
226                         target_read_buffer(rtos->target,
227                                 name_ptr,
228                                 ECOS_THREAD_NAME_STR_SIZE,
229                                 (uint8_t *)&tmp_str);
230                 if (retval != ERROR_OK) {
231                         LOG_ERROR("Error reading thread name from eCos target");
232                         return retval;
233                 }
234                 tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00';
235
236                 if (tmp_str[0] == '\x00')
237                         strcpy(tmp_str, "No Name");
238
239                 rtos->thread_details[tasks_found].thread_name_str =
240                         malloc(strlen(tmp_str)+1);
241                 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
242
243                 /* Read the thread status */
244                 int64_t thread_status = 0;
245                 retval = target_read_buffer(rtos->target,
246                                 thread_index + param->thread_state_offset,
247                                 4,
248                                 (uint8_t *)&thread_status);
249                 if (retval != ERROR_OK) {
250                         LOG_ERROR("Error reading thread state from eCos target");
251                         return retval;
252                 }
253
254                 for (i = 0; (i < ECOS_NUM_STATES) && (eCos_thread_states[i].value != thread_status); i++) {
255                         /*
256                          * empty
257                          */
258                 }
259
260                 const char *state_desc;
261                 if  (i < ECOS_NUM_STATES)
262                         state_desc = eCos_thread_states[i].desc;
263                 else
264                         state_desc = "Unknown state";
265
266                 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
267                                         state_desc)+1);
268                 strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc);
269
270                 rtos->thread_details[tasks_found].exists = true;
271
272                 rtos->thread_details[tasks_found].display_str = NULL;
273
274                 tasks_found++;
275                 prev_thread_ptr = thread_index;
276
277                 /* Get the location of the next thread structure. */
278                 thread_index = rtos->symbols[eCos_VAL_thread_list].address;
279                 retval = target_read_buffer(rtos->target,
280                                 prev_thread_ptr + param->thread_next_offset,
281                                 param->pointer_width,
282                                 (uint8_t *) &thread_index);
283                 if (retval != ERROR_OK) {
284                         LOG_ERROR("Error reading next thread pointer in eCos thread list");
285                         return retval;
286                 }
287         } while (thread_index != first_thread);
288
289         rtos->thread_count = tasks_found;
290         return 0;
291 }
292
293 static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
294 {
295         int retval;
296         const struct eCos_params *param;
297
298         *hex_reg_list = NULL;
299
300         if (rtos == NULL)
301                 return -1;
302
303         if (thread_id == 0)
304                 return -2;
305
306         if (rtos->rtos_specific_params == NULL)
307                 return -3;
308
309         param = (const struct eCos_params *) rtos->rtos_specific_params;
310
311         /* Find the thread with that thread id */
312         uint16_t id = 0;
313         uint32_t thread_list_head = rtos->symbols[eCos_VAL_thread_list].address;
314         uint32_t thread_index;
315         target_read_buffer(rtos->target, thread_list_head, param->pointer_width,
316                         (uint8_t *)&thread_index);
317         bool done = false;
318         while (!done) {
319                 retval = target_read_buffer(rtos->target,
320                                 thread_index + param->thread_uniqueid_offset,
321                                 2,
322                                 (uint8_t *)&id);
323                 if (retval != ERROR_OK) {
324                         LOG_ERROR("Error reading unique id from eCos thread");
325                         return retval;
326                 }
327
328                 if (id == thread_id) {
329                         done = true;
330                         break;
331                 }
332                 target_read_buffer(rtos->target,
333                         thread_index + param->thread_next_offset,
334                         param->pointer_width,
335                         (uint8_t *) &thread_index);
336         }
337
338         if (done) {
339                 /* Read the stack pointer */
340                 int64_t stack_ptr = 0;
341                 retval = target_read_buffer(rtos->target,
342                                 thread_index + param->thread_stack_offset,
343                                 param->pointer_width,
344                                 (uint8_t *)&stack_ptr);
345                 if (retval != ERROR_OK) {
346                         LOG_ERROR("Error reading stack frame from eCos thread");
347                         return retval;
348                 }
349
350                 return rtos_generic_stack_read(rtos->target,
351                         param->stacking_info,
352                         stack_ptr,
353                         hex_reg_list);
354         }
355
356         return -1;
357 }
358
359 static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
360 {
361         unsigned int i;
362         *symbol_list = malloc(
363                         sizeof(symbol_table_elem_t) * ARRAY_SIZE(eCos_symbol_list));
364
365         for (i = 0; i < ARRAY_SIZE(eCos_symbol_list); i++)
366                 (*symbol_list)[i].symbol_name = eCos_symbol_list[i];
367
368         return 0;
369 }
370
371 static int eCos_detect_rtos(struct target *target)
372 {
373         if ((target->rtos->symbols != NULL) &&
374                         (target->rtos->symbols[eCos_VAL_thread_list].address != 0)) {
375                 /* looks like eCos */
376                 return 1;
377         }
378         return 0;
379 }
380
381 static int eCos_create(struct target *target)
382 {
383         int i = 0;
384         while ((i < ECOS_NUM_PARAMS) &&
385                 (0 != strcmp(eCos_params_list[i].target_name, target->type->name))) {
386                 i++;
387         }
388         if (i >= ECOS_NUM_PARAMS) {
389                 LOG_ERROR("Could not find target in eCos compatibility list");
390                 return -1;
391         }
392
393         target->rtos->rtos_specific_params = (void *) &eCos_params_list[i];
394         target->rtos->current_thread = 0;
395         target->rtos->thread_details = NULL;
396         return 0;
397 }