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"
25 #include "target/register.h"
27 #include "helper/log.h"
28 #include "helper/types.h"
29 #include "server/gdb_server.h"
31 static bool hwthread_detect_rtos(struct target
*target
);
32 static int hwthread_create(struct target
*target
);
33 static int hwthread_update_threads(struct rtos
*rtos
);
34 static int hwthread_get_thread_reg(struct rtos
*rtos
, int64_t thread_id
,
35 uint32_t reg_num
, struct rtos_reg
*rtos_reg
);
36 static int hwthread_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
37 struct rtos_reg
**reg_list
, int *num_regs
);
38 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[]);
39 static int hwthread_smp_init(struct target
*target
);
40 static int hwthread_set_reg(struct rtos
*rtos
, uint32_t reg_num
, uint8_t *reg_value
);
42 #define HW_THREAD_NAME_STR_SIZE (32)
44 extern int rtos_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
);
46 static inline threadid_t
threadid_from_target(const struct target
*target
)
48 return target
->coreid
+ 1;
51 const struct rtos_type hwthread_rtos
= {
53 .detect_rtos
= hwthread_detect_rtos
,
54 .create
= hwthread_create
,
55 .update_threads
= hwthread_update_threads
,
56 .get_thread_reg_list
= hwthread_get_thread_reg_list
,
57 .get_thread_reg
= hwthread_get_thread_reg
,
58 .get_symbol_list_to_lookup
= hwthread_get_symbol_list_to_lookup
,
59 .smp_init
= hwthread_smp_init
,
60 .set_reg
= hwthread_set_reg
,
63 struct hwthread_params
{
67 static int hwthread_fill_thread(struct rtos
*rtos
, struct target
*curr
, int thread_num
)
69 char tmp_str
[HW_THREAD_NAME_STR_SIZE
];
70 threadid_t tid
= threadid_from_target(curr
);
72 memset(tmp_str
, 0, HW_THREAD_NAME_STR_SIZE
);
74 /* thread-id is the core-id of this core inside the SMP group plus 1 */
75 rtos
->thread_details
[thread_num
].threadid
= tid
;
76 /* create the thread name */
77 rtos
->thread_details
[thread_num
].exists
= true;
78 rtos
->thread_details
[thread_num
].thread_name_str
= strdup(target_name(curr
));
79 snprintf(tmp_str
, HW_THREAD_NAME_STR_SIZE
-1, "state: %s", debug_reason_name(curr
));
80 rtos
->thread_details
[thread_num
].extra_info_str
= strdup(tmp_str
);
85 static int hwthread_update_threads(struct rtos
*rtos
)
87 int threads_found
= 0;
88 int thread_list_size
= 0;
89 struct target_list
*head
;
90 struct target
*target
;
91 int64_t current_thread
= 0;
92 enum target_debug_reason current_reason
= DBG_REASON_UNDEFINED
;
97 target
= rtos
->target
;
99 /* wipe out previous thread details if any */
100 rtos_free_threadlist(rtos
);
102 /* determine the number of "threads" */
104 for (head
= target
->head
; head
!= NULL
; head
= head
->next
) {
105 struct target
*curr
= head
->target
;
107 if (!target_was_examined(curr
))
113 thread_list_size
= 1;
115 /* create space for new thread details */
116 rtos
->thread_details
= malloc(sizeof(struct thread_detail
) * thread_list_size
);
119 /* loop over all threads */
120 for (head
= target
->head
; head
!= NULL
; head
= head
->next
) {
121 struct target
*curr
= head
->target
;
123 if (!target_was_examined(curr
))
126 threadid_t tid
= threadid_from_target(curr
);
128 hwthread_fill_thread(rtos
, curr
, threads_found
);
130 /* find an interesting thread to set as current */
131 switch (current_reason
) {
132 case DBG_REASON_UNDEFINED
:
133 current_reason
= curr
->debug_reason
;
134 current_thread
= tid
;
136 case DBG_REASON_SINGLESTEP
:
137 /* single-step can only be overridden by itself */
138 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
139 if (tid
== rtos
->current_threadid
)
140 current_thread
= tid
;
143 case DBG_REASON_BREAKPOINT
:
144 /* single-step overrides breakpoint */
145 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
146 current_reason
= curr
->debug_reason
;
147 current_thread
= tid
;
149 /* multiple breakpoints, prefer gdbs' threadid */
150 if (curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
151 if (tid
== rtos
->current_threadid
)
152 current_thread
= tid
;
155 case DBG_REASON_WATCHPOINT
:
156 /* breakpoint and single-step override watchpoint */
157 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
158 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
159 current_reason
= curr
->debug_reason
;
160 current_thread
= tid
;
163 case DBG_REASON_DBGRQ
:
164 /* all other reasons override debug-request */
165 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
166 curr
->debug_reason
== DBG_REASON_WATCHPOINT
||
167 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
168 current_reason
= curr
->debug_reason
;
169 current_thread
= tid
;
171 if (curr
->debug_reason
== DBG_REASON_DBGRQ
) {
172 if (tid
== rtos
->current_threadid
)
173 current_thread
= tid
;
185 hwthread_fill_thread(rtos
, target
, threads_found
);
186 current_thread
= threadid_from_target(target
);
190 rtos
->thread_count
= threads_found
;
192 /* we found an interesting thread, set it as current */
193 if (current_thread
!= 0)
194 rtos
->current_thread
= current_thread
;
195 else if (rtos
->current_threadid
!= 0)
196 rtos
->current_thread
= rtos
->current_threadid
;
198 rtos
->current_thread
= threadid_from_target(target
);
200 LOG_DEBUG("%s current_thread=%i", __func__
, (int)rtos
->current_thread
);
204 static int hwthread_smp_init(struct target
*target
)
206 return hwthread_update_threads(target
->rtos
);
209 static struct target
*hwthread_find_thread(struct target
*target
, int64_t thread_id
)
211 /* Find the thread with that thread_id */
215 for (struct target_list
*head
= target
->head
; head
!= NULL
; head
= head
->next
) {
216 if (thread_id
== threadid_from_target(head
->target
))
219 } else if (thread_id
== threadid_from_target(target
)) {
225 static int hwthread_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
226 struct rtos_reg
**rtos_reg_list
, int *rtos_reg_list_size
)
231 struct target
*target
= rtos
->target
;
233 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
237 if (!target_was_examined(curr
))
241 struct reg
**reg_list
;
242 int retval
= target_get_gdb_reg_list(curr
, ®_list
, ®_list_size
,
244 if (retval
!= ERROR_OK
)
248 for (int i
= 0; i
< reg_list_size
; i
++) {
249 if (reg_list
[i
] == NULL
|| reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
253 *rtos_reg_list_size
= j
;
254 *rtos_reg_list
= calloc(*rtos_reg_list_size
, sizeof(struct rtos_reg
));
255 if (*rtos_reg_list
== NULL
) {
261 for (int i
= 0; i
< reg_list_size
; i
++) {
262 if (reg_list
[i
] == NULL
|| reg_list
[i
]->exist
== false || reg_list
[i
]->hidden
)
264 (*rtos_reg_list
)[j
].number
= (*reg_list
)[i
].number
;
265 (*rtos_reg_list
)[j
].size
= (*reg_list
)[i
].size
;
266 memcpy((*rtos_reg_list
)[j
].value
, (*reg_list
)[i
].value
,
267 ((*reg_list
)[i
].size
+ 7) / 8);
275 static int hwthread_get_thread_reg(struct rtos
*rtos
, int64_t thread_id
,
276 uint32_t reg_num
, struct rtos_reg
*rtos_reg
)
281 struct target
*target
= rtos
->target
;
283 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
285 LOG_ERROR("Couldn't find RTOS thread for id %" PRId64
".", thread_id
);
289 if (!target_was_examined(curr
)) {
290 LOG_ERROR("Target %d hasn't been examined yet.", curr
->coreid
);
294 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
296 LOG_ERROR("Couldn't find register %" PRIu32
" in thread %" PRId64
".", reg_num
,
301 if (reg
->type
->get(reg
) != ERROR_OK
)
304 rtos_reg
->number
= reg
->number
;
305 rtos_reg
->size
= reg
->size
;
306 unsigned bytes
= (reg
->size
+ 7) / 8;
307 assert(bytes
<= sizeof(rtos_reg
->value
));
308 memcpy(rtos_reg
->value
, reg
->value
, bytes
);
313 static int hwthread_set_reg(struct rtos
*rtos
, uint32_t reg_num
, uint8_t *reg_value
)
318 struct target
*target
= rtos
->target
;
320 struct target
*curr
= hwthread_find_thread(target
, rtos
->current_thread
);
324 struct reg
*reg
= register_get_by_number(curr
->reg_cache
, reg_num
, true);
328 return reg
->type
->set(reg
, reg_value
);
331 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
333 /* return an empty list, we don't have any symbols to look up */
334 *symbol_list
= calloc(1, sizeof(struct symbol_table_elem
));
335 (*symbol_list
)[0].symbol_name
= NULL
;
339 static int hwthread_target_for_threadid(struct connection
*connection
, int64_t thread_id
, struct target
**p_target
)
341 struct target
*target
= get_target_from_connection(connection
);
343 struct target
*curr
= hwthread_find_thread(target
, thread_id
);
352 static bool hwthread_detect_rtos(struct target
*target
)
354 /* always return 0, avoid auto-detection */
358 static int hwthread_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
)
360 struct target
*target
= get_target_from_connection(connection
);
362 struct target
*curr
= NULL
;
363 int64_t current_threadid
;
365 if (packet
[0] == 'H' && packet
[1] == 'g') {
366 sscanf(packet
, "Hg%16" SCNx64
, ¤t_threadid
);
368 if (current_threadid
> 0) {
369 if (hwthread_target_for_threadid(connection
, current_threadid
, &curr
) != ERROR_OK
) {
370 LOG_ERROR("hwthread: cannot find thread id %"PRId64
, current_threadid
);
371 gdb_put_packet(connection
, "E01", 3);
374 target
->rtos
->current_thread
= current_threadid
;
376 if (current_threadid
== 0 || current_threadid
== -1)
377 target
->rtos
->current_thread
= threadid_from_target(target
);
379 target
->rtos
->current_threadid
= current_threadid
;
381 gdb_put_packet(connection
, "OK", 2);
385 return rtos_thread_packet(connection
, packet
, packet_size
);
388 static int hwthread_create(struct target
*target
)
390 LOG_INFO("Hardware thread awareness created");
392 target
->rtos
->rtos_specific_params
= NULL
;
393 target
->rtos
->current_thread
= 0;
394 target
->rtos
->thread_details
= NULL
;
395 target
->rtos
->gdb_target_for_threadid
= hwthread_target_for_threadid
;
396 target
->rtos
->gdb_thread_packet
= hwthread_thread_packet
;