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_value(struct rtos *rtos, int64_t thread_id,
21  uint32_t reg_num, uint32_t *size, uint8_t **value);
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 static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id);
32 
33 #define HW_THREAD_NAME_STR_SIZE (32)
34 
35 static inline threadid_t threadid_from_target(const struct target *target)
36 {
37  if (!target->smp)
38  return 1;
39 
40  threadid_t threadid = 1;
41  struct target_list *head;
43  if (target == head->target)
44  return threadid;
45  ++threadid;
46  }
47  assert(0 && "Target is not found in it's own SMP group!");
48  return -1;
49 }
50 
51 const struct rtos_type hwthread_rtos = {
52  .name = "hwthread",
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_value = hwthread_get_thread_reg_value,
58  .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
59  .smp_init = hwthread_smp_init,
60  .set_reg = hwthread_set_reg,
61  .read_buffer = hwthread_read_buffer,
62  .write_buffer = hwthread_write_buffer,
63  .needs_fake_step = hwthread_needs_fake_step
64 };
65 
68 };
69 
70 static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num, threadid_t tid)
71 {
72  char tmp_str[HW_THREAD_NAME_STR_SIZE];
73 
74  memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);
75 
76  /* thread-id is the index of this core inside the SMP group plus 1 */
77  rtos->thread_details[thread_num].threadid = tid;
78  /* create the thread name */
79  rtos->thread_details[thread_num].exists = true;
80  rtos->thread_details[thread_num].thread_name_str = strdup(target_name(curr));
81  snprintf(tmp_str, HW_THREAD_NAME_STR_SIZE-1, "state: %s", debug_reason_name(curr));
82  rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str);
83 
84  return ERROR_OK;
85 }
86 
87 static int hwthread_update_threads(struct rtos *rtos)
88 {
89  int threads_found = 0;
90  int thread_list_size = 0;
91  struct target_list *head;
92  struct target *target;
93  int64_t current_thread = 0;
94  int64_t current_threadid = rtos->current_threadid; /* thread selected by GDB */
95  enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
96 
97  if (!rtos)
98  return -1;
99 
100  target = rtos->target;
101 
102  /* wipe out previous thread details if any */
104 
105  /* determine the number of "threads" */
106  if (target->smp) {
108  struct target *curr = head->target;
109 
110  if (!target_was_examined(curr) ||
111  curr->state == TARGET_UNAVAILABLE)
112  continue;
113 
114  ++thread_list_size;
115  }
116  } else
117  thread_list_size = 1;
118 
119  /* restore the threadid which is currently selected by GDB
120  * because rtos_free_threadlist() wipes out it
121  * (GDB thread id is 1-based indexing) */
122  if (current_threadid <= thread_list_size)
123  rtos->current_threadid = current_threadid;
124  else
125  LOG_TARGET_WARNING(target, "SMP node change, disconnect GDB from core/thread %" PRId64,
126  current_threadid);
127 
128  /* create space for new thread details */
129  rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
130 
131  if (target->smp) {
132  /* loop over all threads */
134  struct target *curr = head->target;
135 
136  if (!target_was_examined(curr) ||
137  curr->state == TARGET_UNAVAILABLE)
138  continue;
139 
140  threadid_t tid = threadid_from_target(curr);
141  hwthread_fill_thread(rtos, curr, threads_found, tid);
142 
143  /* find an interesting thread to set as current */
144  switch (current_reason) {
146  current_reason = curr->debug_reason;
147  current_thread = tid;
148  break;
150  /* single-step can only be overridden by itself */
151  if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
152  if (tid == rtos->current_threadid)
153  current_thread = tid;
154  }
155  break;
157  /* single-step overrides breakpoint */
158  if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
159  current_reason = curr->debug_reason;
160  current_thread = tid;
161  } else if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
162  /* multiple breakpoints, prefer gdbs' threadid */
163  if (tid == rtos->current_threadid)
164  current_thread = tid;
165  }
166  break;
168  /* breakpoint and single-step override watchpoint */
169  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
171  current_reason = curr->debug_reason;
172  current_thread = tid;
173  }
174  break;
175  case DBG_REASON_DBGRQ:
176  /* all other reasons override debug-request */
177  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
180  current_reason = curr->debug_reason;
181  current_thread = tid;
182  } else if (curr->debug_reason == DBG_REASON_DBGRQ) {
183  if (tid == rtos->current_threadid)
184  current_thread = tid;
185  }
186 
187  break;
188 
189  default:
190  break;
191  }
192 
193  threads_found++;
194  }
195  } else {
196  current_thread = 1;
198  threads_found++;
199  }
200 
201  rtos->thread_count = threads_found;
202 
203  /* we found an interesting thread, set it as current */
204  if (current_thread != 0)
206  else if (rtos->current_threadid != 0)
208  else
210 
211  LOG_TARGET_DEBUG(target, "current_thread=%" PRId64 ", threads_found=%d",
212  rtos->current_thread, threads_found);
213  return 0;
214 }
215 
216 static int hwthread_smp_init(struct target *target)
217 {
219 }
220 
221 static struct target *hwthread_find_thread(struct target *target, threadid_t thread_id)
222 {
223  /* Find the thread with that thread_id (index in SMP group plus 1)*/
224  if (!(target && target->smp))
225  return target;
226  struct target_list *head;
227  threadid_t tid = 1;
229  if (thread_id == tid)
230  return head->target;
231  ++tid;
232  }
233  return NULL;
234 }
235 
236 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
237  struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
238 {
239  if (!rtos)
240  return ERROR_FAIL;
241 
242  struct target *target = rtos->target;
243 
244  struct target *curr = hwthread_find_thread(target, thread_id);
245  if (!curr)
246  return ERROR_FAIL;
247 
248  if (!target_was_examined(curr))
249  return ERROR_FAIL;
250 
251  int reg_list_size;
252  struct reg **reg_list;
253  int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
255  if (retval != ERROR_OK)
256  return retval;
257 
258  int j = 0;
259  for (int i = 0; i < reg_list_size; i++) {
260  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
261  continue;
262  j++;
263  }
264  *rtos_reg_list_size = j;
265  *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
266  if (!*rtos_reg_list) {
267  free(reg_list);
268  return ERROR_FAIL;
269  }
270 
271  j = 0;
272  for (int i = 0; i < reg_list_size; i++) {
273  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
274  continue;
275  if (!reg_list[i]->valid) {
276  retval = reg_list[i]->type->get(reg_list[i]);
277  if (retval != ERROR_OK) {
278  LOG_TARGET_ERROR(curr, "Couldn't get register %s",
279  reg_list[i]->name);
280  free(reg_list);
281  free(*rtos_reg_list);
282  return retval;
283  }
284  }
285  (*rtos_reg_list)[j].number = reg_list[i]->number;
286  (*rtos_reg_list)[j].size = reg_list[i]->size;
287  memcpy((*rtos_reg_list)[j].value, reg_list[i]->value,
288  DIV_ROUND_UP(reg_list[i]->size, 8));
289  j++;
290  }
291  free(reg_list);
292 
293  return ERROR_OK;
294 }
295 
296 static int hwthread_get_thread_reg_value(struct rtos *rtos, int64_t thread_id,
297  uint32_t reg_num, uint32_t *size, uint8_t **value)
298 {
299  if (!rtos)
300  return ERROR_FAIL;
301 
302  struct target *target = rtos->target;
303 
304  struct target *curr = hwthread_find_thread(target, thread_id);
305  if (!curr) {
306  LOG_TARGET_ERROR(target, "Couldn't find RTOS thread for id %" PRId64,
307  thread_id);
308  return ERROR_FAIL;
309  }
310 
311  if (!target_was_examined(curr)) {
312  LOG_TARGET_ERROR(curr, "Target hasn't been examined yet.");
313  return ERROR_FAIL;
314  }
315 
316  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
317  if (!reg) {
318  LOG_TARGET_ERROR(curr, "Couldn't find register %" PRIu32 " in thread %" PRId64,
319  reg_num, thread_id);
320  return ERROR_FAIL;
321  }
322 
323  if (reg->type->get(reg) != ERROR_OK)
324  return ERROR_FAIL;
325 
326  *size = reg->size;
327  unsigned int bytes = DIV_ROUND_UP(reg->size, 8);
328  *value = malloc(bytes);
329  if (!*value) {
330  LOG_ERROR("Failed to allocate memory for %d-bit register.", reg->size);
331  return ERROR_FAIL;
332  }
333  memcpy(*value, reg->value, bytes);
334 
335  return ERROR_OK;
336 }
337 
338 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
339 {
340  if (!rtos)
341  return ERROR_FAIL;
342 
343  struct target *target = rtos->target;
344 
346  if (!curr)
347  return ERROR_FAIL;
348 
349  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
350  if (!reg)
351  return ERROR_FAIL;
352 
353  return reg->type->set(reg, reg_value);
354 }
355 
356 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
357 {
358  /* return an empty list, we don't have any symbols to look up */
359  *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
360  (*symbol_list)[0].symbol_name = NULL;
361  return 0;
362 }
363 
364 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
365 {
367 
368  struct target *curr = hwthread_find_thread(target, thread_id);
369  if (!curr)
370  return ERROR_FAIL;
371 
372  *p_target = curr;
373 
374  return ERROR_OK;
375 }
376 
377 static bool hwthread_detect_rtos(struct target *target)
378 {
379  /* always return 0, avoid auto-detection */
380  return false;
381 }
382 
383 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
384 {
385  if (packet[0] == 'H' && packet[1] == 'g') {
386  int64_t current_threadid;
387  sscanf(packet, "Hg%16" SCNx64, &current_threadid);
388 
390 
391  if (current_threadid > 0) {
392  struct target *curr = NULL;
393  if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
394  LOG_TARGET_ERROR(target, "hwthread: cannot find thread id %" PRId64,
395  current_threadid);
396  gdb_put_packet(connection, "E01", 3);
397  return ERROR_FAIL;
398  }
399  target->rtos->current_thread = current_threadid;
400  } else if (current_threadid == 0 || current_threadid == -1) {
402  }
403 
404  target->rtos->current_threadid = current_threadid;
405 
406  gdb_put_packet(connection, "OK", 2);
407  return ERROR_OK;
408  }
409 
410  return rtos_thread_packet(connection, packet, packet_size);
411 }
412 
413 static int hwthread_create(struct target *target)
414 {
415  LOG_TARGET_INFO(target, "Hardware thread awareness created");
416 
418  target->rtos->current_thread = 0;
422  return ERROR_OK;
423 }
424 
426  uint32_t size, uint8_t *buffer)
427 {
428  if (!rtos)
429  return ERROR_FAIL;
430 
431  struct target *target = rtos->target;
432 
434  if (!curr)
435  return ERROR_FAIL;
436 
437  return target_read_buffer(curr, address, size, buffer);
438 }
439 
441  uint32_t size, const uint8_t *buffer)
442 {
443  if (!rtos)
444  return ERROR_FAIL;
445 
446  struct target *target = rtos->target;
447 
449  if (!curr)
450  return ERROR_FAIL;
451 
452  return target_write_buffer(curr, address, size, buffer);
453 }
454 
455 bool hwthread_needs_fake_step(struct target *target, int64_t thread_id)
456 {
457  return false;
458 }
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:413
static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
Definition: hwthread.c:383
static bool hwthread_detect_rtos(struct target *target)
Definition: hwthread.c:377
static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: hwthread.c:425
#define HW_THREAD_NAME_STR_SIZE
Definition: hwthread.c:33
static int hwthread_update_threads(struct rtos *rtos)
Definition: hwthread.c:87
static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
Definition: hwthread.c:338
static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: hwthread.c:356
static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: hwthread.c:440
static struct target * hwthread_find_thread(struct target *target, threadid_t thread_id)
Definition: hwthread.c:221
const struct rtos_type hwthread_rtos
Definition: hwthread.c:51
static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id)
Definition: hwthread.c:455
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:236
static threadid_t threadid_from_target(const struct target *target)
Definition: hwthread.c:35
static int hwthread_get_thread_reg_value(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, uint32_t *size, uint8_t **value)
Definition: hwthread.c:296
static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
Definition: hwthread.c:364
static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num, threadid_t tid)
Definition: hwthread.c:70
static int hwthread_smp_init(struct target *target)
Definition: hwthread.c:216
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_TARGET_INFO(target, fmt_str,...)
Definition: log.h:154
#define LOG_TARGET_WARNING(target, fmt_str,...)
Definition: log.h:160
#define ERROR_FAIL
Definition: log.h:175
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:163
#define LOG_TARGET_DEBUG(target, fmt_str,...)
Definition: log.h:151
#define LOG_ERROR(expr ...)
Definition: log.h:134
#define ERROR_OK
Definition: log.h:169
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:354
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:725
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
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:279
#define NULL
Definition: usb.h:16