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_list(struct rtos
*rtos
, int64_t thread_id
,
35 struct rtos_reg
**reg_list
, int *num_regs
);
36 static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[]);
37 static int hwthread_smp_init(struct target
*target
);
39 #define HW_THREAD_NAME_STR_SIZE (32)
41 extern int rtos_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
);
43 static inline threadid_t
threadid_from_target(const struct target
*target
)
45 return target
->coreid
+ 1;
48 const struct rtos_type hwthread_rtos
= {
50 .detect_rtos
= hwthread_detect_rtos
,
51 .create
= hwthread_create
,
52 .update_threads
= hwthread_update_threads
,
53 .get_thread_reg_list
= hwthread_get_thread_reg_list
,
54 .get_symbol_list_to_lookup
= hwthread_get_symbol_list_to_lookup
,
55 .smp_init
= hwthread_smp_init
,
58 struct hwthread_params
{
62 static int hwthread_fill_thread(struct rtos
*rtos
, struct target
*curr
, int thread_num
)
64 char tmp_str
[HW_THREAD_NAME_STR_SIZE
];
65 threadid_t tid
= threadid_from_target(curr
);
67 memset(tmp_str
, 0, HW_THREAD_NAME_STR_SIZE
);
69 /* thread-id is the core-id of this core inside the SMP group plus 1 */
70 rtos
->thread_details
[thread_num
].threadid
= tid
;
71 /* create the thread name */
72 rtos
->thread_details
[thread_num
].exists
= true;
73 rtos
->thread_details
[thread_num
].thread_name_str
= strdup(target_name(curr
));
74 snprintf(tmp_str
, HW_THREAD_NAME_STR_SIZE
-1, "state: %s", debug_reason_name(curr
));
75 rtos
->thread_details
[thread_num
].extra_info_str
= strdup(tmp_str
);
80 static int hwthread_update_threads(struct rtos
*rtos
)
82 int threads_found
= 0;
83 int thread_list_size
= 0;
84 struct target_list
*head
;
85 struct target
*target
;
86 int64_t current_thread
= 0;
87 enum target_debug_reason current_reason
= DBG_REASON_UNDEFINED
;
92 target
= rtos
->target
;
94 /* wipe out previous thread details if any */
95 rtos_free_threadlist(rtos
);
97 /* determine the number of "threads" */
99 for (head
= target
->head
; head
!= NULL
; head
= head
->next
) {
100 struct target
*curr
= head
->target
;
102 if (!target_was_examined(curr
))
108 thread_list_size
= 1;
110 /* create space for new thread details */
111 rtos
->thread_details
= malloc(sizeof(struct thread_detail
) * thread_list_size
);
114 /* loop over all threads */
115 for (head
= target
->head
; head
!= NULL
; head
= head
->next
) {
116 struct target
*curr
= head
->target
;
118 if (!target_was_examined(curr
))
121 threadid_t tid
= threadid_from_target(curr
);
123 hwthread_fill_thread(rtos
, curr
, threads_found
);
125 /* find an interesting thread to set as current */
126 switch (current_reason
) {
127 case DBG_REASON_UNDEFINED
:
128 current_reason
= curr
->debug_reason
;
129 current_thread
= tid
;
131 case DBG_REASON_SINGLESTEP
:
132 /* single-step can only be overridden by itself */
133 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
134 if (tid
== rtos
->current_threadid
)
135 current_thread
= tid
;
138 case DBG_REASON_BREAKPOINT
:
139 /* single-step overrides breakpoint */
140 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
) {
141 current_reason
= curr
->debug_reason
;
142 current_thread
= tid
;
144 /* multiple breakpoints, prefer gdbs' threadid */
145 if (curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
146 if (tid
== rtos
->current_threadid
)
147 current_thread
= tid
;
150 case DBG_REASON_WATCHPOINT
:
151 /* breakpoint and single-step override watchpoint */
152 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
153 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
154 current_reason
= curr
->debug_reason
;
155 current_thread
= tid
;
158 case DBG_REASON_DBGRQ
:
159 /* all other reasons override debug-request */
160 if (curr
->debug_reason
== DBG_REASON_SINGLESTEP
||
161 curr
->debug_reason
== DBG_REASON_WATCHPOINT
||
162 curr
->debug_reason
== DBG_REASON_BREAKPOINT
) {
163 current_reason
= curr
->debug_reason
;
164 current_thread
= tid
;
166 if (curr
->debug_reason
== DBG_REASON_DBGRQ
) {
167 if (tid
== rtos
->current_threadid
)
168 current_thread
= tid
;
180 hwthread_fill_thread(rtos
, target
, threads_found
);
181 current_thread
= threadid_from_target(target
);
185 rtos
->thread_count
= threads_found
;
187 /* we found an interesting thread, set it as current */
188 if (current_thread
!= 0)
189 rtos
->current_thread
= current_thread
;
190 else if (rtos
->current_threadid
!= 0)
191 rtos
->current_thread
= rtos
->current_threadid
;
193 rtos
->current_thread
= threadid_from_target(target
);
195 LOG_DEBUG("%s current_thread=%i", __func__
, (int)rtos
->current_thread
);
199 static int hwthread_smp_init(struct target
*target
)
201 return hwthread_update_threads(target
->rtos
);
204 static int hwthread_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
205 struct rtos_reg
**rtos_reg_list
, int *num_regs
)
207 struct target_list
*head
;
208 struct target
*target
;
210 struct reg
**reg_list
;
216 target
= rtos
->target
;
218 /* Find the thread with that thread_id */
221 for (head
= target
->head
; head
!= NULL
; head
= head
->next
) {
224 if (thread_id
== threadid_from_target(curr
))
232 if (thread_id
!= threadid_from_target(curr
))
237 if (!target_was_examined(curr
))
240 retval
= target_get_gdb_reg_list(curr
, ®_list
, num_regs
,
242 if (retval
!= ERROR_OK
)
245 *rtos_reg_list
= calloc(*num_regs
, sizeof(struct rtos_reg
));
246 if (*rtos_reg_list
== NULL
) {
251 for (int i
= 0; i
< *num_regs
; i
++) {
252 (*rtos_reg_list
)[i
].number
= (*reg_list
)[i
].number
;
253 (*rtos_reg_list
)[i
].size
= (*reg_list
)[i
].size
;
254 memcpy((*rtos_reg_list
)[i
].value
, (*reg_list
)[i
].value
,
255 ((*reg_list
)[i
].size
+ 7) / 8);
264 static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
266 /* return an empty list, we don't have any symbols to look up */
267 *symbol_list
= calloc(1, sizeof(symbol_table_elem_t
));
268 (*symbol_list
)[0].symbol_name
= NULL
;
272 static int hwthread_target_for_threadid(struct connection
*connection
, int64_t thread_id
, struct target
**p_target
)
274 struct target
*target
= get_target_from_connection(connection
);
275 struct target_list
*head
;
279 /* Find the thread with that thread_id */
281 for (head
= target
->head
; head
!= NULL
; head
= head
->next
) {
284 if (thread_id
== threadid_from_target(curr
))
292 if (thread_id
!= threadid_from_target(curr
))
301 static bool hwthread_detect_rtos(struct target
*target
)
303 /* always return 0, avoid auto-detection */
307 static int hwthread_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
)
309 struct target
*target
= get_target_from_connection(connection
);
311 struct target
*curr
= NULL
;
312 int64_t current_threadid
;
314 if (packet
[0] == 'H' && packet
[1] == 'g') {
315 sscanf(packet
, "Hg%16" SCNx64
, ¤t_threadid
);
317 if (current_threadid
> 0) {
318 if (hwthread_target_for_threadid(connection
, current_threadid
, &curr
) != ERROR_OK
) {
319 LOG_ERROR("hwthread: cannot find thread id %"PRId64
, current_threadid
);
320 gdb_put_packet(connection
, "E01", 3);
323 target
->rtos
->current_thread
= current_threadid
;
325 if (current_threadid
== 0 || current_threadid
== -1)
326 target
->rtos
->current_thread
= threadid_from_target(target
);
328 target
->rtos
->current_threadid
= current_threadid
;
330 gdb_put_packet(connection
, "OK", 2);
334 return rtos_thread_packet(connection
, packet
, packet_size
);
337 static int hwthread_create(struct target
*target
)
339 LOG_INFO("Hardware thread awareness created");
341 target
->rtos
->rtos_specific_params
= NULL
;
342 target
->rtos
->current_thread
= 0;
343 target
->rtos
->thread_details
= NULL
;
344 target
->rtos
->gdb_target_for_threadid
= hwthread_target_for_threadid
;
345 target
->rtos
->gdb_thread_packet
= hwthread_thread_packet
;
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)