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