Revert "Remove duplicate of a counter in hwthread_update_threads"
[openocd.git] / src / rtos / hwthread.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #include <helper/time_support.h>
8 #include <jtag/jtag.h>
9 #include "target/target.h"
10 #include "target/target_type.h"
11 #include "target/register.h"
12 #include <target/smp.h>
13 #include "rtos.h"
14 #include "helper/log.h"
15 #include "helper/types.h"
16 #include "server/gdb_server.h"
17
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);
32
33 #define HW_THREAD_NAME_STR_SIZE (32)
34
35 extern int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
36
37 static inline threadid_t threadid_from_target(const struct target *target)
38 {
39 return target->coreid + 1;
40 }
41
42 const struct rtos_type hwthread_rtos = {
43 .name = "hwthread",
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,
54 };
55
56 struct hwthread_params {
57 int dummy_param;
58 };
59
60 static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num)
61 {
62 char tmp_str[HW_THREAD_NAME_STR_SIZE];
63 threadid_t tid = threadid_from_target(curr);
64
65 memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);
66
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);
74
75 return ERROR_OK;
76 }
77
78 static int hwthread_update_threads(struct rtos *rtos)
79 {
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;
86
87 if (!rtos)
88 return -1;
89
90 target = rtos->target;
91
92 /* wipe out previous thread details if any */
93 rtos_free_threadlist(rtos);
94
95 /* determine the number of "threads" */
96 if (target->smp) {
97 foreach_smp_target(head, target->smp_targets) {
98 struct target *curr = head->target;
99
100 if (!target_was_examined(curr))
101 continue;
102
103 ++thread_list_size;
104 }
105 } else
106 thread_list_size = 1;
107
108 /* create space for new thread details */
109 rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
110
111 if (target->smp) {
112 /* loop over all threads */
113 foreach_smp_target(head, target->smp_targets) {
114 struct target *curr = head->target;
115
116 if (!target_was_examined(curr))
117 continue;
118
119 threadid_t tid = threadid_from_target(curr);
120
121 hwthread_fill_thread(rtos, curr, threads_found);
122
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;
128 break;
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;
134 }
135 break;
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;
141 } else
142 /* multiple breakpoints, prefer gdbs' threadid */
143 if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
144 if (tid == rtos->current_threadid)
145 current_thread = tid;
146 }
147 break;
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;
154 }
155 break;
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;
163 } else
164 if (curr->debug_reason == DBG_REASON_DBGRQ) {
165 if (tid == rtos->current_threadid)
166 current_thread = tid;
167 }
168
169 break;
170
171 default:
172 break;
173 }
174
175 threads_found++;
176 }
177 } else {
178 hwthread_fill_thread(rtos, target, threads_found);
179 current_thread = threadid_from_target(target);
180 threads_found++;
181 }
182
183 rtos->thread_count = threads_found;
184
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;
190 else
191 rtos->current_thread = threadid_from_target(target);
192
193 LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
194 return 0;
195 }
196
197 static int hwthread_smp_init(struct target *target)
198 {
199 return hwthread_update_threads(target->rtos);
200 }
201
202 static struct target *hwthread_find_thread(struct target *target, int64_t thread_id)
203 {
204 /* Find the thread with that thread_id */
205 if (!target)
206 return NULL;
207 if (target->smp) {
208 struct target_list *head;
209 foreach_smp_target(head, target->smp_targets) {
210 if (thread_id == threadid_from_target(head->target))
211 return head->target;
212 }
213 } else if (thread_id == threadid_from_target(target)) {
214 return target;
215 }
216 return NULL;
217 }
218
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)
221 {
222 if (!rtos)
223 return ERROR_FAIL;
224
225 struct target *target = rtos->target;
226
227 struct target *curr = hwthread_find_thread(target, thread_id);
228 if (!curr)
229 return ERROR_FAIL;
230
231 if (!target_was_examined(curr))
232 return ERROR_FAIL;
233
234 int reg_list_size;
235 struct reg **reg_list;
236 int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
237 REG_CLASS_GENERAL);
238 if (retval != ERROR_OK)
239 return retval;
240
241 int j = 0;
242 for (int i = 0; i < reg_list_size; i++) {
243 if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
244 continue;
245 j++;
246 }
247 *rtos_reg_list_size = j;
248 *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
249 if (!*rtos_reg_list) {
250 free(reg_list);
251 return ERROR_FAIL;
252 }
253
254 j = 0;
255 for (int i = 0; i < reg_list_size; i++) {
256 if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
257 continue;
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 ((*reg_list)[i].size + 7) / 8);
262 j++;
263 }
264 free(reg_list);
265
266 return ERROR_OK;
267 }
268
269 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
270 uint32_t reg_num, struct rtos_reg *rtos_reg)
271 {
272 if (!rtos)
273 return ERROR_FAIL;
274
275 struct target *target = rtos->target;
276
277 struct target *curr = hwthread_find_thread(target, thread_id);
278 if (!curr) {
279 LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id);
280 return ERROR_FAIL;
281 }
282
283 if (!target_was_examined(curr)) {
284 LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid);
285 return ERROR_FAIL;
286 }
287
288 struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
289 if (!reg) {
290 LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num,
291 thread_id);
292 return ERROR_FAIL;
293 }
294
295 if (reg->type->get(reg) != ERROR_OK)
296 return ERROR_FAIL;
297
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);
303
304 return ERROR_OK;
305 }
306
307 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
308 {
309 if (!rtos)
310 return ERROR_FAIL;
311
312 struct target *target = rtos->target;
313
314 struct target *curr = hwthread_find_thread(target, rtos->current_thread);
315 if (!curr)
316 return ERROR_FAIL;
317
318 struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
319 if (!reg)
320 return ERROR_FAIL;
321
322 return reg->type->set(reg, reg_value);
323 }
324
325 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
326 {
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;
330 return 0;
331 }
332
333 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
334 {
335 struct target *target = get_target_from_connection(connection);
336
337 struct target *curr = hwthread_find_thread(target, thread_id);
338 if (!curr)
339 return ERROR_FAIL;
340
341 *p_target = curr;
342
343 return ERROR_OK;
344 }
345
346 static bool hwthread_detect_rtos(struct target *target)
347 {
348 /* always return 0, avoid auto-detection */
349 return false;
350 }
351
352 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
353 {
354 struct target *target = get_target_from_connection(connection);
355
356 struct target *curr = NULL;
357 int64_t current_threadid;
358
359 if (packet[0] == 'H' && packet[1] == 'g') {
360 sscanf(packet, "Hg%16" SCNx64, &current_threadid);
361
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);
366 return ERROR_FAIL;
367 }
368 target->rtos->current_thread = current_threadid;
369 } else
370 if (current_threadid == 0 || current_threadid == -1)
371 target->rtos->current_thread = threadid_from_target(target);
372
373 target->rtos->current_threadid = current_threadid;
374
375 gdb_put_packet(connection, "OK", 2);
376 return ERROR_OK;
377 }
378
379 return rtos_thread_packet(connection, packet, packet_size);
380 }
381
382 static int hwthread_create(struct target *target)
383 {
384 LOG_INFO("Hardware thread awareness created");
385
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;
391 return 0;
392 }
393
394 static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
395 uint32_t size, uint8_t *buffer)
396 {
397 if (!rtos)
398 return ERROR_FAIL;
399
400 struct target *target = rtos->target;
401
402 struct target *curr = hwthread_find_thread(target, rtos->current_thread);
403 if (!curr)
404 return ERROR_FAIL;
405
406 return target_read_buffer(curr, address, size, buffer);
407 }
408
409 static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
410 uint32_t size, const uint8_t *buffer)
411 {
412 if (!rtos)
413 return ERROR_FAIL;
414
415 struct target *target = rtos->target;
416
417 struct target *curr = hwthread_find_thread(target, rtos->current_thread);
418 if (!curr)
419 return ERROR_FAIL;
420
421 return target_write_buffer(curr, address, size, buffer);
422 }

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)