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 int64_t current_threadid
= rtos
->current_threadid
; /* thread selected by GDB */
86 enum target_debug_reason current_reason
= DBG_REASON_UNDEFINED
;
91 target
= rtos
->target
;
93 /* wipe out previous thread details if any */
94 rtos_free_threadlist(rtos
);
96 /* determine the number of "threads" */
98 foreach_smp_target(head
, target
->smp_targets
) {
99 struct target
*curr
= head
->target
;
101 if (!target_was_examined(curr
))
107 thread_list_size
= 1;
109 /* restore the threadid which is currently selected by GDB
110 * because rtos_free_threadlist() wipes out it
111 * (GDB thread id is 1-based indexing) */
112 if (current_threadid
<= thread_list_size
)
113 rtos
->current_threadid
= current_threadid
;
115 LOG_WARNING("SMP node change, disconnect GDB from core/thread %" PRId64
,
118 /* create space for new thread details */
119 rtos
->thread_details
= malloc(sizeof(struct thread_detail
) * thread_list_size
);
122 /* loop over all threads */
123 foreach_smp_target(head
, target
->smp_targets
) {
124 struct target
*curr
= head
->target
;
126 if (!target_was_examined(curr
))
129 threadid_t tid
= threadid_from_target(curr
);
131 hwthread_fill_thread(rtos
, curr
, threads_found
);
133 /* find an interesting thread to set as current */
134 switch (current_reason
) {
135 case DBG_REASON_UNDEFINED
:
136 current_reason
= curr
->debug_reason
;
137 current_thread
= tid
;
139 case DBG_REASON_SINGLESTEP
:
140 /* single-step can only be overridden by itself */
141 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
142 if (tid
== rtos
->current_threadid
)
143 current_thread
= tid
;
146 case DBG_REASON_BREAKPOINT
:
147 /* single-step overrides breakpoint */
148 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
149 current_reason
= curr
->debug_reason
;
150 current_thread
= tid
;
152 /* multiple breakpoints, prefer gdbs' threadid */
153 if (curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
154 if (tid
== rtos
->current_threadid
)
155 current_thread
= tid
;
158 case DBG_REASON_WATCHPOINT
:
159 /* breakpoint and single-step override watchpoint */
160 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
161 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
162 current_reason
= curr
->debug_reason
;
163 current_thread
= tid
;
166 case DBG_REASON_DBGRQ
:
167 /* all other reasons override debug-request */
168 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
169 curr
->debug_reason
== DBG_REASON_WATCHPOINT
||
170 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
171 current_reason
= curr
->debug_reason
;
172 current_thread
= tid
;
174 if (curr
->debug_reason
== DBG_REASON_DBGRQ
) {
175 if (tid
== rtos
->current_threadid
)
176 current_thread
= tid
;
188 hwthread_fill_thread(rtos
, target
, threads_found
);
189 current_thread
= threadid_from_target(target
);
193 rtos
->thread_count
= threads_found
;
195 /* we found an interesting thread, set it as current */
196 if (current_thread
!= 0)
197 rtos
->current_thread
= current_thread
;
198 else if (rtos
->current_threadid
!= 0)
199 rtos
->current_thread
= rtos
->current_threadid
;
201 rtos
->current_thread
= threadid_from_target(target
);
203 LOG_DEBUG("%s current_thread=%i", __func__
, (int)rtos
->current_thread
);
207 static int hwthread_smp_init(struct target
*target
)
209 return hwthread_update_threads(target
->rtos
);
212 static struct target
*hwthread_find_thread(struct target
*target
, int64_t thread_id
)
214 /* Find the thread with that thread_id */
218 struct target_list
*head
;
219 foreach_smp_target(head
, target
->smp_targets
) {
220 if (thread_id
== threadid_from_target(head
->target
))
223 } else if (thread_id
== threadid_from_target(target
)) {
229 static int hwthread_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
230 struct rtos_reg
**rtos_reg_list
, int *rtos_reg_list_size
)
235 struct target
*target
= rtos
->target
;
237 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
241 if (!target_was_examined(curr
))
245 struct reg
**reg_list
;
246 int retval
= target_get_gdb_reg_list(curr
, ®_list
, ®_list_size
,
248 if (retval
!= ERROR_OK
)
252 for (int i
= 0; i
< reg_list_size
; i
++) {
253 if (!reg_list
[i
] || reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
257 *rtos_reg_list_size
= j
;
258 *rtos_reg_list
= calloc(*rtos_reg_list_size
, sizeof(struct rtos_reg
));
259 if (!*rtos_reg_list
) {
265 for (int i
= 0; i
< reg_list_size
; i
++) {
266 if (!reg_list
[i
] || reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
268 if (!reg_list
[i
]->valid
) {
269 retval
= reg_list
[i
]->type
->get(reg_list
[i
]);
270 if (retval
!= ERROR_OK
) {
271 LOG_ERROR("Couldn't get register %s.", reg_list
[i
]->name
);
273 free(*rtos_reg_list
);
277 (*rtos_reg_list
)[j
].number
= reg_list
[i
]->number
;
278 (*rtos_reg_list
)[j
].size
= reg_list
[i
]->size
;
279 memcpy((*rtos_reg_list
)[j
].value
, reg_list
[i
]->value
,
280 DIV_ROUND_UP(reg_list
[i
]->size
, 8));
288 static int hwthread_get_thread_reg(struct rtos
*rtos
, int64_t thread_id
,
289 uint32_t reg_num
, struct rtos_reg
*rtos_reg
)
294 struct target
*target
= rtos
->target
;
296 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
298 LOG_ERROR("Couldn't find RTOS thread for id %" PRId64
".", thread_id
);
302 if (!target_was_examined(curr
)) {
303 LOG_ERROR("Target %d hasn't been examined yet.", curr
->coreid
);
307 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
309 LOG_ERROR("Couldn't find register %" PRIu32
" in thread %" PRId64
".", reg_num
,
314 if (reg
->type
->get(reg
) != ERROR_OK
)
317 rtos_reg
->number
= reg
->number
;
318 rtos_reg
->size
= reg
->size
;
319 unsigned bytes
= (reg
->size
+ 7) / 8;
320 assert(bytes
<= sizeof(rtos_reg
->value
));
321 memcpy(rtos_reg
->value
, reg
->value
, bytes
);
326 static int hwthread_set_reg(struct rtos
*rtos
, uint32_t reg_num
, uint8_t *reg_value
)
331 struct target
*target
= rtos
->target
;
333 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
337 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
341 return reg
->type
->set(reg
, reg_value
);
344 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
346 /* return an empty list, we don't have any symbols to look up */
347 *symbol_list
= calloc(1, sizeof(struct symbol_table_elem
));
348 (*symbol_list
)[0].symbol_name
= NULL
;
352 static int hwthread_target_for_threadid(struct connection
*connection
, int64_t thread_id
, struct target
**p_target
)
354 struct target
*target
= get_target_from_connection(connection
);
356 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
365 static bool hwthread_detect_rtos(struct target
*target
)
367 /* always return 0, avoid auto-detection */
371 static int hwthread_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
)
373 struct target
*target
= get_target_from_connection(connection
);
375 struct target
*curr
= NULL
;
376 int64_t current_threadid
;
378 if (packet
[0] == 'H' && packet
[1] == 'g') {
379 sscanf(packet
, "Hg%16" SCNx64
, ¤t_threadid
);
381 if (current_threadid
> 0) {
382 if (hwthread_target_for_threadid(connection
, current_threadid
, &curr
) != ERROR_OK
) {
383 LOG_ERROR("hwthread: cannot find thread id %"PRId64
, current_threadid
);
384 gdb_put_packet(connection
, "E01", 3);
387 target
->rtos
->current_thread
= current_threadid
;
389 if (current_threadid
== 0 || current_threadid
== -1)
390 target
->rtos
->current_thread
= threadid_from_target(target
);
392 target
->rtos
->current_threadid
= current_threadid
;
394 gdb_put_packet(connection
, "OK", 2);
398 return rtos_thread_packet(connection
, packet
, packet_size
);
401 static int hwthread_create(struct target
*target
)
403 LOG_INFO("Hardware thread awareness created");
405 target
->rtos
->rtos_specific_params
= NULL
;
406 target
->rtos
->current_thread
= 0;
407 target
->rtos
->thread_details
= NULL
;
408 target
->rtos
->gdb_target_for_threadid
= hwthread_target_for_threadid
;
409 target
->rtos
->gdb_thread_packet
= hwthread_thread_packet
;
413 static int hwthread_read_buffer(struct rtos
*rtos
, target_addr_t address
,
414 uint32_t size
, uint8_t *buffer
)
419 struct target
*target
= rtos
->target
;
421 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
425 return target_read_buffer(curr
, address
, size
, buffer
);
428 static int hwthread_write_buffer(struct rtos
*rtos
, target_addr_t address
,
429 uint32_t size
, const uint8_t *buffer
)
434 struct target
*target
= rtos
->target
;
436 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
440 return target_write_buffer(curr
, address
, size
, buffer
);