OpenOCD
hwthread.c
Go to the documentation of this file.
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 
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  int64_t current_threadid = rtos->current_threadid; /* thread selected by GDB */
86  enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
87 
88  if (!rtos)
89  return -1;
90 
91  target = rtos->target;
92 
93  /* wipe out previous thread details if any */
95 
96  /* determine the number of "threads" */
97  if (target->smp) {
99  struct target *curr = head->target;
100 
101  if (!target_was_examined(curr))
102  continue;
103 
104  ++thread_list_size;
105  }
106  } else
107  thread_list_size = 1;
108 
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;
114  else
115  LOG_WARNING("SMP node change, disconnect GDB from core/thread %" PRId64,
116  current_threadid);
117 
118  /* create space for new thread details */
119  rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
120 
121  if (target->smp) {
122  /* loop over all threads */
124  struct target *curr = head->target;
125 
126  if (!target_was_examined(curr))
127  continue;
128 
129  threadid_t tid = threadid_from_target(curr);
130 
131  hwthread_fill_thread(rtos, curr, threads_found);
132 
133  /* find an interesting thread to set as current */
134  switch (current_reason) {
136  current_reason = curr->debug_reason;
137  current_thread = tid;
138  break;
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;
144  }
145  break;
147  /* single-step overrides breakpoint */
148  if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
149  current_reason = curr->debug_reason;
150  current_thread = tid;
151  } else
152  /* multiple breakpoints, prefer gdbs' threadid */
153  if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
154  if (tid == rtos->current_threadid)
155  current_thread = tid;
156  }
157  break;
159  /* breakpoint and single-step override watchpoint */
160  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
162  current_reason = curr->debug_reason;
163  current_thread = tid;
164  }
165  break;
166  case DBG_REASON_DBGRQ:
167  /* all other reasons override debug-request */
168  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
171  current_reason = curr->debug_reason;
172  current_thread = tid;
173  } else
174  if (curr->debug_reason == DBG_REASON_DBGRQ) {
175  if (tid == rtos->current_threadid)
176  current_thread = tid;
177  }
178 
179  break;
180 
181  default:
182  break;
183  }
184 
185  threads_found++;
186  }
187  } else {
188  hwthread_fill_thread(rtos, target, threads_found);
190  threads_found++;
191  }
192 
193  rtos->thread_count = threads_found;
194 
195  /* we found an interesting thread, set it as current */
196  if (current_thread != 0)
198  else if (rtos->current_threadid != 0)
200  else
202 
203  LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
204  return 0;
205 }
206 
207 static int hwthread_smp_init(struct target *target)
208 {
210 }
211 
212 static struct target *hwthread_find_thread(struct target *target, int64_t thread_id)
213 {
214  /* Find the thread with that thread_id */
215  if (!target)
216  return NULL;
217  if (target->smp) {
218  struct target_list *head;
220  if (thread_id == threadid_from_target(head->target))
221  return head->target;
222  }
223  } else if (thread_id == threadid_from_target(target)) {
224  return target;
225  }
226  return NULL;
227 }
228 
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)
231 {
232  if (!rtos)
233  return ERROR_FAIL;
234 
235  struct target *target = rtos->target;
236 
237  struct target *curr = hwthread_find_thread(target, thread_id);
238  if (!curr)
239  return ERROR_FAIL;
240 
241  if (!target_was_examined(curr))
242  return ERROR_FAIL;
243 
244  int reg_list_size;
245  struct reg **reg_list;
246  int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
248  if (retval != ERROR_OK)
249  return retval;
250 
251  int j = 0;
252  for (int i = 0; i < reg_list_size; i++) {
253  if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
254  continue;
255  j++;
256  }
257  *rtos_reg_list_size = j;
258  *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
259  if (!*rtos_reg_list) {
260  free(reg_list);
261  return ERROR_FAIL;
262  }
263 
264  j = 0;
265  for (int i = 0; i < reg_list_size; i++) {
266  if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
267  continue;
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);
272  free(reg_list);
273  free(*rtos_reg_list);
274  return retval;
275  }
276  }
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));
281  j++;
282  }
283  free(reg_list);
284 
285  return ERROR_OK;
286 }
287 
288 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
289  uint32_t reg_num, struct rtos_reg *rtos_reg)
290 {
291  if (!rtos)
292  return ERROR_FAIL;
293 
294  struct target *target = rtos->target;
295 
296  struct target *curr = hwthread_find_thread(target, thread_id);
297  if (!curr) {
298  LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id);
299  return ERROR_FAIL;
300  }
301 
302  if (!target_was_examined(curr)) {
303  LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid);
304  return ERROR_FAIL;
305  }
306 
307  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
308  if (!reg) {
309  LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num,
310  thread_id);
311  return ERROR_FAIL;
312  }
313 
314  if (reg->type->get(reg) != ERROR_OK)
315  return ERROR_FAIL;
316 
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);
322 
323  return ERROR_OK;
324 }
325 
326 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
327 {
328  if (!rtos)
329  return ERROR_FAIL;
330 
331  struct target *target = rtos->target;
332 
334  if (!curr)
335  return ERROR_FAIL;
336 
337  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
338  if (!reg)
339  return ERROR_FAIL;
340 
341  return reg->type->set(reg, reg_value);
342 }
343 
344 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
345 {
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;
349  return 0;
350 }
351 
352 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
353 {
355 
356  struct target *curr = hwthread_find_thread(target, thread_id);
357  if (!curr)
358  return ERROR_FAIL;
359 
360  *p_target = curr;
361 
362  return ERROR_OK;
363 }
364 
365 static bool hwthread_detect_rtos(struct target *target)
366 {
367  /* always return 0, avoid auto-detection */
368  return false;
369 }
370 
371 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
372 {
374 
375  struct target *curr = NULL;
376  int64_t current_threadid;
377 
378  if (packet[0] == 'H' && packet[1] == 'g') {
379  sscanf(packet, "Hg%16" SCNx64, &current_threadid);
380 
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);
385  return ERROR_FAIL;
386  }
387  target->rtos->current_thread = current_threadid;
388  } else
389  if (current_threadid == 0 || current_threadid == -1)
391 
392  target->rtos->current_threadid = current_threadid;
393 
394  gdb_put_packet(connection, "OK", 2);
395  return ERROR_OK;
396  }
397 
398  return rtos_thread_packet(connection, packet, packet_size);
399 }
400 
401 static int hwthread_create(struct target *target)
402 {
403  LOG_INFO("Hardware thread awareness created");
404 
406  target->rtos->current_thread = 0;
410  return 0;
411 }
412 
413 static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
414  uint32_t size, uint8_t *buffer)
415 {
416  if (!rtos)
417  return ERROR_FAIL;
418 
419  struct target *target = rtos->target;
420 
422  if (!curr)
423  return ERROR_FAIL;
424 
425  return target_read_buffer(curr, address, size, buffer);
426 }
427 
428 static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
429  uint32_t size, const uint8_t *buffer)
430 {
431  if (!rtos)
432  return ERROR_FAIL;
433 
434  struct target *target = rtos->target;
435 
437  if (!curr)
438  return ERROR_FAIL;
439 
440  return target_write_buffer(curr, address, size, buffer);
441 }
const char * name
Definition: armv4_5.c:76
int gdb_put_packet(struct connection *connection, char *buffer, int len)
Definition: gdb_server.c:531
static struct target * get_target_from_connection(struct connection *connection)
Definition: gdb_server.h:32
static int hwthread_create(struct target *target)
Definition: hwthread.c:401
static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
Definition: hwthread.c:371
static bool hwthread_detect_rtos(struct target *target)
Definition: hwthread.c:365
static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: hwthread.c:413
int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size)
Definition: rtos.c:346
#define HW_THREAD_NAME_STR_SIZE
Definition: hwthread.c:33
static int hwthread_update_threads(struct rtos *rtos)
Definition: hwthread.c:78
static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
Definition: hwthread.c:326
static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: hwthread.c:344
static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: hwthread.c:428
const struct rtos_type hwthread_rtos
Definition: hwthread.c:42
static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *rtos_reg)
Definition: hwthread.c:288
static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: hwthread.c:229
static struct target * hwthread_find_thread(struct target *target, int64_t thread_id)
Definition: hwthread.c:212
static threadid_t threadid_from_target(const struct target *target)
Definition: hwthread.c:37
static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num)
Definition: hwthread.c:60
static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
Definition: hwthread.c:352
static int hwthread_smp_init(struct target *target)
Definition: hwthread.c:207
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_WARNING(expr ...)
Definition: log.h:120
#define ERROR_FAIL
Definition: log.h:161
#define LOG_ERROR(expr ...)
Definition: log.h:123
#define LOG_INFO(expr ...)
Definition: log.h:117
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:155
struct reg * register_get_by_number(struct reg_cache *first, uint32_t reg_num, bool search_all)
Definition: register.c:28
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:707
int64_t threadid_t
Definition: rtos.h:15
struct target * target
Definition: rtt/rtt.c:26
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
#define foreach_smp_target(pos, head)
Definition: smp.h:15
int(* get)(struct reg *reg)
Definition: register.h:152
int(* set)(struct reg *reg, uint8_t *buf)
Definition: register.h:153
Definition: register.h:111
bool valid
Definition: register.h:126
bool exist
Definition: register.h:128
uint32_t size
Definition: register.h:132
uint8_t * value
Definition: register.h:122
uint32_t number
Definition: register.h:115
bool hidden
Definition: register.h:130
const struct reg_arch_type * type
Definition: register.h:141
Definition: rtos.h:53
uint32_t number
Definition: rtos.h:54
uint8_t value[16]
Definition: rtos.h:56
uint32_t size
Definition: rtos.h:55
Definition: rtos.h:59
const char * name
Definition: rtos.h:60
Definition: rtos.h:36
int thread_count
Definition: rtos.h:47
int(* gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size)
Definition: rtos.h:48
struct thread_detail * thread_details
Definition: rtos.h:46
struct target * target
Definition: rtos.h:40
void * rtos_specific_params
Definition: rtos.h:50
int(* gdb_target_for_threadid)(struct connection *connection, int64_t thread_id, struct target **p_target)
Definition: rtos.h:49
threadid_t current_thread
Definition: rtos.h:45
int64_t current_threadid
Definition: rtos.h:43
Table should be terminated by an element with NULL in symbol_name.
Definition: rtos.h:23
struct target * target
Definition: target.h:215
Definition: target.h:120
int32_t coreid
Definition: target.h:125
int smp
Definition: target.h:192
enum target_debug_reason debug_reason
Definition: target.h:159
struct reg_cache * reg_cache
Definition: target.h:163
struct list_head * smp_targets
Definition: target.h:193
struct rtos * rtos
Definition: target.h:188
char * extra_info_str
Definition: rtos.h:33
char * thread_name_str
Definition: rtos.h:32
bool exists
Definition: rtos.h:31
threadid_t threadid
Definition: rtos.h:30
int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: target.c:2408
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2473
int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class)
Obtain the registers for GDB.
Definition: target.c:1437
const char * debug_reason_name(struct target *t)
Definition: target.c:289
target_debug_reason
Definition: target.h:72
@ DBG_REASON_UNDEFINED
Definition: target.h:81
@ DBG_REASON_DBGRQ
Definition: target.h:73
@ DBG_REASON_SINGLESTEP
Definition: target.h:77
@ DBG_REASON_WATCHPOINT
Definition: target.h:75
@ DBG_REASON_BREAKPOINT
Definition: target.h:74
@ REG_CLASS_GENERAL
Definition: target.h:116
static const char * target_name(struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:234
static bool target_was_examined(struct target *target)
Definition: target.h:438
#define DIV_ROUND_UP(m, n)
Rounds m up to the nearest multiple of n using division.
Definition: types.h:79
uint64_t target_addr_t
Definition: types.h:335
#define NULL
Definition: usb.h:16