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