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