jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / rtos / eCos.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 ***************************************************************************/
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <helper/time_support.h>
11 #include <jtag/jtag.h>
12 #include "target/target.h"
13 #include "target/target_type.h"
14 #include "target/armv7m.h"
15 #include "rtos.h"
16 #include "helper/log.h"
17 #include "helper/types.h"
18 #include "helper/bits.h"
19 #include "rtos_standard_stackings.h"
20 #include "rtos_ecos_stackings.h"
21 #include "server/gdb_server.h"
22
23 /* Unfortunately for the moment we are limited to returning the hardwired
24 * register count (ARMV7M_NUM_CORE_REGS for Cortex-M) since the openocd RTOS
25 * support does not yet support accessing all per-thread "stacked"
26 * registers. e.g. For Cortex-M under eCos we have a per-thread BASEPRI, and for
27 * all eCos targets we may have per-thread VFP/FPU register state.
28 *
29 * So, for the moment, we continue to use the hardwired limit for the depth of
30 * the returned register description vector. The current openocd
31 * rtos_standard_stackings.c just provides the main core regs for the Cortex_M*
32 * targets regardless of whether FPU is present/enabled.
33 *
34 * However, this code is written with the expectation that we may eventually be
35 * able to provide more register information ("m-system" and "vfp" for example)
36 * and also with the expectation of supporting different register sets being
37 * returned depending on the per-thread Cortex-M eCos contex_m for
38 * example. Hence the fact that the eCos_stack_layout_*() functions below allow
39 * for the stack context descriptor vector to be returned by those calls
40 * allowing for eventual support where this code will potentially cache
41 * different sets of register descriptors for the different shapes of contexts
42 * in a *single* application/binary run-time.
43 *
44 * TODO: Extend openocd generic RTOS support to allow thread-specific system and
45 * FPU register state to be returned. */
46
47 struct ecos_params;
48
49 static bool ecos_detect_rtos(struct target *target);
50 static int ecos_create(struct target *target);
51 static int ecos_update_threads(struct rtos *rtos);
52 static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
53 static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
54 static int ecos_stack_layout_cortexm(struct rtos *rtos, struct ecos_params *param,
55 int64_t stack_ptr, const struct rtos_register_stacking **si);
56 static int ecos_stack_layout_arm(struct rtos *rtos, struct ecos_params *param,
57 int64_t stack_ptr, const struct rtos_register_stacking **si);
58
59 /* The current eCos thread IDentifier uses 0 as an unused (not a valid thread
60 * ID) value. Currently the unique_id field is 16-bits, but the eCos SMP support
61 * convention is that only 12-bits of the ID will be used. This
62 * ECOS_MAX_THREAD_COUNT manifest is provided to limit the potential for
63 * interpreting stale/inconsistent thread list state when the debug host scans
64 * the thread list before the target RTOS has completed its initialisation. This
65 * support will need to revisited when eCos is re-engineered to support more
66 * than 16 CPU SMP setups. */
67 #define ECOS_MAX_THREAD_COUNT (4095)
68
69 struct ecos_thread_state {
70 int value;
71 const char *desc;
72 };
73
74 /* The status is actually a logical-OR bitmask of states: */
75 enum ecos_thread_state_flags {
76 RUNNING = 0, /* explicit no-bits-set value */
77 SLEEPING = BIT(0),
78 COUNTSLEEP = BIT(1),
79 SUSPENDED = BIT(2),
80 CREATING = BIT(3),
81 EXITED = BIT(4),
82 SLEEPSET = (SLEEPING | COUNTSLEEP)
83 };
84
85 /* Cyg_Thread:: reason codes for wake and sleep fields: */
86 static const struct ecos_thread_state ecos_thread_reasons[] = {
87 { 0, "NONE" }, /* normally indicates "not yet started" */
88 { 1, "WAIT" }, /* wait with no timeout */
89 { 2, "DELAY" }, /* simple time delay */
90 { 3, "TIMEOUT" }, /* wait with timeout *or* timeout expired */
91 { 4, "BREAK" }, /* forced break out of sleep */
92 { 5, "DESTRUCT" }, /* wait on object being destroyed */
93 { 6, "EXIT" }, /* forced termination */
94 { 7, "DONE" } /* wait/delay completed */
95 };
96
97 static const char * const target_cortex_m[] = {
98 "cortex_m",
99 "hla_target",
100 NULL
101 };
102
103 static const char * const target_arm[] = {
104 "cortex_a",
105 "arm7tdmi",
106 "arm720t",
107 "arm9tdmi",
108 "arm920t",
109 "arm926ejs",
110 "arm946e",
111 "arm966e",
112 "arm11",
113 NULL
114 };
115
116 /* Since individual eCos application configurations may have different thread
117 * object structure layouts depending on the actual build-time enabled features
118 * we provide support for applications built containing the relevant symbolic
119 * support to match the actual application binary being debugged, rather than
120 * relying on a set of default/fixed (and potentially incorrect)
121 * offsets. However, for backwards compatibility, we do *NOT* enforce the
122 * requirement for the common extra helper symbols to be present to allow the
123 * fallback to the simple fixed CM3 model to avoid affecting existing users of
124 * older eCos worlds. Similarly we need to provide support for per-thread
125 * register context offsets, as well as for per-application-configurations,
126 * since some targets can have different stacked state on a per-thread basis
127 * (e.g. "cortex_m"). This is why the stacking_info is now set at run-time
128 * rather than being fixed. */
129
130 struct ecos_params {
131 const char * const *target_names; /* NULL terminated list of targets */
132 int (*target_stack_layout)(struct rtos *rtos, struct ecos_params *param,
133 int64_t stack_ptr, const struct rtos_register_stacking **si);
134 bool flush_common;
135 unsigned char pointer_width;
136 unsigned char uid_width;
137 unsigned char state_width;
138 unsigned int thread_stack_offset;
139 unsigned int thread_name_offset;
140 unsigned int thread_state_offset;
141 unsigned int thread_next_offset;
142 unsigned int thread_uniqueid_offset;
143 const struct rtos_register_stacking *stacking_info;
144 };
145
146 /* As mentioned above we provide default offset values for the "cortex_m"
147 * targets for backwards compatibility with older eCos application builds and
148 * previous users of this RTOS specific support that do not have the
149 * configuration specific offsets provided in the symbol table. The support for
150 * other targets (e.g. "cortex_a") we do expect the application to provide the
151 * required symbolic information. We do not populate the stacking_info reference
152 * until we have had a chance to interrogate the symbol table. */
153
154 static struct ecos_params ecos_params_list[] = {
155 {
156 .target_names = target_cortex_m,
157 .pointer_width = 4,
158 .uid_width = 2,
159 .state_width = 4,
160 .thread_stack_offset = 0x0c,
161 .thread_name_offset = 0x9c,
162 .thread_state_offset = 0x3c,
163 .thread_next_offset = 0xa0,
164 .thread_uniqueid_offset = 0x4c,
165 .target_stack_layout = ecos_stack_layout_cortexm,
166 .stacking_info = NULL
167 },
168 {
169 .target_names = target_arm,
170 .pointer_width = 0,
171 .uid_width = 0,
172 .state_width = 0,
173 .thread_stack_offset = 0,
174 .thread_name_offset = 0,
175 .thread_state_offset = 0,
176 .thread_next_offset = 0,
177 .thread_uniqueid_offset = 0,
178 .target_stack_layout = ecos_stack_layout_arm,
179 .stacking_info = NULL
180 }
181 };
182
183 #define ECOS_NUM_PARAMS ARRAY_SIZE(ecos_params_list)
184
185 /* To eventually allow for more than just the ARMV7M_NUM_CORE_REGS to be
186 * returned by the Cortex-M support, and to avoid run-time lookups we manually
187 * maintain our own mapping for the supplied stack register vector entries. This
188 * enum needs to match the rtos_ecos_regoff_cortexm[] vector. Admittedly the
189 * initial indices just match the corresponding ARMV7M_R* definitions, but after
190 * the base registers the ARMV7M_* number space does not match the vector we
191 * wish to populate in this eCos support code. */
192 enum ecos_reglist_cortexm {
193 ECOS_REGLIST_R0 = 0,
194 ECOS_REGLIST_R1,
195 ECOS_REGLIST_R2,
196 ECOS_REGLIST_R3,
197 ECOS_REGLIST_R4,
198 ECOS_REGLIST_R5,
199 ECOS_REGLIST_R6,
200 ECOS_REGLIST_R7,
201 ECOS_REGLIST_R8,
202 ECOS_REGLIST_R9,
203 ECOS_REGLIST_R10,
204 ECOS_REGLIST_R11,
205 ECOS_REGLIST_R12,
206 ECOS_REGLIST_R13,
207 ECOS_REGLIST_R14,
208 ECOS_REGLIST_PC,
209 ECOS_REGLIST_XPSR, /* ARMV7M_NUM_CORE_REGS */
210 ECOS_REGLIST_BASEPRI,
211 ECOS_REGLIST_FPSCR, /* Following for FPU contexts */
212 ECOS_REGLIST_D0,
213 ECOS_REGLIST_D1,
214 ECOS_REGLIST_D2,
215 ECOS_REGLIST_D3,
216 ECOS_REGLIST_D4,
217 ECOS_REGLIST_D5,
218 ECOS_REGLIST_D6,
219 ECOS_REGLIST_D7,
220 ECOS_REGLIST_D8,
221 ECOS_REGLIST_D9,
222 ECOS_REGLIST_D10,
223 ECOS_REGLIST_D11,
224 ECOS_REGLIST_D12,
225 ECOS_REGLIST_D13,
226 ECOS_REGLIST_D14,
227 ECOS_REGLIST_D15
228 };
229
230 #define ECOS_CORTEXM_BASE_NUMREGS (ARMV7M_NUM_CORE_REGS)
231
232 /* NOTE: The offsets in this vector are overwritten by the architecture specific
233 * layout functions depending on the specific application configuration. The
234 * ordering of this vector MUST match eCos_reglist. */
235 static struct stack_register_offset rtos_ecos_regoff_cortexm[] = {
236 { ARMV7M_R0, -1, 32 }, /* r0 */
237 { ARMV7M_R1, -1, 32 }, /* r1 */
238 { ARMV7M_R2, -1, 32 }, /* r2 */
239 { ARMV7M_R3, -1, 32 }, /* r3 */
240 { ARMV7M_R4, -1, 32 }, /* r4 */
241 { ARMV7M_R5, -1, 32 }, /* r5 */
242 { ARMV7M_R6, -1, 32 }, /* r6 */
243 { ARMV7M_R7, -1, 32 }, /* r7 */
244 { ARMV7M_R8, -1, 32 }, /* r8 */
245 { ARMV7M_R9, -1, 32 }, /* r9 */
246 { ARMV7M_R10, -1, 32 }, /* r10 */
247 { ARMV7M_R11, -1, 32 }, /* r11 */
248 { ARMV7M_R12, -1, 32 }, /* r12 */
249 { ARMV7M_R13, -1, 32 }, /* sp */
250 { ARMV7M_R14, -1, 32 }, /* lr */
251 { ARMV7M_PC, -1, 32 }, /* pc */
252 { ARMV7M_XPSR, -1, 32 }, /* xPSR */
253 { ARMV7M_BASEPRI, -1, 32 }, /* BASEPRI */
254 { ARMV7M_FPSCR, -1, 32 }, /* FPSCR */
255 { ARMV7M_D0, -1, 64 }, /* D0 (S0/S1) */
256 { ARMV7M_D1, -1, 64 }, /* D1 (S2/S3) */
257 { ARMV7M_D2, -1, 64 }, /* D2 (S4/S5) */
258 { ARMV7M_D3, -1, 64 }, /* D3 (S6/S7) */
259 { ARMV7M_D4, -1, 64 }, /* D4 (S8/S9) */
260 { ARMV7M_D5, -1, 64 }, /* D5 (S10/S11) */
261 { ARMV7M_D6, -1, 64 }, /* D6 (S12/S13) */
262 { ARMV7M_D7, -1, 64 }, /* D7 (S14/S15) */
263 { ARMV7M_D8, -1, 64 }, /* D8 (S16/S17) */
264 { ARMV7M_D9, -1, 64 }, /* D9 (S18/S19) */
265 { ARMV7M_D10, -1, 64 }, /* D10 (S20/S21) */
266 { ARMV7M_D11, -1, 64 }, /* D11 (S22/S23) */
267 { ARMV7M_D12, -1, 64 }, /* D12 (S24/S25) */
268 { ARMV7M_D13, -1, 64 }, /* D13 (S26/S27) */
269 { ARMV7M_D14, -1, 64 }, /* D14 (S28/S29) */
270 { ARMV7M_D15, -1, 64 }, /* D15 (S30/S31) */
271 };
272
273 static struct stack_register_offset rtos_ecos_regoff_arm[] = {
274 { 0, -1, 32 }, /* r0 */
275 { 1, -1, 32 }, /* r1 */
276 { 2, -1, 32 }, /* r2 */
277 { 3, -1, 32 }, /* r3 */
278 { 4, -1, 32 }, /* r4 */
279 { 5, -1, 32 }, /* r5 */
280 { 6, -1, 32 }, /* r6 */
281 { 7, -1, 32 }, /* r7 */
282 { 8, -1, 32 }, /* r8 */
283 { 9, -1, 32 }, /* r9 */
284 { 10, -1, 32 }, /* r10 */
285 { 11, -1, 32 }, /* r11 (fp) */
286 { 12, -1, 32 }, /* r12 (ip) */
287 { 13, -1, 32 }, /* sp (r13) */
288 { 14, -1, 32 }, /* lr (r14) */
289 { 15, -1, 32 }, /* pc (r15) */
290 { 16, -1, 32 }, /* xPSR */
291 };
292
293 static struct rtos_register_stacking rtos_ecos_stacking = {
294 .stack_registers_size = 0,
295 .stack_growth_direction = -1,
296 .num_output_registers = 0,
297 .calculate_process_stack = NULL, /* stack_alignment */
298 .register_offsets = NULL
299 };
300
301 /* To avoid the run-time cost of matching explicit symbol names we push the
302 * lookup offsets to this *manually* maintained enumeration which must match the
303 * ecos_symbol_list[] order below. */
304 enum ecos_symbol_values {
305 ECOS_VAL_THREAD_LIST = 0,
306 ECOS_VAL_CURRENT_THREAD_PTR,
307 ECOS_VAL_COMMON_THREAD_NEXT_OFF,
308 ECOS_VAL_COMMON_THREAD_NEXT_SIZE,
309 ECOS_VAL_COMMON_THREAD_STATE_OFF,
310 ECOS_VAL_COMMON_THREAD_STATE_SIZE,
311 ECOS_VAL_COMMON_THREAD_SLEEP_OFF,
312 ECOS_VAL_COMMON_THREAD_SLEEP_SIZE,
313 ECOS_VAL_COMMON_THREAD_WAKE_OFF,
314 ECOS_VAL_COMMON_THREAD_WAKE_SIZE,
315 ECOS_VAL_COMMON_THREAD_ID_OFF,
316 ECOS_VAL_COMMON_THREAD_ID_SIZE,
317 ECOS_VAL_COMMON_THREAD_NAME_OFF,
318 ECOS_VAL_COMMON_THREAD_NAME_SIZE,
319 ECOS_VAL_COMMON_THREAD_PRI_OFF,
320 ECOS_VAL_COMMON_THREAD_PRI_SIZE,
321 ECOS_VAL_COMMON_THREAD_STACK_OFF,
322 ECOS_VAL_COMMON_THREAD_STACK_SIZE,
323 ECOS_VAL_CORTEXM_THREAD_SAVED,
324 ECOS_VAL_CORTEXM_CTX_THREAD_SIZE,
325 ECOS_VAL_CORTEXM_CTX_TYPE_OFF,
326 ECOS_VAL_CORTEXM_CTX_TYPE_SIZE,
327 ECOS_VAL_CORTEXM_CTX_BASEPRI_OFF,
328 ECOS_VAL_CORTEXM_CTX_BASEPRI_SIZE,
329 ECOS_VAL_CORTEXM_CTX_SP_OFF,
330 ECOS_VAL_CORTEXM_CTX_SP_SIZE,
331 ECOS_VAL_CORTEXM_CTX_REG_OFF,
332 ECOS_VAL_CORTEXM_CTX_REG_SIZE,
333 ECOS_VAL_CORTEXM_CTX_PC_OFF,
334 ECOS_VAL_CORTEXM_CTX_PC_SIZE,
335 ECOS_VAL_CORTEXM_VAL_EXCEPTION,
336 ECOS_VAL_CORTEXM_VAL_THREAD,
337 ECOS_VAL_CORTEXM_VAL_INTERRUPT,
338 ECOS_VAL_CORTEXM_VAL_FPU,
339 ECOS_VAL_CORTEXM_CTX_FPSCR_OFF,
340 ECOS_VAL_CORTEXM_CTX_FPSCR_SIZE,
341 ECOS_VAL_CORTEXM_CTX_S_OFF,
342 ECOS_VAL_CORTEXM_CTX_S_SIZE,
343 ECOS_VAL_ARM_REGSIZE,
344 ECOS_VAL_ARM_CTX_R0_OFF,
345 ECOS_VAL_ARM_CTX_R1_OFF,
346 ECOS_VAL_ARM_CTX_R2_OFF,
347 ECOS_VAL_ARM_CTX_R3_OFF,
348 ECOS_VAL_ARM_CTX_R4_OFF,
349 ECOS_VAL_ARM_CTX_R5_OFF,
350 ECOS_VAL_ARM_CTX_R6_OFF,
351 ECOS_VAL_ARM_CTX_R7_OFF,
352 ECOS_VAL_ARM_CTX_R8_OFF,
353 ECOS_VAL_ARM_CTX_R9_OFF,
354 ECOS_VAL_ARM_CTX_R10_OFF,
355 ECOS_VAL_ARM_CTX_FP_OFF,
356 ECOS_VAL_ARM_CTX_IP_OFF,
357 ECOS_VAL_ARM_CTX_SP_OFF,
358 ECOS_VAL_ARM_CTX_LR_OFF,
359 ECOS_VAL_ARM_CTX_PC_OFF,
360 ECOS_VAL_ARM_CTX_CPSR_OFF,
361 ECOS_VAL_ARM_FPUSIZE,
362 ECOS_VAL_ARM_CTX_FPSCR_OFF,
363 ECOS_VAL_ARM_SCOUNT,
364 ECOS_VAL_ARM_CTX_SVEC_OFF,
365 ECOS_VAL_ARM_VFPCOUNT,
366 ECOS_VAL_ARM_CTX_VFPVEC_OFF
367 };
368
369 struct symbols {
370 const char *name;
371 const char * const *target_names; /* non-NULL when for a specific architecture */
372 bool optional;
373 };
374
375 #define ECOSSYM(_n, _o, _t) { .name = _n, .optional = (_o), .target_names = _t }
376
377 /* Some of offset/size helper symbols are common to all eCos
378 * targets. Unfortunately, for historical reasons, some information is in
379 * architecture specific namespaces leading to some duplication and a larger
380 * vector below. */
381 static const struct symbols ecos_symbol_list[] = {
382 ECOSSYM("Cyg_Thread::thread_list", false, NULL),
383 ECOSSYM("Cyg_Scheduler_Base::current_thread", false, NULL),
384 /* Following symbols *are* required for generic application-specific
385 * configuration support, but we mark as optional for backwards
386 * compatibility with the previous fixed Cortex-M3 only RTOS plugin
387 * implementation. */
388 ECOSSYM("__ecospro_syminfo.off.cyg_thread.list_next", true, NULL),
389 ECOSSYM("__ecospro_syminfo.size.cyg_thread.list_next", true, NULL),
390 ECOSSYM("__ecospro_syminfo.off.cyg_thread.state", true, NULL),
391 ECOSSYM("__ecospro_syminfo.size.cyg_thread.state", true, NULL),
392 ECOSSYM("__ecospro_syminfo.off.cyg_thread.sleep_reason", true, NULL),
393 ECOSSYM("__ecospro_syminfo.size.cyg_thread.sleep_reason", true, NULL),
394 ECOSSYM("__ecospro_syminfo.off.cyg_thread.wake_reason", true, NULL),
395 ECOSSYM("__ecospro_syminfo.size.cyg_thread.wake_reason", true, NULL),
396 ECOSSYM("__ecospro_syminfo.off.cyg_thread.unique_id", true, NULL),
397 ECOSSYM("__ecospro_syminfo.size.cyg_thread.unique_id", true, NULL),
398 ECOSSYM("__ecospro_syminfo.off.cyg_thread.name", true, NULL),
399 ECOSSYM("__ecospro_syminfo.size.cyg_thread.name", true, NULL),
400 ECOSSYM("__ecospro_syminfo.off.cyg_thread.priority", true, NULL),
401 ECOSSYM("__ecospro_syminfo.size.cyg_thread.priority", true, NULL),
402 ECOSSYM("__ecospro_syminfo.off.cyg_thread.stack_ptr", true, NULL),
403 ECOSSYM("__ecospro_syminfo.size.cyg_thread.stack_ptr", true, NULL),
404 /* optional Cortex-M: */
405 ECOSSYM("__ecospro_syminfo.cortexm.thread.saved", true, target_cortex_m),
406 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.Thread", true, target_cortex_m),
407 ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.type", true, target_cortex_m),
408 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.type", true, target_cortex_m),
409 ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.basepri", true, target_cortex_m),
410 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.basepri", true, target_cortex_m),
411 ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.sp", true, target_cortex_m),
412 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.sp", true, target_cortex_m),
413 ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.r", true, target_cortex_m),
414 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.r", true, target_cortex_m),
415 ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.pc", true, target_cortex_m),
416 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.pc", true, target_cortex_m),
417 ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.EXCEPTION", true, target_cortex_m),
418 ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.THREAD", true, target_cortex_m),
419 ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.INTERRUPT", true, target_cortex_m),
420 /* optional Cortex-M with H/W FPU configured: */
421 ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.WITH_FPU", true, target_cortex_m),
422 ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.fpscr", true, target_cortex_m),
423 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.fpscr", true, target_cortex_m),
424 ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.s", true, target_cortex_m),
425 ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.s", true, target_cortex_m),
426 /* optional ARM: */
427 ECOSSYM("ARMREG_SIZE", true, target_arm),
428 ECOSSYM("armreg_r0", true, target_arm),
429 ECOSSYM("armreg_r1", true, target_arm),
430 ECOSSYM("armreg_r2", true, target_arm),
431 ECOSSYM("armreg_r3", true, target_arm),
432 ECOSSYM("armreg_r4", true, target_arm),
433 ECOSSYM("armreg_r5", true, target_arm),
434 ECOSSYM("armreg_r6", true, target_arm),
435 ECOSSYM("armreg_r7", true, target_arm),
436 ECOSSYM("armreg_r8", true, target_arm),
437 ECOSSYM("armreg_r9", true, target_arm),
438 ECOSSYM("armreg_r10", true, target_arm),
439 ECOSSYM("armreg_fp", true, target_arm),
440 ECOSSYM("armreg_ip", true, target_arm),
441 ECOSSYM("armreg_sp", true, target_arm),
442 ECOSSYM("armreg_lr", true, target_arm),
443 ECOSSYM("armreg_pc", true, target_arm),
444 ECOSSYM("armreg_cpsr", true, target_arm),
445 /* optional ARM FPU common: */
446 ECOSSYM("ARMREG_FPUCONTEXT_SIZE", true, target_arm),
447 ECOSSYM("armreg_fpscr", true, target_arm),
448 /* optional ARM FPU single-precision: */
449 ECOSSYM("ARMREG_S_COUNT", true, target_arm),
450 ECOSSYM("armreg_s_vec", true, target_arm),
451 /* optional ARM FPU double-precision: */
452 ECOSSYM("ARMREG_VFP_COUNT", true, target_arm),
453 ECOSSYM("armreg_vfp_vec", true, target_arm),
454 };
455
456 const struct rtos_type ecos_rtos = {
457 .name = "eCos",
458
459 .detect_rtos = ecos_detect_rtos,
460 .create = ecos_create,
461 .update_threads = ecos_update_threads,
462 .get_thread_reg_list = ecos_get_thread_reg_list,
463 .get_symbol_list_to_lookup = ecos_get_symbol_list_to_lookup,
464
465 };
466
467 static symbol_address_t ecos_value(struct rtos *rtos, unsigned int idx)
468 {
469 if (idx < ARRAY_SIZE(ecos_symbol_list))
470 return rtos->symbols[idx].address;
471
472 /* We do not terminate, just return 0 in this case. */
473 LOG_ERROR("eCos: Invalid symbol index %u", idx);
474 return 0;
475 }
476
477 #define XMLENTRY(_c, _s) { .xc = (_c), .rs = (_s), .rlen = (sizeof(_s) - 1) }
478
479 static const struct {
480 char xc;
481 const char *rs;
482 size_t rlen;
483 } xmlchars[] = {
484 XMLENTRY('<', "&lt;"),
485 XMLENTRY('&', "&amp;"),
486 XMLENTRY('>', "&gt;"),
487 XMLENTRY('\'', "&apos;"),
488 XMLENTRY('"', "&quot;")
489 };
490
491 /** Escape any XML reserved characters in a string. */
492 static bool ecos_escape_string(const char *raw, char *out, size_t limit)
493 {
494 static const char *tokens = "<&>\'\"";
495 bool escaped = false;
496
497 if (!out || !limit)
498 return false;
499
500 (void)memset(out, '\0', limit);
501
502 while (raw && *raw && limit) {
503 size_t lok = strcspn(raw, tokens);
504 if (lok) {
505 size_t tocopy;
506 tocopy = ((limit < lok) ? limit : lok);
507 (void)memcpy(out, raw, tocopy);
508 limit -= tocopy;
509 out += tocopy;
510 raw += lok;
511 continue;
512 }
513
514 char *fidx = strchr(tokens, *raw);
515 if (!fidx) {
516 /* Should never happen assuming xmlchars
517 * vector and tokens string match. */
518 LOG_ERROR("eCos: Unexpected XML char %c", *raw);
519 continue;
520 }
521
522 uint32_t cidx = (fidx - tokens);
523 size_t tocopy = xmlchars[cidx].rlen;
524 if (limit < tocopy)
525 break;
526
527 escaped = true;
528 (void)memcpy(out, xmlchars[cidx].rs, tocopy);
529 limit -= tocopy;
530 out += tocopy;
531 raw++;
532 }
533
534 return escaped;
535 }
536
537 static int ecos_check_app_info(struct rtos *rtos, struct ecos_params *param)
538 {
539 if (!rtos || !param)
540 return -1;
541
542 if (param->flush_common) {
543 if (debug_level >= LOG_LVL_DEBUG) {
544 for (unsigned int idx = 0; idx < ARRAY_SIZE(ecos_symbol_list); idx++) {
545 LOG_DEBUG("eCos: %s 0x%016" PRIX64 " %s",
546 rtos->symbols[idx].optional ? "OPTIONAL" : " ",
547 rtos->symbols[idx].address, rtos->symbols[idx].symbol_name);
548 }
549 }
550
551 /* If "__ecospro_syminfo.size.cyg_thread.list_next" is non-zero then we
552 * expect all of the generic thread structure symbols to have been
553 * provided. */
554 symbol_address_t thread_next_size = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NEXT_SIZE);
555 if (thread_next_size != 0) {
556 param->pointer_width = thread_next_size;
557 param->uid_width = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_ID_SIZE);
558 param->state_width = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STATE_SIZE);
559 param->thread_stack_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STACK_OFF);
560 param->thread_name_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NAME_OFF);
561 param->thread_state_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STATE_OFF);
562 param->thread_next_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NEXT_OFF);
563 param->thread_uniqueid_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_ID_OFF);
564 }
565
566 if (param->uid_width != sizeof(uint16_t)) {
567 /* Currently all eCos configurations use a 16-bit field to hold the
568 * unique thread ID. */
569 LOG_WARNING("eCos: Unexpected unique_id width %" PRIu8, param->uid_width);
570 param->uid_width = (unsigned char)sizeof(uint16_t);
571 }
572
573 param->stacking_info = NULL;
574 param->flush_common = false;
575 }
576
577 return ERROR_OK;
578 }
579
580 /* The Cortex-M eCosPro "thread" contexts have a "type" indicator, which tracks
581 * the context state of (THREAD | EXCEPTION | INTERRUPT) and whether FPU
582 * registers are saved.
583 *
584 * For thread-aware debugging from GDB we are only interested in THREAD states
585 * and so do not need to implement support for INTERRUPT or EXCEPTION thread
586 * contexts since this code does not expose those stack contexts via the
587 * constructed thread list support. */
588 static int ecos_stack_layout_cortexm(struct rtos *rtos,
589 struct ecos_params *param, int64_t stack_ptr,
590 const struct rtos_register_stacking **si)
591 {
592 int retval = ERROR_OK;
593
594 /* CONSIDER: We could return
595 * ecos_value(rtos, ECOS_VAL_CORTEXM_THREAD_SAVED) as the actual PC
596 * address of a context switch, with the LR being set to the context PC
597 * field to give a true representation of where the thread switch
598 * occurs. However that would require extending the common
599 * rtos_generic_stack_read() code with suitable support for applying a
600 * supplied value, or just implementing our own version of that code that
601 * can inject data into what is passed onwards to GDB. */
602
603 /* UPDATE: When we can return VFP register state then we will NOT be
604 * basing the cached state on the single param->stacking_info value,
605 * since we will need a different stacking_info structure returned for
606 * each thread type when FPU support is enabled. The use of the single
607 * param->stacking_info is a holder whilst we are limited to the fixed
608 * ARMV7M_NUM_CORE_REGS set of descriptors. */
609
610 if (!param->stacking_info &&
611 ecos_value(rtos, ECOS_VAL_CORTEXM_THREAD_SAVED) &&
612 ecos_value(rtos, ECOS_VAL_CORTEXM_VAL_THREAD)) {
613 unsigned char numoutreg = ECOS_CORTEXM_BASE_NUMREGS;
614
615 rtos_ecos_stacking.stack_registers_size = ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_THREAD_SIZE);
616 rtos_ecos_stacking.calculate_process_stack = rtos_generic_stack_align8;
617 rtos_ecos_stacking.register_offsets = rtos_ecos_regoff_cortexm;
618
619 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R0].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x00);
620 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R1].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x04);
621 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R2].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x08);
622 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R3].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x0C);
623 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R4].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x10);
624 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R5].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x14);
625 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R6].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x18);
626 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R7].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x1C);
627 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R8].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x20);
628 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R9].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x24);
629 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R10].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x28);
630 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R11].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x2C);
631 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R12].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x30);
632 /* Rather than using the stacked ECOS_VAL_CORTEXM_CTX_SP_OFF
633 * value we force the reported sp to be after the stacked
634 * register context. */
635 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R13].offset = -2;
636 rtos_ecos_regoff_cortexm[ECOS_REGLIST_R14].offset = -1;
637 rtos_ecos_regoff_cortexm[ECOS_REGLIST_PC].offset = ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_PC_OFF);
638 rtos_ecos_regoff_cortexm[ECOS_REGLIST_XPSR].offset = -1;
639
640 param->stacking_info = &rtos_ecos_stacking;
641
642 /* Common Cortex-M thread register offsets for the current
643 * symbol table: */
644 if (retval == ERROR_OK && param->stacking_info) {
645 if (numoutreg > ECOS_REGLIST_BASEPRI) {
646 rtos_ecos_regoff_cortexm[ECOS_REGLIST_BASEPRI].offset =
647 ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_BASEPRI_OFF);
648 }
649
650 rtos_ecos_stacking.num_output_registers = numoutreg;
651 }
652 }
653
654 if (si)
655 *si = param->stacking_info;
656
657 return retval;
658 }
659
660 static int ecos_stack_layout_arm(struct rtos *rtos, struct ecos_params *param,
661 int64_t stack_ptr, const struct rtos_register_stacking **si)
662 {
663 int retval = ERROR_OK;
664
665 if (!param->stacking_info && ecos_value(rtos, ECOS_VAL_ARM_REGSIZE)) {
666 /* When OpenOCD is extended to allow FPU registers to be returned from a
667 * stacked thread context we can check:
668 * if (0 != ecos_value(rtos, ECOS_VAL_ARM_FPUSIZE)) { FPU }
669 * for presence of FPU registers in the context. */
670
671 rtos_ecos_stacking.stack_registers_size = ecos_value(rtos, ECOS_VAL_ARM_REGSIZE);
672 rtos_ecos_stacking.num_output_registers = ARRAY_SIZE(rtos_ecos_regoff_arm);
673 rtos_ecos_stacking.register_offsets = rtos_ecos_regoff_arm;
674
675 rtos_ecos_regoff_arm[0].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R0_OFF);
676 rtos_ecos_regoff_arm[1].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R1_OFF);
677 rtos_ecos_regoff_arm[2].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R2_OFF);
678 rtos_ecos_regoff_arm[3].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R3_OFF);
679 rtos_ecos_regoff_arm[4].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R4_OFF);
680 rtos_ecos_regoff_arm[5].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R5_OFF);
681 rtos_ecos_regoff_arm[6].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R6_OFF);
682 rtos_ecos_regoff_arm[7].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R7_OFF);
683 rtos_ecos_regoff_arm[8].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R8_OFF);
684 rtos_ecos_regoff_arm[9].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R9_OFF);
685 rtos_ecos_regoff_arm[10].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R10_OFF);
686 rtos_ecos_regoff_arm[11].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_FP_OFF);
687 rtos_ecos_regoff_arm[12].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_IP_OFF);
688 rtos_ecos_regoff_arm[13].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_SP_OFF);
689 rtos_ecos_regoff_arm[14].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_LR_OFF);
690 rtos_ecos_regoff_arm[15].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_PC_OFF);
691 rtos_ecos_regoff_arm[16].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_CPSR_OFF);
692
693 param->stacking_info = &rtos_ecos_stacking;
694 }
695
696 if (si)
697 *si = param->stacking_info;
698
699 return retval;
700 }
701
702 /* We see this function called on a new connection, it looks like before and
703 * after the "tar rem"/"tar extended-remote". It might be the only point we can
704 * decide to cache information (to check if the symbol table has changed). */
705 static int ecos_update_threads(struct rtos *rtos)
706 {
707 int retval;
708 int tasks_found = 0;
709 int thread_list_size = 0;
710 struct ecos_params *param;
711
712 if (!rtos)
713 return -1;
714
715 /* wipe out previous thread details if any */
716 rtos_free_threadlist(rtos);
717
718 if (!rtos->rtos_specific_params)
719 return -3;
720
721 param = rtos->rtos_specific_params;
722
723 if (!rtos->symbols) {
724 /* NOTE: We only see this when connecting from GDB the first
725 * time before the application image is loaded. So it is not a
726 * hook for detecting an application change. */
727 param->flush_common = true;
728 LOG_ERROR("No symbols for eCos");
729 return -4;
730 }
731
732 retval = ecos_check_app_info(rtos, param);
733 if (retval != ERROR_OK)
734 return retval;
735
736 if (rtos->symbols[ECOS_VAL_THREAD_LIST].address == 0) {
737 LOG_ERROR("Don't have the thread list head");
738 return -2;
739 }
740
741 /* determine the number of current threads */
742 uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
743 uint32_t thread_index;
744 target_read_buffer(rtos->target,
745 thread_list_head,
746 param->pointer_width,
747 (uint8_t *) &thread_index);
748 uint32_t first_thread = thread_index;
749
750 /* Even if 0==first_thread indicates a system with no defined eCos
751 * threads, instead of early exiting here we fall through the code to
752 * allow the creation of a faked "Current Execution" descriptor as
753 * needed. */
754
755 if (first_thread) {
756 /* Since the OpenOCD RTOS support can attempt to obtain thread
757 * information on initial connection when the system *may* have
758 * undefined memory state it is possible for a simple thread count scan
759 * to produce invalid results. To avoid blocking indefinitely when
760 * encountering an invalid closed loop we limit the number of threads to
761 * the maximum possible, and if we pass that limit then something is
762 * wrong so treat the system as having no threads defined. */
763 do {
764 thread_list_size++;
765 if (thread_list_size > ECOS_MAX_THREAD_COUNT) {
766 /* Treat as "no threads" case: */
767 first_thread = 0;
768 thread_list_size = 0;
769 break;
770 }
771 retval = target_read_buffer(rtos->target,
772 thread_index + param->thread_next_offset,
773 param->pointer_width,
774 (uint8_t *)&thread_index);
775 if (retval != ERROR_OK)
776 return retval;
777 } while (thread_index != first_thread);
778 }
779
780 /* read the current thread id */
781 rtos->current_thread = 0;
782
783 uint32_t current_thread_addr;
784 retval = target_read_buffer(rtos->target,
785 rtos->symbols[ECOS_VAL_CURRENT_THREAD_PTR].address,
786 param->pointer_width,
787 (uint8_t *)&current_thread_addr);
788 if (retval != ERROR_OK) {
789 LOG_ERROR("Reading active thread address");
790 return retval;
791 }
792
793 if (current_thread_addr) {
794 uint16_t id = 0;
795 retval = target_read_buffer(rtos->target,
796 current_thread_addr + param->thread_uniqueid_offset,
797 param->uid_width,
798 (uint8_t *)&id);
799 if (retval != ERROR_OK) {
800 LOG_ERROR("Could not read eCos current thread from target");
801 return retval;
802 }
803 rtos->current_thread = (threadid_t)id;
804 }
805
806 if (thread_list_size == 0 || rtos->current_thread == 0) {
807 /* Either : No RTOS threads - there is always at least the current execution though */
808 /* OR : No current thread - all threads suspended - show the current execution
809 * of idling */
810 static const char tmp_str[] = "Current Execution";
811 thread_list_size++;
812 tasks_found++;
813 rtos->thread_details = malloc(
814 sizeof(struct thread_detail) * thread_list_size);
815 /* 1 is a valid eCos thread id, so we return 0 for this faked
816 * "current" CPU state: */
817 rtos->thread_details->threadid = 0;
818 rtos->thread_details->exists = true;
819 rtos->thread_details->extra_info_str = NULL;
820 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
821 strcpy(rtos->thread_details->thread_name_str, tmp_str);
822
823 /* Early exit if current CPU state our only "thread": */
824 if (thread_list_size == 1) {
825 rtos->thread_count = 1;
826 return ERROR_OK;
827 }
828 } else {
829 /* create space for new thread details */
830 rtos->thread_details = malloc(
831 sizeof(struct thread_detail) * thread_list_size);
832 }
833
834 /* loop over all threads */
835 thread_index = first_thread;
836 do {
837 #define ECOS_THREAD_NAME_STR_SIZE (200)
838 char tmp_str[ECOS_THREAD_NAME_STR_SIZE];
839 uint32_t name_ptr = 0;
840 uint32_t prev_thread_ptr;
841
842 /* Save the thread ID. For eCos the thread has a unique ID distinct from
843 * the thread_index descriptor pointer. We present this scheduler ID
844 * instead of the descriptor memory address. */
845 uint16_t thread_id = 0;
846 retval = target_read_buffer(rtos->target,
847 thread_index + param->thread_uniqueid_offset,
848 param->uid_width,
849 (uint8_t *)&thread_id);
850 if (retval != ERROR_OK) {
851 LOG_ERROR("Could not read eCos thread id from target");
852 return retval;
853 }
854 rtos->thread_details[tasks_found].threadid = thread_id;
855
856 /* Read the name pointer */
857 retval = target_read_buffer(rtos->target,
858 thread_index + param->thread_name_offset,
859 param->pointer_width,
860 (uint8_t *)&name_ptr);
861 if (retval != ERROR_OK) {
862 LOG_ERROR("Could not read eCos thread name pointer from target");
863 return retval;
864 }
865
866 /* Read the thread name */
867 retval =
868 target_read_buffer(rtos->target,
869 name_ptr,
870 ECOS_THREAD_NAME_STR_SIZE,
871 (uint8_t *)&tmp_str);
872 if (retval != ERROR_OK) {
873 LOG_ERROR("Error reading thread name from eCos target");
874 return retval;
875 }
876 tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00';
877
878 /* Since eCos can have arbitrary C string names we can sometimes
879 * get an internal warning from GDB about "not well-formed
880 * (invalid token)" since the XML post-processing done by GDB on
881 * the OpenOCD returned response containing the thread strings
882 * is not escaped. For example the eCos kernel testsuite
883 * application tm_basic uses the thread name "<<NULL>>" which
884 * will trigger this failure unless escaped. */
885 if (tmp_str[0] == '\x00') {
886 snprintf(tmp_str, ECOS_THREAD_NAME_STR_SIZE, "NoName:[0x%08" PRIX32 "]", thread_index);
887 } else {
888 /* The following is a workaround to avoid any issues
889 * from arbitrary eCos thread names causing GDB/OpenOCD
890 * issues. We limit the escaped thread name passed to
891 * GDB to the same length as the un-escaped just to
892 * avoid overly long strings. */
893 char esc_str[ECOS_THREAD_NAME_STR_SIZE];
894 bool escaped = ecos_escape_string(tmp_str, esc_str, sizeof(esc_str));
895 if (escaped)
896 strcpy(tmp_str, esc_str);
897 }
898
899 rtos->thread_details[tasks_found].thread_name_str =
900 malloc(strlen(tmp_str)+1);
901 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
902
903 /* Read the thread status */
904 int64_t thread_status = 0;
905 retval = target_read_buffer(rtos->target,
906 thread_index + param->thread_state_offset,
907 param->state_width,
908 (uint8_t *)&thread_status);
909 if (retval != ERROR_OK) {
910 LOG_ERROR("Error reading thread state from eCos target");
911 return retval;
912 }
913
914 /* The thread_status is a BITMASK */
915 char state_desc[21]; /* Enough for "suspended+countsleep\0" maximum */
916
917 if (thread_status & SUSPENDED)
918 strcpy(state_desc, "suspended+");
919 else
920 state_desc[0] = '\0';
921
922 switch (thread_status & ~SUSPENDED) {
923 case RUNNING:
924 if (thread_index == current_thread_addr)
925 strcat(state_desc, "running");
926 else if (thread_status & SUSPENDED)
927 state_desc[9] = '\0'; /* Drop '+' from "suspended+" */
928 else
929 strcat(state_desc, "ready");
930 break;
931 case SLEEPING:
932 strcat(state_desc, "sleeping");
933 break;
934 case SLEEPSET:
935 case COUNTSLEEP:
936 strcat(state_desc, "counted sleep");
937 break;
938 case CREATING:
939 strcpy(state_desc, "creating");
940 break;
941 case EXITED:
942 strcpy(state_desc, "exited");
943 break;
944 default:
945 strcpy(state_desc, "unknown state");
946 break;
947 }
948
949 /* For the moment we do not bother decoding the wake reason for the
950 * active "running" thread, but it is useful providing the sleep reason
951 * for stacked threads. */
952 int64_t sleep_reason = 0; /* sleep reason */
953
954 if (thread_index != current_thread_addr &&
955 ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_SIZE)) {
956 retval = target_read_buffer(rtos->target,
957 (thread_index + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_OFF)),
958 ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_SIZE),
959 (uint8_t *)&sleep_reason);
960 if (retval != ERROR_OK) {
961 LOG_ERROR("Error reading thread sleep reason from eCos target");
962 return retval;
963 }
964 if (sleep_reason < 0 ||
965 sleep_reason > (int64_t)ARRAY_SIZE(ecos_thread_reasons)) {
966 sleep_reason = 0;
967 }
968 }
969
970 /* We do not display anything for the Cyg_Thread::NONE reason */
971 size_t tr_extra = 0;
972 const char *reason_desc = NULL;
973 if (sleep_reason)
974 reason_desc = ecos_thread_reasons[sleep_reason].desc;
975 if (reason_desc)
976 tr_extra = 2 + strlen(reason_desc) + 1;
977
978 /* Display thread priority if available: */
979 int64_t priority = 0;
980 size_t pri_extra = 0;
981 if (ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_SIZE)) {
982 retval = target_read_buffer(rtos->target,
983 (thread_index + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_OFF)),
984 ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_SIZE),
985 (uint8_t *)&priority);
986 if (retval != ERROR_OK) {
987 LOG_ERROR("Error reading thread priority from eCos target");
988 return retval;
989 }
990 pri_extra = (12 + 20); /* worst-case ", Priority: " */
991 }
992
993 size_t eilen = (8 + strlen(state_desc) + tr_extra + pri_extra);
994 char *eistr = malloc(eilen);
995 /* We do not need to treat a malloc failure as a fatal error here since
996 * the code below will just not report extra thread information if NULL,
997 * thus allowing all of the threads to be enumerated even with reduced
998 * information when the host is low on memory. However... */
999 if (!eistr) {
1000 LOG_ERROR("OOM allocating extra information buffer");
1001 return ERROR_FAIL;
1002 }
1003
1004 int soff = snprintf(eistr, eilen, "State: %s", state_desc);
1005 if (tr_extra && reason_desc)
1006 soff += snprintf(&eistr[soff], (eilen - soff), " (%s)", reason_desc);
1007 if (pri_extra)
1008 (void)snprintf(&eistr[soff], (eilen - soff), ", Priority: %" PRId64 "", priority);
1009 rtos->thread_details[tasks_found].extra_info_str = eistr;
1010
1011 rtos->thread_details[tasks_found].exists = true;
1012
1013 tasks_found++;
1014 prev_thread_ptr = thread_index;
1015
1016 /* Get the location of the next thread structure. */
1017 thread_index = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
1018 retval = target_read_buffer(rtos->target,
1019 prev_thread_ptr + param->thread_next_offset,
1020 param->pointer_width,
1021 (uint8_t *) &thread_index);
1022 if (retval != ERROR_OK) {
1023 LOG_ERROR("Error reading next thread pointer in eCos thread list");
1024 return retval;
1025 }
1026 } while (thread_index != first_thread);
1027
1028 rtos->thread_count = tasks_found;
1029 return ERROR_OK;
1030 }
1031
1032 static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
1033 struct rtos_reg **reg_list, int *num_regs)
1034 {
1035 int retval;
1036 struct ecos_params *param;
1037
1038 if (!rtos)
1039 return -1;
1040
1041 if (thread_id == 0)
1042 return -2;
1043
1044 if (!rtos->rtos_specific_params)
1045 return -3;
1046
1047 param = rtos->rtos_specific_params;
1048
1049 retval = ecos_check_app_info(rtos, param);
1050 if (retval != ERROR_OK)
1051 return retval;
1052
1053 /* We can get memory access errors reported by this function on
1054 * re-connecting to a board with stale thread information in memory. The
1055 * initial ecos_update_threads() is called twice and may read
1056 * stale/invalid information depending on the memory state. This happens
1057 * as part of the "target remote" connection so cannot be avoided by GDB
1058 * scripting. It is not critical and allowing the application to run and
1059 * initialise its BSS etc. will allow correct thread and register
1060 * information to be obtained. This really only affects debug sessions
1061 * where "info thr" is used before the initial run-time initialisation
1062 * has occurred. */
1063
1064 /* Find the thread with that thread id */
1065 uint16_t id = 0;
1066 uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
1067 uint32_t thread_index;
1068 target_read_buffer(rtos->target, thread_list_head, param->pointer_width,
1069 (uint8_t *)&thread_index);
1070 bool done = false;
1071 while (!done) {
1072 retval = target_read_buffer(rtos->target,
1073 thread_index + param->thread_uniqueid_offset,
1074 param->uid_width,
1075 (uint8_t *)&id);
1076 if (retval != ERROR_OK) {
1077 LOG_ERROR("Error reading unique id from eCos thread 0x%08" PRIX32 "", thread_index);
1078 return retval;
1079 }
1080
1081 if (id == thread_id) {
1082 done = true;
1083 break;
1084 }
1085 target_read_buffer(rtos->target,
1086 thread_index + param->thread_next_offset,
1087 param->pointer_width,
1088 (uint8_t *) &thread_index);
1089 }
1090
1091 if (done) {
1092 /* Read the stack pointer */
1093 int64_t stack_ptr = 0;
1094 retval = target_read_buffer(rtos->target,
1095 thread_index + param->thread_stack_offset,
1096 param->pointer_width,
1097 (uint8_t *)&stack_ptr);
1098 if (retval != ERROR_OK) {
1099 LOG_ERROR("Error reading stack frame from eCos thread");
1100 return retval;
1101 }
1102
1103 if (!stack_ptr) {
1104 LOG_ERROR("NULL stack pointer in thread %" PRIu64, thread_id);
1105 return -5;
1106 }
1107
1108 const struct rtos_register_stacking *stacking_info = NULL;
1109 if (param->target_stack_layout) {
1110 retval = param->target_stack_layout(rtos, param, stack_ptr, &stacking_info);
1111 if (retval != ERROR_OK) {
1112 LOG_ERROR("Error reading stack layout for eCos thread");
1113 return retval;
1114 }
1115 }
1116 if (!stacking_info)
1117 stacking_info = &rtos_ecos_cortex_m3_stacking;
1118
1119 return rtos_generic_stack_read(rtos->target,
1120 stacking_info,
1121 stack_ptr,
1122 reg_list,
1123 num_regs);
1124 }
1125
1126 return -1;
1127 }
1128
1129 /* NOTE: This is only called once when the first GDB connection is made to
1130 * OpenOCD and not on subsequent connections (when the application symbol table
1131 * may have changed, affecting the offsets of critical fields and the stacked
1132 * context shape). */
1133 static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
1134 {
1135 unsigned int i;
1136 *symbol_list = calloc(
1137 ARRAY_SIZE(ecos_symbol_list), sizeof(struct symbol_table_elem));
1138
1139 /* If the target reference was passed into this function we could limit
1140 * the symbols we need to lookup to the target->type->name based
1141 * range. For the moment we need to provide a single vector with all of
1142 * the symbols across all of the supported architectures. */
1143 for (i = 0; i < ARRAY_SIZE(ecos_symbol_list); i++) {
1144 (*symbol_list)[i].symbol_name = ecos_symbol_list[i].name;
1145 (*symbol_list)[i].optional = ecos_symbol_list[i].optional;
1146 }
1147
1148 return 0;
1149 }
1150
1151 /* NOTE: Only called by rtos.c:rtos_qsymbol() when auto-detecting the RTOS. If
1152 * the target configuration uses the explicit "-rtos" config option then this
1153 * detection routine is NOT called. */
1154 static bool ecos_detect_rtos(struct target *target)
1155 {
1156 if ((target->rtos->symbols) &&
1157 (target->rtos->symbols[ECOS_VAL_THREAD_LIST].address != 0)) {
1158 /* looks like eCos */
1159 return true;
1160 }
1161 return false;
1162 }
1163
1164 /* Since we should never have 0 as a valid eCos thread ID we use $Hg0 as the
1165 * indicator of a new session as regards flushing any cached state. */
1166 static int ecos_packet_hook(struct connection *connection,
1167 const char *packet, int packet_size)
1168 {
1169 int64_t current_threadid;
1170
1171 if (packet[0] == 'H' && packet[1] == 'g') {
1172 int numscan = sscanf(packet, "Hg%16" SCNx64, &current_threadid);
1173 if (numscan == 1 && current_threadid == 0) {
1174 struct target *target = get_target_from_connection(connection);
1175 if (target && target->rtos && target->rtos->rtos_specific_params) {
1176 struct ecos_params *param;
1177 param = target->rtos->rtos_specific_params;
1178 param->flush_common = true;
1179 }
1180 }
1181 }
1182
1183 return rtos_thread_packet(connection, packet, packet_size);
1184 }
1185
1186 /* Called at start of day when eCos detected or specified in config file. */
1187 static int ecos_create(struct target *target)
1188 {
1189 for (unsigned int i = 0; i < ARRAY_SIZE(ecos_params_list); i++) {
1190 const char * const *tnames = ecos_params_list[i].target_names;
1191 while (*tnames) {
1192 if (strcmp(*tnames, target->type->name) == 0) {
1193 /* LOG_DEBUG("eCos: matched target \"%s\"", target->type->name); */
1194 target->rtos->rtos_specific_params = (void *)&ecos_params_list[i];
1195 ecos_params_list[i].flush_common = true;
1196 ecos_params_list[i].stacking_info = NULL;
1197 target->rtos->current_thread = 0;
1198 target->rtos->thread_details = NULL;
1199
1200 /* We use the $Hg0 packet as a new GDB connection "start-of-day" hook to
1201 * force a re-cache of information. It is possible for a single OpenOCD
1202 * session to be connected to a target with multiple GDB debug sessions
1203 * started/stopped. With eCos it is possible for those GDB sessions to
1204 * present applications with different offsets within a thread
1205 * descriptor for fields used by this module, and for the stacked
1206 * context within the connected target architecture to differ between
1207 * applications and even between threads in a single application. So we
1208 * need to ensure any information we cache is flushed on an application
1209 * change, and GDB referencing an invalid eCos thread ID (0) is a good
1210 * enough point, since we can accept the re-cache hit if that packet
1211 * appears during an established session, whilst benefiting from not
1212 * re-loading information on every update_threads or get_thread_reg_list
1213 * call. */
1214 target->rtos->gdb_thread_packet = ecos_packet_hook;
1215 /* We do not currently use the target->rtos->gdb_target_for_threadid
1216 * hook. */
1217 return 0;
1218 }
1219 tnames++;
1220 }
1221 }
1222
1223 LOG_ERROR("Could not find target in eCos compatibility list");
1224 return -1;
1225 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)