1 // SPDX-License-Identifier: GPL-2.0-or-later
7 #include <helper/time_support.h>
9 #include "target/target.h"
10 #include "target/target_type.h"
11 #include "target/register.h"
12 #include <target/smp.h>
14 #include "helper/log.h"
15 #include "helper/types.h"
16 #include "server/gdb_server.h"
18 static bool hwthread_detect_rtos(struct target
*target
);
19 static int hwthread_create(struct target
*target
);
20 static int hwthread_update_threads(struct rtos
*rtos
);
21 static int hwthread_get_thread_reg(struct rtos
*rtos
, int64_t thread_id
,
22 uint32_t reg_num
, struct rtos_reg
*rtos_reg
);
23 static int hwthread_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
24 struct rtos_reg
**reg_list
, int *num_regs
);
25 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[]);
26 static int hwthread_smp_init(struct target
*target
);
27 static int hwthread_set_reg(struct rtos
*rtos
, uint32_t reg_num
, uint8_t *reg_value
);
28 static int hwthread_read_buffer(struct rtos
*rtos
, target_addr_t address
,
29 uint32_t size
, uint8_t *buffer
);
30 static int hwthread_write_buffer(struct rtos
*rtos
, target_addr_t address
,
31 uint32_t size
, const uint8_t *buffer
);
33 #define HW_THREAD_NAME_STR_SIZE (32)
35 static inline threadid_t
threadid_from_target(const struct target
*target
)
37 return target
->coreid
+ 1;
40 const struct rtos_type hwthread_rtos
= {
42 .detect_rtos
= hwthread_detect_rtos
,
43 .create
= hwthread_create
,
44 .update_threads
= hwthread_update_threads
,
45 .get_thread_reg_list
= hwthread_get_thread_reg_list
,
46 .get_thread_reg
= hwthread_get_thread_reg
,
47 .get_symbol_list_to_lookup
= hwthread_get_symbol_list_to_lookup
,
48 .smp_init
= hwthread_smp_init
,
49 .set_reg
= hwthread_set_reg
,
50 .read_buffer
= hwthread_read_buffer
,
51 .write_buffer
= hwthread_write_buffer
,
54 struct hwthread_params
{
58 static int hwthread_fill_thread(struct rtos
*rtos
, struct target
*curr
, int thread_num
)
60 char tmp_str
[HW_THREAD_NAME_STR_SIZE
];
61 threadid_t tid
= threadid_from_target(curr
);
63 memset(tmp_str
, 0, HW_THREAD_NAME_STR_SIZE
);
65 /* thread-id is the core-id of this core inside the SMP group plus 1 */
66 rtos
->thread_details
[thread_num
].threadid
= tid
;
67 /* create the thread name */
68 rtos
->thread_details
[thread_num
].exists
= true;
69 rtos
->thread_details
[thread_num
].thread_name_str
= strdup(target_name(curr
));
70 snprintf(tmp_str
, HW_THREAD_NAME_STR_SIZE
-1, "state: %s", debug_reason_name(curr
));
71 rtos
->thread_details
[thread_num
].extra_info_str
= strdup(tmp_str
);
76 static int hwthread_update_threads(struct rtos
*rtos
)
78 int threads_found
= 0;
79 int thread_list_size
= 0;
80 struct target_list
*head
;
81 struct target
*target
;
82 int64_t current_thread
= 0;
83 int64_t current_threadid
= rtos
->current_threadid
; /* thread selected by GDB */
84 enum target_debug_reason current_reason
= DBG_REASON_UNDEFINED
;
89 target
= rtos
->target
;
91 /* wipe out previous thread details if any */
92 rtos_free_threadlist(rtos
);
94 /* determine the number of "threads" */
96 foreach_smp_target(head
, target
->smp_targets
) {
97 struct target
*curr
= head
->target
;
99 if (!target_was_examined(curr
))
105 thread_list_size
= 1;
107 /* restore the threadid which is currently selected by GDB
108 * because rtos_free_threadlist() wipes out it
109 * (GDB thread id is 1-based indexing) */
110 if (current_threadid
<= thread_list_size
)
111 rtos
->current_threadid
= current_threadid
;
113 LOG_WARNING("SMP node change, disconnect GDB from core/thread %" PRId64
,
116 /* create space for new thread details */
117 rtos
->thread_details
= malloc(sizeof(struct thread_detail
) * thread_list_size
);
120 /* loop over all threads */
121 foreach_smp_target(head
, target
->smp_targets
) {
122 struct target
*curr
= head
->target
;
124 if (!target_was_examined(curr
))
127 threadid_t tid
= threadid_from_target(curr
);
129 hwthread_fill_thread(rtos
, curr
, threads_found
);
131 /* find an interesting thread to set as current */
132 switch (current_reason
) {
133 case DBG_REASON_UNDEFINED
:
134 current_reason
= curr
->debug_reason
;
135 current_thread
= tid
;
137 case DBG_REASON_SINGLESTEP
:
138 /* single-step can only be overridden by itself */
139 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
140 if (tid
== rtos
->current_threadid
)
141 current_thread
= tid
;
144 case DBG_REASON_BREAKPOINT
:
145 /* single-step overrides breakpoint */
146 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
147 current_reason
= curr
->debug_reason
;
148 current_thread
= tid
;
150 /* multiple breakpoints, prefer gdbs' threadid */
151 if (curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
152 if (tid
== rtos
->current_threadid
)
153 current_thread
= tid
;
156 case DBG_REASON_WATCHPOINT
:
157 /* breakpoint and single-step override watchpoint */
158 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
159 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
160 current_reason
= curr
->debug_reason
;
161 current_thread
= tid
;
164 case DBG_REASON_DBGRQ
:
165 /* all other reasons override debug-request */
166 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
167 curr
->debug_reason
== DBG_REASON_WATCHPOINT
||
168 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
169 current_reason
= curr
->debug_reason
;
170 current_thread
= tid
;
172 if (curr
->debug_reason
== DBG_REASON_DBGRQ
) {
173 if (tid
== rtos
->current_threadid
)
174 current_thread
= tid
;
186 hwthread_fill_thread(rtos
, target
, threads_found
);
187 current_thread
= threadid_from_target(target
);
191 rtos
->thread_count
= threads_found
;
193 /* we found an interesting thread, set it as current */
194 if (current_thread
!= 0)
195 rtos
->current_thread
= current_thread
;
196 else if (rtos
->current_threadid
!= 0)
197 rtos
->current_thread
= rtos
->current_threadid
;
199 rtos
->current_thread
= threadid_from_target(target
);
201 LOG_DEBUG("%s current_thread=%i", __func__
, (int)rtos
->current_thread
);
205 static int hwthread_smp_init(struct target
*target
)
207 return hwthread_update_threads(target
->rtos
);
210 static struct target
*hwthread_find_thread(struct target
*target
, int64_t thread_id
)
212 /* Find the thread with that thread_id */
216 struct target_list
*head
;
217 foreach_smp_target(head
, target
->smp_targets
) {
218 if (thread_id
== threadid_from_target(head
->target
))
221 } else if (thread_id
== threadid_from_target(target
)) {
227 static int hwthread_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
228 struct rtos_reg
**rtos_reg_list
, int *rtos_reg_list_size
)
233 struct target
*target
= rtos
->target
;
235 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
239 if (!target_was_examined(curr
))
243 struct reg
**reg_list
;
244 int retval
= target_get_gdb_reg_list(curr
, ®_list
, ®_list_size
,
246 if (retval
!= ERROR_OK
)
250 for (int i
= 0; i
< reg_list_size
; i
++) {
251 if (!reg_list
[i
] || reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
255 *rtos_reg_list_size
= j
;
256 *rtos_reg_list
= calloc(*rtos_reg_list_size
, sizeof(struct rtos_reg
));
257 if (!*rtos_reg_list
) {
263 for (int i
= 0; i
< reg_list_size
; i
++) {
264 if (!reg_list
[i
] || reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
266 if (!reg_list
[i
]->valid
) {
267 retval
= reg_list
[i
]->type
->get(reg_list
[i
]);
268 if (retval
!= ERROR_OK
) {
269 LOG_ERROR("Couldn't get register %s.", reg_list
[i
]->name
);
271 free(*rtos_reg_list
);
275 (*rtos_reg_list
)[j
].number
= reg_list
[i
]->number
;
276 (*rtos_reg_list
)[j
].size
= reg_list
[i
]->size
;
277 memcpy((*rtos_reg_list
)[j
].value
, reg_list
[i
]->value
,
278 DIV_ROUND_UP(reg_list
[i
]->size
, 8));
286 static int hwthread_get_thread_reg(struct rtos
*rtos
, int64_t thread_id
,
287 uint32_t reg_num
, struct rtos_reg
*rtos_reg
)
292 struct target
*target
= rtos
->target
;
294 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
296 LOG_ERROR("Couldn't find RTOS thread for id %" PRId64
".", thread_id
);
300 if (!target_was_examined(curr
)) {
301 LOG_ERROR("Target %d hasn't been examined yet.", curr
->coreid
);
305 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
307 LOG_ERROR("Couldn't find register %" PRIu32
" in thread %" PRId64
".", reg_num
,
312 if (reg
->type
->get(reg
) != ERROR_OK
)
315 rtos_reg
->number
= reg
->number
;
316 rtos_reg
->size
= reg
->size
;
317 unsigned bytes
= (reg
->size
+ 7) / 8;
318 assert(bytes
<= sizeof(rtos_reg
->value
));
319 memcpy(rtos_reg
->value
, reg
->value
, bytes
);
324 static int hwthread_set_reg(struct rtos
*rtos
, uint32_t reg_num
, uint8_t *reg_value
)
329 struct target
*target
= rtos
->target
;
331 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
335 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
339 return reg
->type
->set(reg
, reg_value
);
342 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
344 /* return an empty list, we don't have any symbols to look up */
345 *symbol_list
= calloc(1, sizeof(struct symbol_table_elem
));
346 (*symbol_list
)[0].symbol_name
= NULL
;
350 static int hwthread_target_for_threadid(struct connection
*connection
, int64_t thread_id
, struct target
**p_target
)
352 struct target
*target
= get_target_from_connection(connection
);
354 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
363 static bool hwthread_detect_rtos(struct target
*target
)
365 /* always return 0, avoid auto-detection */
369 static int hwthread_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
)
371 struct target
*target
= get_target_from_connection(connection
);
373 struct target
*curr
= NULL
;
374 int64_t current_threadid
;
376 if (packet
[0] == 'H' && packet
[1] == 'g') {
377 sscanf(packet
, "Hg%16" SCNx64
, ¤t_threadid
);
379 if (current_threadid
> 0) {
380 if (hwthread_target_for_threadid(connection
, current_threadid
, &curr
) != ERROR_OK
) {
381 LOG_ERROR("hwthread: cannot find thread id %"PRId64
, current_threadid
);
382 gdb_put_packet(connection
, "E01", 3);
385 target
->rtos
->current_thread
= current_threadid
;
387 if (current_threadid
== 0 || current_threadid
== -1)
388 target
->rtos
->current_thread
= threadid_from_target(target
);
390 target
->rtos
->current_threadid
= current_threadid
;
392 gdb_put_packet(connection
, "OK", 2);
396 return rtos_thread_packet(connection
, packet
, packet_size
);
399 static int hwthread_create(struct target
*target
)
401 LOG_INFO("Hardware thread awareness created");
403 target
->rtos
->rtos_specific_params
= NULL
;
404 target
->rtos
->current_thread
= 0;
405 target
->rtos
->thread_details
= NULL
;
406 target
->rtos
->gdb_target_for_threadid
= hwthread_target_for_threadid
;
407 target
->rtos
->gdb_thread_packet
= hwthread_thread_packet
;
411 static int hwthread_read_buffer(struct rtos
*rtos
, target_addr_t address
,
412 uint32_t size
, uint8_t *buffer
)
417 struct target
*target
= rtos
->target
;
419 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
423 return target_read_buffer(curr
, address
, size
, buffer
);
426 static int hwthread_write_buffer(struct rtos
*rtos
, target_addr_t address
,
427 uint32_t size
, const uint8_t *buffer
)
432 struct target
*target
= rtos
->target
;
434 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
438 return target_write_buffer(curr
, address
, size
, buffer
);
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)