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 extern int rtos_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
);
37 static inline threadid_t
threadid_from_target(const struct target
*target
)
39 return target
->coreid
+ 1;
42 const struct rtos_type hwthread_rtos
= {
44 .detect_rtos
= hwthread_detect_rtos
,
45 .create
= hwthread_create
,
46 .update_threads
= hwthread_update_threads
,
47 .get_thread_reg_list
= hwthread_get_thread_reg_list
,
48 .get_thread_reg
= hwthread_get_thread_reg
,
49 .get_symbol_list_to_lookup
= hwthread_get_symbol_list_to_lookup
,
50 .smp_init
= hwthread_smp_init
,
51 .set_reg
= hwthread_set_reg
,
52 .read_buffer
= hwthread_read_buffer
,
53 .write_buffer
= hwthread_write_buffer
,
56 struct hwthread_params
{
60 static int hwthread_fill_thread(struct rtos
*rtos
, struct target
*curr
, int thread_num
)
62 char tmp_str
[HW_THREAD_NAME_STR_SIZE
];
63 threadid_t tid
= threadid_from_target(curr
);
65 memset(tmp_str
, 0, HW_THREAD_NAME_STR_SIZE
);
67 /* thread-id is the core-id of this core inside the SMP group plus 1 */
68 rtos
->thread_details
[thread_num
].threadid
= tid
;
69 /* create the thread name */
70 rtos
->thread_details
[thread_num
].exists
= true;
71 rtos
->thread_details
[thread_num
].thread_name_str
= strdup(target_name(curr
));
72 snprintf(tmp_str
, HW_THREAD_NAME_STR_SIZE
-1, "state: %s", debug_reason_name(curr
));
73 rtos
->thread_details
[thread_num
].extra_info_str
= strdup(tmp_str
);
78 static int hwthread_update_threads(struct rtos
*rtos
)
80 int threads_found
= 0;
81 int thread_list_size
= 0;
82 struct target_list
*head
;
83 struct target
*target
;
84 int64_t current_thread
= 0;
85 enum target_debug_reason current_reason
= DBG_REASON_UNDEFINED
;
90 target
= rtos
->target
;
92 /* wipe out previous thread details if any */
93 rtos_free_threadlist(rtos
);
95 /* determine the number of "threads" */
97 foreach_smp_target(head
, target
->smp_targets
) {
98 struct target
*curr
= head
->target
;
100 if (!target_was_examined(curr
))
106 thread_list_size
= 1;
108 /* create space for new thread details */
109 rtos
->thread_details
= malloc(sizeof(struct thread_detail
) * thread_list_size
);
112 /* loop over all threads */
113 foreach_smp_target(head
, target
->smp_targets
) {
114 struct target
*curr
= head
->target
;
116 if (!target_was_examined(curr
))
119 threadid_t tid
= threadid_from_target(curr
);
121 hwthread_fill_thread(rtos
, curr
, threads_found
);
123 /* find an interesting thread to set as current */
124 switch (current_reason
) {
125 case DBG_REASON_UNDEFINED
:
126 current_reason
= curr
->debug_reason
;
127 current_thread
= tid
;
129 case DBG_REASON_SINGLESTEP
:
130 /* single-step can only be overridden by itself */
131 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
132 if (tid
== rtos
->current_threadid
)
133 current_thread
= tid
;
136 case DBG_REASON_BREAKPOINT
:
137 /* single-step overrides breakpoint */
138 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
139 current_reason
= curr
->debug_reason
;
140 current_thread
= tid
;
142 /* multiple breakpoints, prefer gdbs' threadid */
143 if (curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
144 if (tid
== rtos
->current_threadid
)
145 current_thread
= tid
;
148 case DBG_REASON_WATCHPOINT
:
149 /* breakpoint and single-step override watchpoint */
150 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
151 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
152 current_reason
= curr
->debug_reason
;
153 current_thread
= tid
;
156 case DBG_REASON_DBGRQ
:
157 /* all other reasons override debug-request */
158 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
159 curr
->debug_reason
== DBG_REASON_WATCHPOINT
||
160 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
161 current_reason
= curr
->debug_reason
;
162 current_thread
= tid
;
164 if (curr
->debug_reason
== DBG_REASON_DBGRQ
) {
165 if (tid
== rtos
->current_threadid
)
166 current_thread
= tid
;
178 hwthread_fill_thread(rtos
, target
, threads_found
);
179 current_thread
= threadid_from_target(target
);
183 rtos
->thread_count
= threads_found
;
185 /* we found an interesting thread, set it as current */
186 if (current_thread
!= 0)
187 rtos
->current_thread
= current_thread
;
188 else if (rtos
->current_threadid
!= 0)
189 rtos
->current_thread
= rtos
->current_threadid
;
191 rtos
->current_thread
= threadid_from_target(target
);
193 LOG_DEBUG("%s current_thread=%i", __func__
, (int)rtos
->current_thread
);
197 static int hwthread_smp_init(struct target
*target
)
199 return hwthread_update_threads(target
->rtos
);
202 static struct target
*hwthread_find_thread(struct target
*target
, int64_t thread_id
)
204 /* Find the thread with that thread_id */
208 struct target_list
*head
;
209 foreach_smp_target(head
, target
->smp_targets
) {
210 if (thread_id
== threadid_from_target(head
->target
))
213 } else if (thread_id
== threadid_from_target(target
)) {
219 static int hwthread_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
220 struct rtos_reg
**rtos_reg_list
, int *rtos_reg_list_size
)
225 struct target
*target
= rtos
->target
;
227 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
231 if (!target_was_examined(curr
))
235 struct reg
**reg_list
;
236 int retval
= target_get_gdb_reg_list(curr
, ®_list
, ®_list_size
,
238 if (retval
!= ERROR_OK
)
242 for (int i
= 0; i
< reg_list_size
; i
++) {
243 if (!reg_list
[i
] || reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
247 *rtos_reg_list_size
= j
;
248 *rtos_reg_list
= calloc(*rtos_reg_list_size
, sizeof(struct rtos_reg
));
249 if (!*rtos_reg_list
) {
255 for (int i
= 0; i
< reg_list_size
; i
++) {
256 if (!reg_list
[i
] || reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
258 (*rtos_reg_list
)[j
].number
= reg_list
[i
]->number
;
259 (*rtos_reg_list
)[j
].size
= reg_list
[i
]->size
;
260 memcpy((*rtos_reg_list
)[j
].value
, reg_list
[i
]->value
,
261 DIV_ROUND_UP(reg_list
[i
]->size
, 8));
269 static int hwthread_get_thread_reg(struct rtos
*rtos
, int64_t thread_id
,
270 uint32_t reg_num
, struct rtos_reg
*rtos_reg
)
275 struct target
*target
= rtos
->target
;
277 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
279 LOG_ERROR("Couldn't find RTOS thread for id %" PRId64
".", thread_id
);
283 if (!target_was_examined(curr
)) {
284 LOG_ERROR("Target %d hasn't been examined yet.", curr
->coreid
);
288 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
290 LOG_ERROR("Couldn't find register %" PRIu32
" in thread %" PRId64
".", reg_num
,
295 if (reg
->type
->get(reg
) != ERROR_OK
)
298 rtos_reg
->number
= reg
->number
;
299 rtos_reg
->size
= reg
->size
;
300 unsigned bytes
= (reg
->size
+ 7) / 8;
301 assert(bytes
<= sizeof(rtos_reg
->value
));
302 memcpy(rtos_reg
->value
, reg
->value
, bytes
);
307 static int hwthread_set_reg(struct rtos
*rtos
, uint32_t reg_num
, uint8_t *reg_value
)
312 struct target
*target
= rtos
->target
;
314 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
318 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
322 return reg
->type
->set(reg
, reg_value
);
325 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
327 /* return an empty list, we don't have any symbols to look up */
328 *symbol_list
= calloc(1, sizeof(struct symbol_table_elem
));
329 (*symbol_list
)[0].symbol_name
= NULL
;
333 static int hwthread_target_for_threadid(struct connection
*connection
, int64_t thread_id
, struct target
**p_target
)
335 struct target
*target
= get_target_from_connection(connection
);
337 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
346 static bool hwthread_detect_rtos(struct target
*target
)
348 /* always return 0, avoid auto-detection */
352 static int hwthread_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
)
354 struct target
*target
= get_target_from_connection(connection
);
356 struct target
*curr
= NULL
;
357 int64_t current_threadid
;
359 if (packet
[0] == 'H' && packet
[1] == 'g') {
360 sscanf(packet
, "Hg%16" SCNx64
, ¤t_threadid
);
362 if (current_threadid
> 0) {
363 if (hwthread_target_for_threadid(connection
, current_threadid
, &curr
) != ERROR_OK
) {
364 LOG_ERROR("hwthread: cannot find thread id %"PRId64
, current_threadid
);
365 gdb_put_packet(connection
, "E01", 3);
368 target
->rtos
->current_thread
= current_threadid
;
370 if (current_threadid
== 0 || current_threadid
== -1)
371 target
->rtos
->current_thread
= threadid_from_target(target
);
373 target
->rtos
->current_threadid
= current_threadid
;
375 gdb_put_packet(connection
, "OK", 2);
379 return rtos_thread_packet(connection
, packet
, packet_size
);
382 static int hwthread_create(struct target
*target
)
384 LOG_INFO("Hardware thread awareness created");
386 target
->rtos
->rtos_specific_params
= NULL
;
387 target
->rtos
->current_thread
= 0;
388 target
->rtos
->thread_details
= NULL
;
389 target
->rtos
->gdb_target_for_threadid
= hwthread_target_for_threadid
;
390 target
->rtos
->gdb_thread_packet
= hwthread_thread_packet
;
394 static int hwthread_read_buffer(struct rtos
*rtos
, target_addr_t address
,
395 uint32_t size
, uint8_t *buffer
)
400 struct target
*target
= rtos
->target
;
402 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
406 return target_read_buffer(curr
, address
, size
, buffer
);
409 static int hwthread_write_buffer(struct rtos
*rtos
, target_addr_t address
,
410 uint32_t size
, const uint8_t *buffer
)
415 struct target
*target
= rtos
->target
;
417 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
421 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)