openocd: fix simple cases of NULL comparison
[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, see <http://www.gnu.org/licenses/>. *
15  ***************************************************************************/
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <helper/time_support.h>
22 #include <jtag/jtag.h>
23 #include "target/target.h"
24 #include "target/target_type.h"
25 #include "rtos.h"
26 #include "helper/log.h"
27 #include "helper/types.h"
28 #include "rtos_ecos_stackings.h"
29
30 static bool ecos_detect_rtos(struct target *target);
31 static int ecos_create(struct target *target);
32 static int ecos_update_threads(struct rtos *rtos);
33 static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
34 static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
35
36 struct ecos_thread_state {
37         int value;
38         const char *desc;
39 };
40
41 static const struct ecos_thread_state ecos_thread_states[] = {
42         { 0, "Ready" },
43         { 1, "Sleeping" },
44         { 2, "Countsleep" },
45         { 4, "Suspended" },
46         { 8, "Creating" },
47         { 16, "Exited" }
48 };
49
50 #define ECOS_NUM_STATES ARRAY_SIZE(ecos_thread_states)
51
52 struct ecos_params {
53         const char *target_name;
54         unsigned char pointer_width;
55         unsigned char thread_stack_offset;
56         unsigned char thread_name_offset;
57         unsigned char thread_state_offset;
58         unsigned char thread_next_offset;
59         unsigned char thread_uniqueid_offset;
60         const struct rtos_register_stacking *stacking_info;
61 };
62
63 static const struct ecos_params ecos_params_list[] = {
64         {
65         "cortex_m",                     /* target_name */
66         4,                                              /* pointer_width; */
67         0x0c,                                   /* thread_stack_offset; */
68         0x9c,                                   /* thread_name_offset; */
69         0x3c,                                   /* thread_state_offset; */
70         0xa0,                                   /* thread_next_offset */
71         0x4c,                                   /* thread_uniqueid_offset */
72         &rtos_ecos_cortex_m3_stacking   /* stacking_info */
73         }
74 };
75
76 enum ecos_symbol_values {
77         ECOS_VAL_THREAD_LIST = 0,
78         ECOS_VAL_CURRENT_THREAD_PTR = 1
79 };
80
81 static const char * const ecos_symbol_list[] = {
82         "Cyg_Thread::thread_list",
83         "Cyg_Scheduler_Base::current_thread",
84         NULL
85 };
86
87 const struct rtos_type ecos_rtos = {
88         .name = "eCos",
89
90         .detect_rtos = ecos_detect_rtos,
91         .create = ecos_create,
92         .update_threads = ecos_update_threads,
93         .get_thread_reg_list = ecos_get_thread_reg_list,
94         .get_symbol_list_to_lookup = ecos_get_symbol_list_to_lookup,
95
96 };
97
98 static int ecos_update_threads(struct rtos *rtos)
99 {
100         int retval;
101         int tasks_found = 0;
102         int thread_list_size = 0;
103         const struct ecos_params *param;
104
105         if (!rtos)
106                 return -1;
107
108         if (!rtos->rtos_specific_params)
109                 return -3;
110
111         param = (const struct ecos_params *) rtos->rtos_specific_params;
112
113         if (!rtos->symbols) {
114                 LOG_ERROR("No symbols for eCos");
115                 return -4;
116         }
117
118         if (rtos->symbols[ECOS_VAL_THREAD_LIST].address == 0) {
119                 LOG_ERROR("Don't have the thread list head");
120                 return -2;
121         }
122
123         /* wipe out previous thread details if any */
124         rtos_free_threadlist(rtos);
125
126         /* determine the number of current threads */
127         uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
128         uint32_t thread_index;
129         target_read_buffer(rtos->target,
130                 thread_list_head,
131                 param->pointer_width,
132                 (uint8_t *) &thread_index);
133         uint32_t first_thread = thread_index;
134         do {
135                 thread_list_size++;
136                 retval = target_read_buffer(rtos->target,
137                                 thread_index + param->thread_next_offset,
138                                 param->pointer_width,
139                                 (uint8_t *) &thread_index);
140                 if (retval != ERROR_OK)
141                         return retval;
142         } while (thread_index != first_thread);
143
144         /* read the current thread id */
145         uint32_t current_thread_addr;
146         retval = target_read_buffer(rtos->target,
147                         rtos->symbols[ECOS_VAL_CURRENT_THREAD_PTR].address,
148                         4,
149                         (uint8_t *)&current_thread_addr);
150         if (retval != ERROR_OK)
151                 return retval;
152         rtos->current_thread = 0;
153         retval = target_read_buffer(rtos->target,
154                         current_thread_addr + param->thread_uniqueid_offset,
155                         2,
156                         (uint8_t *)&rtos->current_thread);
157         if (retval != ERROR_OK) {
158                 LOG_ERROR("Could not read eCos current thread from target");
159                 return retval;
160         }
161
162         if ((thread_list_size  == 0) || (rtos->current_thread == 0)) {
163                 /* Either : No RTOS threads - there is always at least the current execution though */
164                 /* OR     : No current thread - all threads suspended - show the current execution
165                  * of idling */
166                 char tmp_str[] = "Current Execution";
167                 thread_list_size++;
168                 tasks_found++;
169                 rtos->thread_details = malloc(
170                                 sizeof(struct thread_detail) * thread_list_size);
171                 rtos->thread_details->threadid = 1;
172                 rtos->thread_details->exists = true;
173                 rtos->thread_details->extra_info_str = NULL;
174                 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
175                 strcpy(rtos->thread_details->thread_name_str, tmp_str);
176
177                 if (thread_list_size == 0) {
178                         rtos->thread_count = 1;
179                         return ERROR_OK;
180                 }
181         } else {
182                 /* create space for new thread details */
183                 rtos->thread_details = malloc(
184                                 sizeof(struct thread_detail) * thread_list_size);
185         }
186
187         /* loop over all threads */
188         thread_index = first_thread;
189         do {
190
191                 #define ECOS_THREAD_NAME_STR_SIZE (200)
192                 char tmp_str[ECOS_THREAD_NAME_STR_SIZE];
193                 unsigned int i = 0;
194                 uint32_t name_ptr = 0;
195                 uint32_t prev_thread_ptr;
196
197                 /* Save the thread pointer */
198                 uint16_t thread_id;
199                 retval = target_read_buffer(rtos->target,
200                                 thread_index + param->thread_uniqueid_offset,
201                                 2,
202                                 (uint8_t *)&thread_id);
203                 if (retval != ERROR_OK) {
204                         LOG_ERROR("Could not read eCos thread id from target");
205                         return retval;
206                 }
207                 rtos->thread_details[tasks_found].threadid = thread_id;
208
209                 /* read the name pointer */
210                 retval = target_read_buffer(rtos->target,
211                                 thread_index + param->thread_name_offset,
212                                 param->pointer_width,
213                                 (uint8_t *)&name_ptr);
214                 if (retval != ERROR_OK) {
215                         LOG_ERROR("Could not read eCos thread name pointer from target");
216                         return retval;
217                 }
218
219                 /* Read the thread name */
220                 retval =
221                         target_read_buffer(rtos->target,
222                                 name_ptr,
223                                 ECOS_THREAD_NAME_STR_SIZE,
224                                 (uint8_t *)&tmp_str);
225                 if (retval != ERROR_OK) {
226                         LOG_ERROR("Error reading thread name from eCos target");
227                         return retval;
228                 }
229                 tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00';
230
231                 if (tmp_str[0] == '\x00')
232                         strcpy(tmp_str, "No Name");
233
234                 rtos->thread_details[tasks_found].thread_name_str =
235                         malloc(strlen(tmp_str)+1);
236                 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
237
238                 /* Read the thread status */
239                 int64_t thread_status = 0;
240                 retval = target_read_buffer(rtos->target,
241                                 thread_index + param->thread_state_offset,
242                                 4,
243                                 (uint8_t *)&thread_status);
244                 if (retval != ERROR_OK) {
245                         LOG_ERROR("Error reading thread state from eCos target");
246                         return retval;
247                 }
248
249                 for (i = 0; (i < ECOS_NUM_STATES) && (ecos_thread_states[i].value != thread_status); i++) {
250                         /*
251                          * empty
252                          */
253                 }
254
255                 const char *state_desc;
256                 if  (i < ECOS_NUM_STATES)
257                         state_desc = ecos_thread_states[i].desc;
258                 else
259                         state_desc = "Unknown state";
260
261                 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
262                                         state_desc)+8);
263                 sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
264
265                 rtos->thread_details[tasks_found].exists = true;
266
267                 tasks_found++;
268                 prev_thread_ptr = thread_index;
269
270                 /* Get the location of the next thread structure. */
271                 thread_index = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
272                 retval = target_read_buffer(rtos->target,
273                                 prev_thread_ptr + param->thread_next_offset,
274                                 param->pointer_width,
275                                 (uint8_t *) &thread_index);
276                 if (retval != ERROR_OK) {
277                         LOG_ERROR("Error reading next thread pointer in eCos thread list");
278                         return retval;
279                 }
280         } while (thread_index != first_thread);
281
282         rtos->thread_count = tasks_found;
283         return 0;
284 }
285
286 static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
287                 struct rtos_reg **reg_list, int *num_regs)
288 {
289         int retval;
290         const struct ecos_params *param;
291
292         if (!rtos)
293                 return -1;
294
295         if (thread_id == 0)
296                 return -2;
297
298         if (!rtos->rtos_specific_params)
299                 return -3;
300
301         param = (const struct ecos_params *) rtos->rtos_specific_params;
302
303         /* Find the thread with that thread id */
304         uint16_t id = 0;
305         uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
306         uint32_t thread_index;
307         target_read_buffer(rtos->target, thread_list_head, param->pointer_width,
308                         (uint8_t *)&thread_index);
309         bool done = false;
310         while (!done) {
311                 retval = target_read_buffer(rtos->target,
312                                 thread_index + param->thread_uniqueid_offset,
313                                 2,
314                                 (uint8_t *)&id);
315                 if (retval != ERROR_OK) {
316                         LOG_ERROR("Error reading unique id from eCos thread");
317                         return retval;
318                 }
319
320                 if (id == thread_id) {
321                         done = true;
322                         break;
323                 }
324                 target_read_buffer(rtos->target,
325                         thread_index + param->thread_next_offset,
326                         param->pointer_width,
327                         (uint8_t *) &thread_index);
328         }
329
330         if (done) {
331                 /* Read the stack pointer */
332                 int64_t stack_ptr = 0;
333                 retval = target_read_buffer(rtos->target,
334                                 thread_index + param->thread_stack_offset,
335                                 param->pointer_width,
336                                 (uint8_t *)&stack_ptr);
337                 if (retval != ERROR_OK) {
338                         LOG_ERROR("Error reading stack frame from eCos thread");
339                         return retval;
340                 }
341
342                 return rtos_generic_stack_read(rtos->target,
343                         param->stacking_info,
344                         stack_ptr,
345                         reg_list,
346                         num_regs);
347         }
348
349         return -1;
350 }
351
352 static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
353 {
354         unsigned int i;
355         *symbol_list = calloc(
356                         ARRAY_SIZE(ecos_symbol_list), sizeof(struct symbol_table_elem));
357
358         for (i = 0; i < ARRAY_SIZE(ecos_symbol_list); i++)
359                 (*symbol_list)[i].symbol_name = ecos_symbol_list[i];
360
361         return 0;
362 }
363
364 static bool ecos_detect_rtos(struct target *target)
365 {
366         if ((target->rtos->symbols != NULL) &&
367                         (target->rtos->symbols[ECOS_VAL_THREAD_LIST].address != 0)) {
368                 /* looks like eCos */
369                 return true;
370         }
371         return false;
372 }
373
374 static int ecos_create(struct target *target)
375 {
376         for (unsigned int i = 0; i < ARRAY_SIZE(ecos_params_list); i++)
377                 if (strcmp(ecos_params_list[i].target_name, target->type->name) == 0) {
378                         target->rtos->rtos_specific_params = (void *)&ecos_params_list[i];
379                         target->rtos->current_thread = 0;
380                         target->rtos->thread_details = NULL;
381                         return 0;
382                 }
383
384         LOG_ERROR("Could not find target in eCos compatibility list");
385         return -1;
386 }