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/register.h"
11 #include <target/smp.h>
12 #include "rtos.h"
13 #include "helper/log.h"
14 #include "helper/types.h"
15 #include "server/gdb_server.h"
16 
17 static bool hwthread_detect_rtos(struct target *target);
18 static int hwthread_create(struct target *target);
19 static int hwthread_update_threads(struct rtos *rtos);
20 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
21  uint32_t reg_num, struct rtos_reg *rtos_reg);
22 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
23  struct rtos_reg **reg_list, int *num_regs);
24 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
25 static int hwthread_smp_init(struct target *target);
26 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
28  uint32_t size, uint8_t *buffer);
30  uint32_t size, const uint8_t *buffer);
31 
32 #define HW_THREAD_NAME_STR_SIZE (32)
33 
34 static inline threadid_t threadid_from_target(const struct target *target)
35 {
36  if (!target->smp)
37  return 1;
38 
39  threadid_t threadid = 1;
40  struct target_list *head;
42  if (target == head->target)
43  return threadid;
44  ++threadid;
45  }
46  assert(0 && "Target is not found in it's own SMP group!");
47  return -1;
48 }
49 
50 const struct rtos_type hwthread_rtos = {
51  .name = "hwthread",
52  .detect_rtos = hwthread_detect_rtos,
53  .create = hwthread_create,
54  .update_threads = hwthread_update_threads,
55  .get_thread_reg_list = hwthread_get_thread_reg_list,
56  .get_thread_reg = hwthread_get_thread_reg,
57  .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
58  .smp_init = hwthread_smp_init,
59  .set_reg = hwthread_set_reg,
60  .read_buffer = hwthread_read_buffer,
61  .write_buffer = hwthread_write_buffer,
62 };
63 
66 };
67 
68 static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num, threadid_t tid)
69 {
70  char tmp_str[HW_THREAD_NAME_STR_SIZE];
71 
72  memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);
73 
74  /* thread-id is the index 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);
81 
82  return ERROR_OK;
83 }
84 
85 static int hwthread_update_threads(struct rtos *rtos)
86 {
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  int64_t current_threadid = rtos->current_threadid; /* thread selected by GDB */
93  enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
94 
95  if (!rtos)
96  return -1;
97 
98  target = rtos->target;
99 
100  /* wipe out previous thread details if any */
102 
103  /* determine the number of "threads" */
104  if (target->smp) {
106  struct target *curr = head->target;
107 
108  if (!target_was_examined(curr) ||
109  curr->state == TARGET_UNAVAILABLE)
110  continue;
111 
112  ++thread_list_size;
113  }
114  } else
115  thread_list_size = 1;
116 
117  /* restore the threadid which is currently selected by GDB
118  * because rtos_free_threadlist() wipes out it
119  * (GDB thread id is 1-based indexing) */
120  if (current_threadid <= thread_list_size)
121  rtos->current_threadid = current_threadid;
122  else
123  LOG_TARGET_WARNING(target, "SMP node change, disconnect GDB from core/thread %" PRId64,
124  current_threadid);
125 
126  /* create space for new thread details */
127  rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
128 
129  if (target->smp) {
130  /* loop over all threads */
132  struct target *curr = head->target;
133 
134  if (!target_was_examined(curr) ||
135  curr->state == TARGET_UNAVAILABLE)
136  continue;
137 
138  threadid_t tid = threadid_from_target(curr);
139  hwthread_fill_thread(rtos, curr, threads_found, tid);
140 
141  /* find an interesting thread to set as current */
142  switch (current_reason) {
144  current_reason = curr->debug_reason;
145  current_thread = tid;
146  break;
148  /* single-step can only be overridden by itself */
149  if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
150  if (tid == rtos->current_threadid)
151  current_thread = tid;
152  }
153  break;
155  /* single-step overrides breakpoint */
156  if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
157  current_reason = curr->debug_reason;
158  current_thread = tid;
159  } else if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
160  /* multiple breakpoints, prefer gdbs' threadid */
161  if (tid == rtos->current_threadid)
162  current_thread = tid;
163  }
164  break;
166  /* breakpoint and single-step override watchpoint */
167  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
169  current_reason = curr->debug_reason;
170  current_thread = tid;
171  }
172  break;
173  case DBG_REASON_DBGRQ:
174  /* all other reasons override debug-request */
175  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
178  current_reason = curr->debug_reason;
179  current_thread = tid;
180  } else if (curr->debug_reason == DBG_REASON_DBGRQ) {
181  if (tid == rtos->current_threadid)
182  current_thread = tid;
183  }
184 
185  break;
186 
187  default:
188  break;
189  }
190 
191  threads_found++;
192  }
193  } else {
194  current_thread = 1;
196  threads_found++;
197  }
198 
199  rtos->thread_count = threads_found;
200 
201  /* we found an interesting thread, set it as current */
202  if (current_thread != 0)
204  else if (rtos->current_threadid != 0)
206  else
208 
209  LOG_TARGET_DEBUG(target, "current_thread=%" PRId64 ", threads_found=%d",
210  rtos->current_thread, threads_found);
211  return 0;
212 }
213 
214 static int hwthread_smp_init(struct target *target)
215 {
217 }
218 
219 static struct target *hwthread_find_thread(struct target *target, threadid_t thread_id)
220 {
221  /* Find the thread with that thread_id (index in SMP group plus 1)*/
222  if (!(target && target->smp))
223  return target;
224  struct target_list *head;
225  threadid_t tid = 1;
227  if (thread_id == tid)
228  return head->target;
229  ++tid;
230  }
231  return NULL;
232 }
233 
234 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
235  struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
236 {
237  if (!rtos)
238  return ERROR_FAIL;
239 
240  struct target *target = rtos->target;
241 
242  struct target *curr = hwthread_find_thread(target, thread_id);
243  if (!curr)
244  return ERROR_FAIL;
245 
246  if (!target_was_examined(curr))
247  return ERROR_FAIL;
248 
249  int reg_list_size;
250  struct reg **reg_list;
251  int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
253  if (retval != ERROR_OK)
254  return retval;
255 
256  int j = 0;
257  for (int i = 0; i < reg_list_size; i++) {
258  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
259  continue;
260  j++;
261  }
262  *rtos_reg_list_size = j;
263  *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
264  if (!*rtos_reg_list) {
265  free(reg_list);
266  return ERROR_FAIL;
267  }
268 
269  j = 0;
270  for (int i = 0; i < reg_list_size; i++) {
271  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
272  continue;
273  if (!reg_list[i]->valid) {
274  retval = reg_list[i]->type->get(reg_list[i]);
275  if (retval != ERROR_OK) {
276  LOG_TARGET_ERROR(curr, "Couldn't get register %s",
277  reg_list[i]->name);
278  free(reg_list);
279  free(*rtos_reg_list);
280  return retval;
281  }
282  }
283  (*rtos_reg_list)[j].number = reg_list[i]->number;
284  (*rtos_reg_list)[j].size = reg_list[i]->size;
285  memcpy((*rtos_reg_list)[j].value, reg_list[i]->value,
286  DIV_ROUND_UP(reg_list[i]->size, 8));
287  j++;
288  }
289  free(reg_list);
290 
291  return ERROR_OK;
292 }
293 
294 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
295  uint32_t reg_num, struct rtos_reg *rtos_reg)
296 {
297  if (!rtos)
298  return ERROR_FAIL;
299 
300  struct target *target = rtos->target;
301 
302  struct target *curr = hwthread_find_thread(target, thread_id);
303  if (!curr) {
304  LOG_TARGET_ERROR(target, "Couldn't find RTOS thread for id %" PRId64,
305  thread_id);
306  return ERROR_FAIL;
307  }
308 
309  if (!target_was_examined(curr)) {
310  LOG_TARGET_ERROR(curr, "Target hasn't been examined yet.");
311  return ERROR_FAIL;
312  }
313 
314  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
315  if (!reg) {
316  LOG_TARGET_ERROR(curr, "Couldn't find register %" PRIu32 " in thread %" PRId64,
317  reg_num, thread_id);
318  return ERROR_FAIL;
319  }
320 
321  if (reg->type->get(reg) != ERROR_OK)
322  return ERROR_FAIL;
323 
325  rtos_reg->size = reg->size;
326  unsigned int bytes = (reg->size + 7) / 8;
327  assert(bytes <= sizeof(rtos_reg->value));
328  memcpy(rtos_reg->value, reg->value, bytes);
329 
330  return ERROR_OK;
331 }
332 
333 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
334 {
335  if (!rtos)
336  return ERROR_FAIL;
337 
338  struct target *target = rtos->target;
339 
341  if (!curr)
342  return ERROR_FAIL;
343 
344  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
345  if (!reg)
346  return ERROR_FAIL;
347 
348  return reg->type->set(reg, reg_value);
349 }
350 
351 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
352 {
353  /* return an empty list, we don't have any symbols to look up */
354  *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
355  (*symbol_list)[0].symbol_name = NULL;
356  return 0;
357 }
358 
359 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
360 {
362 
363  struct target *curr = hwthread_find_thread(target, thread_id);
364  if (!curr)
365  return ERROR_FAIL;
366 
367  *p_target = curr;
368 
369  return ERROR_OK;
370 }
371 
372 static bool hwthread_detect_rtos(struct target *target)
373 {
374  /* always return 0, avoid auto-detection */
375  return false;
376 }
377 
378 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
379 {
380  if (packet[0] == 'H' && packet[1] == 'g') {
381  int64_t current_threadid;
382  sscanf(packet, "Hg%16" SCNx64, &current_threadid);
383 
385 
386  if (current_threadid > 0) {
387  struct target *curr = NULL;
388  if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
389  LOG_TARGET_ERROR(target, "hwthread: cannot find thread id %" PRId64,
390  current_threadid);
391  gdb_put_packet(connection, "E01", 3);
392  return ERROR_FAIL;
393  }
394  target->rtos->current_thread = current_threadid;
395  } else if (current_threadid == 0 || current_threadid == -1) {
397  }
398 
399  target->rtos->current_threadid = current_threadid;
400 
401  gdb_put_packet(connection, "OK", 2);
402  return ERROR_OK;
403  }
404 
405  return rtos_thread_packet(connection, packet, packet_size);
406 }
407 
408 static int hwthread_create(struct target *target)
409 {
410  LOG_TARGET_INFO(target, "Hardware thread awareness created");
411 
413  target->rtos->current_thread = 0;
417  return ERROR_OK;
418 }
419 
421  uint32_t size, uint8_t *buffer)
422 {
423  if (!rtos)
424  return ERROR_FAIL;
425 
426  struct target *target = rtos->target;
427 
429  if (!curr)
430  return ERROR_FAIL;
431 
432  return target_read_buffer(curr, address, size, buffer);
433 }
434 
436  uint32_t size, const uint8_t *buffer)
437 {
438  if (!rtos)
439  return ERROR_FAIL;
440 
441  struct target *target = rtos->target;
442 
444  if (!curr)
445  return ERROR_FAIL;
446 
447  return target_write_buffer(curr, address, size, buffer);
448 }
const char * name
Definition: armv4_5.c:76
uint64_t buffer
Pointer to data buffer to send over SPI.
Definition: dw-spi-helper.h:0
uint32_t size
Size of dw_spi_transaction::buffer.
Definition: dw-spi-helper.h:4
uint32_t address
Starting address. Sector aligned.
Definition: dw-spi-helper.h:0
int gdb_put_packet(struct connection *connection, const char *buffer, int len)
Definition: gdb_server.c:554
static struct target * get_target_from_connection(struct connection *connection)
Definition: gdb_server.h:35
static int hwthread_create(struct target *target)
Definition: hwthread.c:408
static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
Definition: hwthread.c:378
static bool hwthread_detect_rtos(struct target *target)
Definition: hwthread.c:372
static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: hwthread.c:420
#define HW_THREAD_NAME_STR_SIZE
Definition: hwthread.c:32
static int hwthread_update_threads(struct rtos *rtos)
Definition: hwthread.c:85
static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
Definition: hwthread.c:333
static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: hwthread.c:351
static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: hwthread.c:435
static struct target * hwthread_find_thread(struct target *target, threadid_t thread_id)
Definition: hwthread.c:219
const struct rtos_type hwthread_rtos
Definition: hwthread.c:50
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:294
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:234
static threadid_t threadid_from_target(const struct target *target)
Definition: hwthread.c:34
static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
Definition: hwthread.c:359
static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num, threadid_t tid)
Definition: hwthread.c:68
static int hwthread_smp_init(struct target *target)
Definition: hwthread.c:214
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_TARGET_INFO(target, fmt_str,...)
Definition: log.h:153
#define LOG_TARGET_WARNING(target, fmt_str,...)
Definition: log.h:159
#define ERROR_FAIL
Definition: log.h:174
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:162
#define LOG_TARGET_DEBUG(target, fmt_str,...)
Definition: log.h:150
#define ERROR_OK
Definition: log.h:168
struct reg * register_get_by_number(struct reg_cache *first, uint32_t reg_num, bool search_all)
Definition: register.c:28
int rtos_thread_packet(struct connection *connection, char const *packet, int packet_size)
Definition: rtos.c:352
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:698
int64_t threadid_t
Definition: rtos.h:14
struct target * target
Definition: rtt/rtt.c:26
#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:52
uint32_t number
Definition: rtos.h:53
uint8_t value[16]
Definition: rtos.h:55
uint32_t size
Definition: rtos.h:54
Definition: rtos.h:58
const char * name
Definition: rtos.h:59
Definition: rtos.h:35
int thread_count
Definition: rtos.h:46
int(* gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size)
Definition: rtos.h:47
struct thread_detail * thread_details
Definition: rtos.h:45
struct target * target
Definition: rtos.h:39
void * rtos_specific_params
Definition: rtos.h:49
int(* gdb_target_for_threadid)(struct connection *connection, int64_t thread_id, struct target **p_target)
Definition: rtos.h:48
threadid_t current_thread
Definition: rtos.h:44
int64_t current_threadid
Definition: rtos.h:42
Table should be terminated by an element with NULL in symbol_name.
Definition: rtos.h:22
struct target * target
Definition: target.h:217
Definition: target.h:119
enum target_debug_reason debug_reason
Definition: target.h:157
enum target_state state
Definition: target.h:160
struct reg_cache * reg_cache
Definition: target.h:161
struct list_head * smp_targets
Definition: target.h:191
struct rtos * rtos
Definition: target.h:186
unsigned int smp
Definition: target.h:190
char * extra_info_str
Definition: rtos.h:32
char * thread_name_str
Definition: rtos.h:31
bool exists
Definition: rtos.h:30
threadid_t threadid
Definition: rtos.h:29
int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: target.c:2351
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2416
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:1378
const char * debug_reason_name(const struct target *t)
Definition: target.c:256
target_debug_reason
Definition: target.h:71
@ DBG_REASON_UNDEFINED
Definition: target.h:80
@ DBG_REASON_DBGRQ
Definition: target.h:72
@ DBG_REASON_SINGLESTEP
Definition: target.h:76
@ DBG_REASON_WATCHPOINT
Definition: target.h:74
@ DBG_REASON_BREAKPOINT
Definition: target.h:73
@ REG_CLASS_GENERAL
Definition: target.h:115
static bool target_was_examined(const struct target *target)
Definition: target.h:432
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:236
@ TARGET_UNAVAILABLE
Definition: target.h:61
#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