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);
27 static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
28  uint32_t size, uint8_t *buffer);
29 static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
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_WARNING("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
158  /* multiple breakpoints, prefer gdbs' threadid */
159  if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
160  if (tid == rtos->current_threadid)
161  current_thread = tid;
162  }
163  break;
165  /* breakpoint and single-step override watchpoint */
166  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
168  current_reason = curr->debug_reason;
169  current_thread = tid;
170  }
171  break;
172  case DBG_REASON_DBGRQ:
173  /* all other reasons override debug-request */
174  if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
177  current_reason = curr->debug_reason;
178  current_thread = tid;
179  } else
180  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_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
210  return 0;
211 }
212 
213 static int hwthread_smp_init(struct target *target)
214 {
216 }
217 
218 static struct target *hwthread_find_thread(struct target *target, threadid_t thread_id)
219 {
220  /* Find the thread with that thread_id (index in SMP group plus 1)*/
221  if (!(target && target->smp))
222  return target;
223  struct target_list *head;
224  threadid_t tid = 1;
226  if (thread_id == tid)
227  return head->target;
228  ++tid;
229  }
230  return NULL;
231 }
232 
233 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
234  struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
235 {
236  if (!rtos)
237  return ERROR_FAIL;
238 
239  struct target *target = rtos->target;
240 
241  struct target *curr = hwthread_find_thread(target, thread_id);
242  if (!curr)
243  return ERROR_FAIL;
244 
245  if (!target_was_examined(curr))
246  return ERROR_FAIL;
247 
248  int reg_list_size;
249  struct reg **reg_list;
250  int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
252  if (retval != ERROR_OK)
253  return retval;
254 
255  int j = 0;
256  for (int i = 0; i < reg_list_size; i++) {
257  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
258  continue;
259  j++;
260  }
261  *rtos_reg_list_size = j;
262  *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
263  if (!*rtos_reg_list) {
264  free(reg_list);
265  return ERROR_FAIL;
266  }
267 
268  j = 0;
269  for (int i = 0; i < reg_list_size; i++) {
270  if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden)
271  continue;
272  if (!reg_list[i]->valid) {
273  retval = reg_list[i]->type->get(reg_list[i]);
274  if (retval != ERROR_OK) {
275  LOG_ERROR("Couldn't get register %s.", 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_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id);
303  return ERROR_FAIL;
304  }
305 
306  if (!target_was_examined(curr)) {
307  LOG_TARGET_ERROR(curr, "Target hasn't been examined yet.");
308  return ERROR_FAIL;
309  }
310 
311  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
312  if (!reg) {
313  LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num,
314  thread_id);
315  return ERROR_FAIL;
316  }
317 
318  if (reg->type->get(reg) != ERROR_OK)
319  return ERROR_FAIL;
320 
322  rtos_reg->size = reg->size;
323  unsigned int bytes = (reg->size + 7) / 8;
324  assert(bytes <= sizeof(rtos_reg->value));
325  memcpy(rtos_reg->value, reg->value, bytes);
326 
327  return ERROR_OK;
328 }
329 
330 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
331 {
332  if (!rtos)
333  return ERROR_FAIL;
334 
335  struct target *target = rtos->target;
336 
338  if (!curr)
339  return ERROR_FAIL;
340 
341  struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
342  if (!reg)
343  return ERROR_FAIL;
344 
345  return reg->type->set(reg, reg_value);
346 }
347 
348 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
349 {
350  /* return an empty list, we don't have any symbols to look up */
351  *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
352  (*symbol_list)[0].symbol_name = NULL;
353  return 0;
354 }
355 
356 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
357 {
359 
360  struct target *curr = hwthread_find_thread(target, thread_id);
361  if (!curr)
362  return ERROR_FAIL;
363 
364  *p_target = curr;
365 
366  return ERROR_OK;
367 }
368 
369 static bool hwthread_detect_rtos(struct target *target)
370 {
371  /* always return 0, avoid auto-detection */
372  return false;
373 }
374 
375 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
376 {
378 
379  struct target *curr = NULL;
380  int64_t current_threadid;
381 
382  if (packet[0] == 'H' && packet[1] == 'g') {
383  sscanf(packet, "Hg%16" SCNx64, &current_threadid);
384 
385  if (current_threadid > 0) {
386  if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
387  LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid);
388  gdb_put_packet(connection, "E01", 3);
389  return ERROR_FAIL;
390  }
391  target->rtos->current_thread = current_threadid;
392  } else if (current_threadid == 0 || current_threadid == -1) {
394  }
395 
396  target->rtos->current_threadid = current_threadid;
397 
398  gdb_put_packet(connection, "OK", 2);
399  return ERROR_OK;
400  }
401 
402  return rtos_thread_packet(connection, packet, packet_size);
403 }
404 
405 static int hwthread_create(struct target *target)
406 {
407  LOG_INFO("Hardware thread awareness created");
408 
410  target->rtos->current_thread = 0;
414  return 0;
415 }
416 
417 static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
418  uint32_t size, uint8_t *buffer)
419 {
420  if (!rtos)
421  return ERROR_FAIL;
422 
423  struct target *target = rtos->target;
424 
426  if (!curr)
427  return ERROR_FAIL;
428 
429  return target_read_buffer(curr, address, size, buffer);
430 }
431 
432 static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
433  uint32_t size, const uint8_t *buffer)
434 {
435  if (!rtos)
436  return ERROR_FAIL;
437 
438  struct target *target = rtos->target;
439 
441  if (!curr)
442  return ERROR_FAIL;
443 
444  return target_write_buffer(curr, address, size, buffer);
445 }
const char * name
Definition: armv4_5.c:76
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:405
static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
Definition: hwthread.c:375
static bool hwthread_detect_rtos(struct target *target)
Definition: hwthread.c:369
static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: hwthread.c:417
#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:330
static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: hwthread.c:348
static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: hwthread.c:432
static struct target * hwthread_find_thread(struct target *target, threadid_t thread_id)
Definition: hwthread.c:218
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:233
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:356
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:213
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_WARNING(expr ...)
Definition: log.h:129
#define ERROR_FAIL
Definition: log.h:170
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:158
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_INFO(expr ...)
Definition: log.h:126
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
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
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
#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