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  continue;
110 
111  ++thread_list_size;
112  }
113  } else
114  thread_list_size = 1;
115 
116  /* restore the threadid which is currently selected by GDB
117  * because rtos_free_threadlist() wipes out it
118  * (GDB thread id is 1-based indexing) */
119  if (current_threadid <= thread_list_size)
120  rtos->current_threadid = current_threadid;
121  else
122  LOG_TARGET_WARNING(target, "SMP node change, disconnect GDB from core/thread %" PRId64,
123  current_threadid);
124 
125  /* create space for new thread details */
126  rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
127 
128  if (target->smp) {
129  /* loop over all threads */
131  struct target *curr = head->target;
132 
133  if (!target_was_examined(curr))
134  continue;
135 
136  threadid_t tid = threadid_from_target(curr);
137  hwthread_fill_thread(rtos, curr, threads_found, tid);
138 
139  /* find an interesting thread to set as current */
140  switch (current_reason) {
142  current_reason = curr->debug_reason;
143  current_thread = tid;
144  break;
146  /* single-step can only be overridden by itself */
147  if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
148  if (tid == rtos->current_threadid)
149  current_thread = tid;
150  }
151  break;
153  /* single-step overrides breakpoint */
154  if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
155  current_reason = curr->debug_reason;
156  current_thread = tid;
157  } else if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
158  /* multiple breakpoints, prefer gdbs' threadid */
159  if (tid == rtos->current_threadid)
160  current_thread = tid;
161  }
162  break;
164  /* breakpoint and single-step override watchpoint */
165  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
167  current_reason = curr->debug_reason;
168  current_thread = tid;
169  }
170  break;
171  case DBG_REASON_DBGRQ:
172  /* all other reasons override debug-request */
173  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
176  current_reason = curr->debug_reason;
177  current_thread = tid;
178  } else if (curr->debug_reason == DBG_REASON_DBGRQ) {
179  if (tid == rtos->current_threadid)
180  current_thread = tid;
181  }
182 
183  break;
184 
185  default:
186  break;
187  }
188 
189  threads_found++;
190  }
191  } else {
192  current_thread = 1;
194  threads_found++;
195  }
196 
197  rtos->thread_count = threads_found;
198 
199  /* we found an interesting thread, set it as current */
200  if (current_thread != 0)
202  else if (rtos->current_threadid != 0)
204  else
206 
207  LOG_TARGET_DEBUG(target, "%s current_thread=%i", __func__,
208  (int)rtos->current_thread);
209  return 0;
210 }
211 
212 static int hwthread_smp_init(struct target *target)
213 {
215 }
216 
217 static struct target *hwthread_find_thread(struct target *target, threadid_t thread_id)
218 {
219  /* Find the thread with that thread_id (index in SMP group plus 1)*/
220  if (!(target && target->smp))
221  return target;
222  struct target_list *head;
223  threadid_t tid = 1;
225  if (thread_id == tid)
226  return head->target;
227  ++tid;
228  }
229  return NULL;
230 }
231 
232 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
233  struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
234 {
235  if (!rtos)
236  return ERROR_FAIL;
237 
238  struct target *target = rtos->target;
239 
240  struct target *curr = hwthread_find_thread(target, thread_id);
241  if (!curr)
242  return ERROR_FAIL;
243 
244  if (!target_was_examined(curr))
245  return ERROR_FAIL;
246 
247  int reg_list_size;
248  struct reg **reg_list;
249  int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
251  if (retval != ERROR_OK)
252  return retval;
253 
254  int j = 0;
255  for (int i = 0; i < reg_list_size; i++) {
256  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
257  continue;
258  j++;
259  }
260  *rtos_reg_list_size = j;
261  *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
262  if (!*rtos_reg_list) {
263  free(reg_list);
264  return ERROR_FAIL;
265  }
266 
267  j = 0;
268  for (int i = 0; i < reg_list_size; i++) {
269  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
270  continue;
271  if (!reg_list[i]->valid) {
272  retval = reg_list[i]->type->get(reg_list[i]);
273  if (retval != ERROR_OK) {
274  LOG_TARGET_ERROR(curr, "Couldn't get register %s",
275  reg_list[i]->name);
276  free(reg_list);
277  free(*rtos_reg_list);
278  return retval;
279  }
280  }
281  (*rtos_reg_list)[j].number = reg_list[i]->number;
282  (*rtos_reg_list)[j].size = reg_list[i]->size;
283  memcpy((*rtos_reg_list)[j].value, reg_list[i]->value,
284  DIV_ROUND_UP(reg_list[i]->size, 8));
285  j++;
286  }
287  free(reg_list);
288 
289  return ERROR_OK;
290 }
291 
292 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
293  uint32_t reg_num, struct rtos_reg *rtos_reg)
294 {
295  if (!rtos)
296  return ERROR_FAIL;
297 
298  struct target *target = rtos->target;
299 
300  struct target *curr = hwthread_find_thread(target, thread_id);
301  if (!curr) {
302  LOG_TARGET_ERROR(target, "Couldn't find RTOS thread for id %" PRId64,
303  thread_id);
304  return ERROR_FAIL;
305  }
306 
307  if (!target_was_examined(curr)) {
308  LOG_TARGET_ERROR(curr, "Target hasn't been examined yet.");
309  return ERROR_FAIL;
310  }
311 
312  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
313  if (!reg) {
314  LOG_TARGET_ERROR(curr, "Couldn't find register %" PRIu32 " in thread %" PRId64,
315  reg_num, thread_id);
316  return ERROR_FAIL;
317  }
318 
319  if (reg->type->get(reg) != ERROR_OK)
320  return ERROR_FAIL;
321 
323  rtos_reg->size = reg->size;
324  unsigned int bytes = (reg->size + 7) / 8;
325  assert(bytes <= sizeof(rtos_reg->value));
326  memcpy(rtos_reg->value, reg->value, bytes);
327 
328  return ERROR_OK;
329 }
330 
331 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
332 {
333  if (!rtos)
334  return ERROR_FAIL;
335 
336  struct target *target = rtos->target;
337 
339  if (!curr)
340  return ERROR_FAIL;
341 
342  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
343  if (!reg)
344  return ERROR_FAIL;
345 
346  return reg->type->set(reg, reg_value);
347 }
348 
349 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
350 {
351  /* return an empty list, we don't have any symbols to look up */
352  *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
353  (*symbol_list)[0].symbol_name = NULL;
354  return 0;
355 }
356 
357 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
358 {
360 
361  struct target *curr = hwthread_find_thread(target, thread_id);
362  if (!curr)
363  return ERROR_FAIL;
364 
365  *p_target = curr;
366 
367  return ERROR_OK;
368 }
369 
370 static bool hwthread_detect_rtos(struct target *target)
371 {
372  /* always return 0, avoid auto-detection */
373  return false;
374 }
375 
376 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
377 {
378  if (packet[0] == 'H' && packet[1] == 'g') {
379  int64_t current_threadid;
380  sscanf(packet, "Hg%16" SCNx64, &current_threadid);
381 
383 
384  if (current_threadid > 0) {
385  struct target *curr = NULL;
386  if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
387  LOG_TARGET_ERROR(target, "hwthread: cannot find thread id %" PRId64,
388  current_threadid);
389  gdb_put_packet(connection, "E01", 3);
390  return ERROR_FAIL;
391  }
392  target->rtos->current_thread = current_threadid;
393  } else if (current_threadid == 0 || current_threadid == -1) {
395  }
396 
397  target->rtos->current_threadid = current_threadid;
398 
399  gdb_put_packet(connection, "OK", 2);
400  return ERROR_OK;
401  }
402 
403  return rtos_thread_packet(connection, packet, packet_size);
404 }
405 
406 static int hwthread_create(struct target *target)
407 {
408  LOG_TARGET_INFO(target, "Hardware thread awareness created");
409 
411  target->rtos->current_thread = 0;
415  return 0;
416 }
417 
419  uint32_t size, uint8_t *buffer)
420 {
421  if (!rtos)
422  return ERROR_FAIL;
423 
424  struct target *target = rtos->target;
425 
427  if (!curr)
428  return ERROR_FAIL;
429 
430  return target_read_buffer(curr, address, size, buffer);
431 }
432 
434  uint32_t size, const uint8_t *buffer)
435 {
436  if (!rtos)
437  return ERROR_FAIL;
438 
439  struct target *target = rtos->target;
440 
442  if (!curr)
443  return ERROR_FAIL;
444 
445  return target_write_buffer(curr, address, size, buffer);
446 }
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:525
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:406
static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
Definition: hwthread.c:376
static bool hwthread_detect_rtos(struct target *target)
Definition: hwthread.c:370
static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: hwthread.c:418
#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:331
static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: hwthread.c:349
static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: hwthread.c:433
static struct target * hwthread_find_thread(struct target *target, threadid_t thread_id)
Definition: hwthread.c:217
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:292
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:232
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:357
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:212
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_TARGET_INFO(target, fmt_str,...)
Definition: log.h:152
#define LOG_TARGET_WARNING(target, fmt_str,...)
Definition: log.h:158
#define ERROR_FAIL
Definition: log.h:173
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:161
#define LOG_TARGET_DEBUG(target, fmt_str,...)
Definition: log.h:149
#define ERROR_OK
Definition: log.h:167
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:331
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:695
int64_t threadid_t
Definition: rtos.h:15
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: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:214
Definition: target.h:116
enum target_debug_reason debug_reason
Definition: target.h:154
struct reg_cache * reg_cache
Definition: target.h:158
struct list_head * smp_targets
Definition: target.h:188
struct rtos * rtos
Definition: target.h:183
unsigned int smp
Definition: target.h:187
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:2342
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2407
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:1368
const char * debug_reason_name(const struct target *t)
Definition: target.c:247
target_debug_reason
Definition: target.h:68
@ DBG_REASON_UNDEFINED
Definition: target.h:77
@ DBG_REASON_DBGRQ
Definition: target.h:69
@ DBG_REASON_SINGLESTEP
Definition: target.h:73
@ DBG_REASON_WATCHPOINT
Definition: target.h:71
@ DBG_REASON_BREAKPOINT
Definition: target.h:70
@ REG_CLASS_GENERAL
Definition: target.h:112
static bool target_was_examined(const struct target *target)
Definition: target.h:436
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233
#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