1 /***************************************************************************
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. *
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. *
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 ***************************************************************************/
21 #include <helper/time_support.h>
22 #include <jtag/jtag.h>
23 #include "target/target.h"
24 #include "target/target_type.h"
26 #include "helper/log.h"
27 #include "helper/types.h"
28 #include "rtos_ecos_stackings.h"
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
[]);
36 struct ecos_thread_state
{
41 static const struct ecos_thread_state ecos_thread_states
[] = {
50 #define ECOS_NUM_STATES ARRAY_SIZE(ecos_thread_states)
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
;
63 static const struct ecos_params ecos_params_list
[] = {
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 */
76 enum ecos_symbol_values
{
77 ECOS_VAL_THREAD_LIST
= 0,
78 ECOS_VAL_CURRENT_THREAD_PTR
= 1
81 static const char * const ecos_symbol_list
[] = {
82 "Cyg_Thread::thread_list",
83 "Cyg_Scheduler_Base::current_thread",
87 const struct rtos_type ecos_rtos
= {
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
,
98 static int ecos_update_threads(struct rtos
*rtos
)
102 int thread_list_size
= 0;
103 const struct ecos_params
*param
;
108 if (!rtos
->rtos_specific_params
)
111 param
= (const struct ecos_params
*) rtos
->rtos_specific_params
;
113 if (!rtos
->symbols
) {
114 LOG_ERROR("No symbols for eCos");
118 if (rtos
->symbols
[ECOS_VAL_THREAD_LIST
].address
== 0) {
119 LOG_ERROR("Don't have the thread list head");
123 /* wipe out previous thread details if any */
124 rtos_free_threadlist(rtos
);
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
,
131 param
->pointer_width
,
132 (uint8_t *) &thread_index
);
133 uint32_t first_thread
= thread_index
;
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
)
142 } while (thread_index
!= first_thread
);
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
,
149 (uint8_t *)¤t_thread_addr
);
150 if (retval
!= ERROR_OK
)
152 rtos
->current_thread
= 0;
153 retval
= target_read_buffer(rtos
->target
,
154 current_thread_addr
+ param
->thread_uniqueid_offset
,
156 (uint8_t *)&rtos
->current_thread
);
157 if (retval
!= ERROR_OK
) {
158 LOG_ERROR("Could not read eCos current thread from target");
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
166 char tmp_str
[] = "Current Execution";
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
);
177 if (thread_list_size
== 0) {
178 rtos
->thread_count
= 1;
182 /* create space for new thread details */
183 rtos
->thread_details
= malloc(
184 sizeof(struct thread_detail
) * thread_list_size
);
187 /* loop over all threads */
188 thread_index
= first_thread
;
191 #define ECOS_THREAD_NAME_STR_SIZE (200)
192 char tmp_str
[ECOS_THREAD_NAME_STR_SIZE
];
194 uint32_t name_ptr
= 0;
195 uint32_t prev_thread_ptr
;
197 /* Save the thread pointer */
199 retval
= target_read_buffer(rtos
->target
,
200 thread_index
+ param
->thread_uniqueid_offset
,
202 (uint8_t *)&thread_id
);
203 if (retval
!= ERROR_OK
) {
204 LOG_ERROR("Could not read eCos thread id from target");
207 rtos
->thread_details
[tasks_found
].threadid
= thread_id
;
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");
219 /* Read the thread name */
221 target_read_buffer(rtos
->target
,
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");
229 tmp_str
[ECOS_THREAD_NAME_STR_SIZE
-1] = '\x00';
231 if (tmp_str
[0] == '\x00')
232 strcpy(tmp_str
, "No Name");
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
);
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
,
243 (uint8_t *)&thread_status
);
244 if (retval
!= ERROR_OK
) {
245 LOG_ERROR("Error reading thread state from eCos target");
249 for (i
= 0; (i
< ECOS_NUM_STATES
) && (ecos_thread_states
[i
].value
!= thread_status
); i
++) {
255 const char *state_desc
;
256 if (i
< ECOS_NUM_STATES
)
257 state_desc
= ecos_thread_states
[i
].desc
;
259 state_desc
= "Unknown state";
261 rtos
->thread_details
[tasks_found
].extra_info_str
= malloc(strlen(
263 sprintf(rtos
->thread_details
[tasks_found
].extra_info_str
, "State: %s", state_desc
);
265 rtos
->thread_details
[tasks_found
].exists
= true;
268 prev_thread_ptr
= thread_index
;
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");
280 } while (thread_index
!= first_thread
);
282 rtos
->thread_count
= tasks_found
;
286 static int ecos_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
287 struct rtos_reg
**reg_list
, int *num_regs
)
290 const struct ecos_params
*param
;
298 if (!rtos
->rtos_specific_params
)
301 param
= (const struct ecos_params
*) rtos
->rtos_specific_params
;
303 /* Find the thread with that thread id */
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
);
311 retval
= target_read_buffer(rtos
->target
,
312 thread_index
+ param
->thread_uniqueid_offset
,
315 if (retval
!= ERROR_OK
) {
316 LOG_ERROR("Error reading unique id from eCos thread");
320 if (id
== thread_id
) {
324 target_read_buffer(rtos
->target
,
325 thread_index
+ param
->thread_next_offset
,
326 param
->pointer_width
,
327 (uint8_t *) &thread_index
);
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");
342 return rtos_generic_stack_read(rtos
->target
,
343 param
->stacking_info
,
352 static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
355 *symbol_list
= calloc(
356 ARRAY_SIZE(ecos_symbol_list
), sizeof(struct symbol_table_elem
));
358 for (i
= 0; i
< ARRAY_SIZE(ecos_symbol_list
); i
++)
359 (*symbol_list
)[i
].symbol_name
= ecos_symbol_list
[i
];
364 static bool ecos_detect_rtos(struct target
*target
)
366 if ((target
->rtos
->symbols
) &&
367 (target
->rtos
->symbols
[ECOS_VAL_THREAD_LIST
].address
!= 0)) {
368 /* looks like eCos */
374 static int ecos_create(struct target
*target
)
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
;
384 LOG_ERROR("Could not find target in eCos compatibility list");