OpenOCD
riot.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2015 by Daniel Krebs *
5  * Daniel Krebs - github@daniel-krebs.net *
6  ***************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11 
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "rtos.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "target/armv7m.h"
20 #include "rtos_riot_stackings.h"
21 
22 static bool riot_detect_rtos(struct target *target);
23 static int riot_create(struct target *target);
24 static int riot_update_threads(struct rtos *rtos);
25 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
26  struct rtos_reg **reg_list, int *num_regs);
27 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
28 
30  int value;
31  const char *desc;
32 };
33 
34 /* refer RIOT sched.h */
35 static const struct riot_thread_state riot_thread_states[] = {
36  { 0, "Stopped" },
37  { 1, "Zombie" },
38  { 2, "Sleeping" },
39  { 3, "Blocked mutex" },
40  { 4, "Blocked receive" },
41  { 5, "Blocked send" },
42  { 6, "Blocked reply" },
43  { 7, "Blocked any flag" },
44  { 8, "Blocked all flags" },
45  { 9, "Blocked mbox" },
46  { 10, "Blocked condition" },
47  { 11, "Running" },
48  { 12, "Pending" },
49 };
50 #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
51 
52 struct riot_params {
53  const char *target_name;
54  unsigned char thread_sp_offset;
55  unsigned char thread_status_offset;
56 };
57 
58 static const struct riot_params riot_params_list[] = {
59  {
60  "cortex_m", /* target_name */
61  0x00, /* thread_sp_offset */
62  0x04, /* thread_status_offset */
63  },
64  { /* STLink */
65  "hla_target", /* target_name */
66  0x00, /* thread_sp_offset */
67  0x04, /* thread_status_offset */
68  }
69 };
70 #define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list)
71 
72 /* Initialize in riot_create() depending on architecture */
74 
81 };
82 
83 struct riot_symbol {
84  const char *const name;
85  bool optional;
86 };
87 
88 /* refer RIOT core/sched.c */
89 static struct riot_symbol const riot_symbol_list[] = {
90  {"sched_threads", false},
91  {"sched_num_threads", false},
92  {"sched_active_pid", false},
93  {"max_threads", false},
94  {"_tcb_name_offset", true},
95  {NULL, false}
96 };
97 
98 const struct rtos_type riot_rtos = {
99  .name = "RIOT",
100  .detect_rtos = riot_detect_rtos,
101  .create = riot_create,
102  .update_threads = riot_update_threads,
103  .get_thread_reg_list = riot_get_thread_reg_list,
104  .get_symbol_list_to_lookup = riot_get_symbol_list_to_lookup,
105 };
106 
107 static int riot_update_threads(struct rtos *rtos)
108 {
109  int retval;
110  int tasks_found = 0;
111  const struct riot_params *param;
112 
113  if (!rtos)
114  return ERROR_FAIL;
115 
117  return ERROR_FAIL;
118 
119  param = (const struct riot_params *)rtos->rtos_specific_params;
120 
121  if (!rtos->symbols) {
122  LOG_ERROR("No symbols for RIOT");
123  return ERROR_FAIL;
124  }
125 
126  if (rtos->symbols[RIOT_THREADS_BASE].address == 0) {
127  LOG_ERROR("Can't find symbol `%s`",
129  return ERROR_FAIL;
130  }
131 
132  /* wipe out previous thread details if any */
134 
135  /* Reset values */
136  rtos->current_thread = 0;
137  rtos->thread_count = 0;
138 
139  /* read the current thread id */
140  int16_t active_pid = 0;
141  retval = target_read_u16(rtos->target,
143  (uint16_t *)&active_pid);
144  if (retval != ERROR_OK) {
145  LOG_ERROR("Can't read symbol `%s`",
147  return retval;
148  }
149  rtos->current_thread = active_pid;
150 
151  /* read the current thread count
152  * It's `int` in RIOT, but this is Cortex M* only anyway */
153  int32_t thread_count = 0;
154  retval = target_read_u16(rtos->target,
156  (uint16_t *)&thread_count);
157  if (retval != ERROR_OK) {
158  LOG_ERROR("Can't read symbol `%s`",
160  return retval;
161  }
162 
163  /* read the maximum number of threads */
164  uint8_t max_threads = 0;
165  retval = target_read_u8(rtos->target,
167  &max_threads);
168  if (retval != ERROR_OK) {
169  LOG_ERROR("Can't read symbol `%s`",
171  return retval;
172  }
173  if (thread_count > max_threads) {
174  LOG_ERROR("Thread count is invalid");
175  return ERROR_FAIL;
176  }
177  rtos->thread_count = thread_count;
178 
179  /* Base address of thread array */
180  uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
181 
182  /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled
183  * with DEVELHELP, so there are no thread names */
184  uint8_t name_offset = 0;
185  if (rtos->symbols[RIOT_NAME_OFFSET].address != 0) {
186  retval = target_read_u8(rtos->target,
188  &name_offset);
189  if (retval != ERROR_OK) {
190  LOG_ERROR("Can't read symbol `%s`",
192  return retval;
193  }
194  }
195 
196  /* Allocate memory for thread description */
197  rtos->thread_details = calloc(thread_count, sizeof(struct thread_detail));
198  if (!rtos->thread_details) {
199  LOG_ERROR("RIOT: out of memory");
200  return ERROR_FAIL;
201  }
202 
203  /* Buffer for thread names, maximum to display is 32 */
204  char buffer[32];
205 
206  for (unsigned int i = 0; i < max_threads; i++) {
207  if (tasks_found == rtos->thread_count)
208  break;
209 
210  /* get pointer to tcb_t */
211  uint32_t tcb_pointer = 0;
212  retval = target_read_u32(rtos->target,
213  threads_base + (i * 4),
214  &tcb_pointer);
215  if (retval != ERROR_OK) {
216  LOG_ERROR("Can't parse `%s`",
218  goto error;
219  }
220 
221  if (tcb_pointer == 0) {
222  /* PID unused */
223  continue;
224  }
225 
226  /* Index is PID */
227  rtos->thread_details[tasks_found].threadid = i;
228 
229  /* read thread state */
230  uint8_t status = 0;
231  retval = target_read_u8(rtos->target,
232  tcb_pointer + param->thread_status_offset,
233  &status);
234  if (retval != ERROR_OK) {
235  LOG_ERROR("Can't parse `%s`",
237  goto error;
238  }
239 
240  /* Search for state */
241  unsigned int k;
242  for (k = 0; k < RIOT_NUM_STATES; k++) {
243  if (riot_thread_states[k].value == status)
244  break;
245  }
246 
247  /* Copy state string */
248  if (k >= RIOT_NUM_STATES) {
249  rtos->thread_details[tasks_found].extra_info_str =
250  strdup("unknown state");
251  } else {
252  rtos->thread_details[tasks_found].extra_info_str =
253  strdup(riot_thread_states[k].desc);
254  }
255 
256  if (!rtos->thread_details[tasks_found].extra_info_str) {
257  LOG_ERROR("RIOT: out of memory");
258  retval = ERROR_FAIL;
259  goto error;
260  }
261 
262  /* Thread names are only available if compiled with DEVELHELP */
263  if (name_offset != 0) {
264  uint32_t name_pointer = 0;
265  retval = target_read_u32(rtos->target,
266  tcb_pointer + name_offset,
267  &name_pointer);
268  if (retval != ERROR_OK) {
269  LOG_ERROR("Can't parse `%s`",
271  goto error;
272  }
273 
274  /* read thread name */
275  retval = target_read_buffer(rtos->target,
276  name_pointer,
277  sizeof(buffer),
278  (uint8_t *)&buffer);
279  if (retval != ERROR_OK) {
280  LOG_ERROR("Can't parse `%s`",
282  goto error;
283  }
284 
285  /* Make sure the string in the buffer terminates */
286  if (buffer[sizeof(buffer) - 1] != 0)
287  buffer[sizeof(buffer) - 1] = 0;
288 
289  /* Copy thread name */
290  rtos->thread_details[tasks_found].thread_name_str =
291  strdup(buffer);
292 
293  } else {
294  rtos->thread_details[tasks_found].thread_name_str =
295  strdup("Enable DEVELHELP to see task names");
296  }
297 
298  if (!rtos->thread_details[tasks_found].thread_name_str) {
299  LOG_ERROR("RIOT: out of memory");
300  retval = ERROR_FAIL;
301  goto error;
302  }
303 
304  rtos->thread_details[tasks_found].exists = true;
305 
306  tasks_found++;
307  }
308 
309  return ERROR_OK;
310 
311 error:
313  return retval;
314 }
315 
316 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
317  struct rtos_reg **reg_list, int *num_regs)
318 {
319  int retval;
320  const struct riot_params *param;
321 
322  if (!rtos)
323  return ERROR_FAIL;
324 
325  if (thread_id == 0)
326  return ERROR_FAIL;
327 
329  return ERROR_FAIL;
330 
331  param = (const struct riot_params *)rtos->rtos_specific_params;
332 
333  /* find the thread with given thread id */
334  uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
335  uint32_t tcb_pointer = 0;
336  retval = target_read_u32(rtos->target,
337  threads_base + (thread_id * 4),
338  &tcb_pointer);
339  if (retval != ERROR_OK) {
340  LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
341  return retval;
342  }
343 
344  /* read stack pointer for that thread */
345  uint32_t stackptr = 0;
346  retval = target_read_u32(rtos->target,
347  tcb_pointer + param->thread_sp_offset,
348  &stackptr);
349  if (retval != ERROR_OK) {
350  LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
351  return retval;
352  }
353 
356  stackptr,
357  reg_list,
358  num_regs);
359 }
360 
361 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
362 {
363  *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem));
364 
365  if (!*symbol_list) {
366  LOG_ERROR("RIOT: out of memory");
367  return ERROR_FAIL;
368  }
369 
370  for (unsigned int i = 0; i < ARRAY_SIZE(riot_symbol_list); i++) {
371  (*symbol_list)[i].symbol_name = riot_symbol_list[i].name;
372  (*symbol_list)[i].optional = riot_symbol_list[i].optional;
373  }
374 
375  return ERROR_OK;
376 }
377 
378 static bool riot_detect_rtos(struct target *target)
379 {
380  if ((target->rtos->symbols) &&
382  /* looks like RIOT */
383  return true;
384  }
385  return false;
386 }
387 
388 static int riot_create(struct target *target)
389 {
390  unsigned int i = 0;
391 
392  /* lookup if target is supported by RIOT */
393  while ((i < RIOT_NUM_PARAMS) &&
394  (strcmp(riot_params_list[i].target_name, target->type->name) != 0)) {
395  i++;
396  }
397  if (i >= RIOT_NUM_PARAMS) {
398  LOG_ERROR("Could not find target in RIOT compatibility list");
399  return ERROR_FAIL;
400  }
401 
403  target->rtos->current_thread = 0;
405 
406  /* Stacking is different depending on architecture */
407  struct armv7m_common *armv7m_target = target_to_armv7m(target);
408 
409  if (armv7m_target->arm.arch == ARM_ARCH_V6M)
411  else if (is_armv7m(armv7m_target))
413  else {
414  LOG_ERROR("No stacking info for architecture");
415  return ERROR_FAIL;
416  }
417  return ERROR_OK;
418 }
@ ARM_ARCH_V6M
Definition: arm.h:56
const char * name
Definition: armv4_5.c:76
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:262
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:250
The JTAG interface can be implemented with a software or hardware fifo.
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define ERROR_OK
Definition: log.h:164
static const struct rtos_register_stacking * stacking_info
Definition: riot.c:73
static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: riot.c:361
static const struct riot_thread_state riot_thread_states[]
Definition: riot.c:35
static bool riot_detect_rtos(struct target *target)
Definition: riot.c:378
static int riot_update_threads(struct rtos *rtos)
Definition: riot.c:107
static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: riot.c:316
static struct riot_symbol const riot_symbol_list[]
Definition: riot.c:89
const struct rtos_type riot_rtos
Definition: riot.c:98
#define RIOT_NUM_PARAMS
Definition: riot.c:70
#define RIOT_NUM_STATES
Definition: riot.c:50
static const struct riot_params riot_params_list[]
Definition: riot.c:58
static int riot_create(struct target *target)
Definition: riot.c:388
riot_symbol_values
Definition: riot.c:75
@ RIOT_NAME_OFFSET
Definition: riot.c:80
@ RIOT_NUM_THREADS
Definition: riot.c:77
@ RIOT_ACTIVE_PID
Definition: riot.c:78
@ RIOT_THREADS_BASE
Definition: riot.c:76
@ RIOT_MAX_THREADS
Definition: riot.c:79
int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs)
Definition: rtos.c:602
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:695
const struct rtos_register_stacking rtos_riot_cortex_m0_stacking
const struct rtos_register_stacking rtos_riot_cortex_m34_stacking
enum arm_arch arch
ARM architecture version.
Definition: arm.h:201
struct arm arm
Definition: armv7m.h:225
unsigned char thread_sp_offset
Definition: riot.c:54
const char * target_name
Definition: riot.c:53
unsigned char thread_status_offset
Definition: riot.c:55
const char *const name
Definition: riot.c:84
bool optional
Definition: riot.c:85
const char * desc
Definition: riot.c:31
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
struct thread_detail * thread_details
Definition: rtos.h:46
struct symbol_table_elem * symbols
Definition: rtos.h:39
struct target * target
Definition: rtos.h:40
void * rtos_specific_params
Definition: rtos.h:50
threadid_t current_thread
Definition: rtos.h:45
Table should be terminated by an element with NULL in symbol_name.
Definition: rtos.h:23
symbol_address_t address
Definition: rtos.h:25
const char * name
Name of this type of target.
Definition: target_type.h:31
Definition: target.h:116
struct rtos * rtos
Definition: target.h:183
struct target_type * type
Definition: target.h:117
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_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2407
int target_read_u8(struct target *target, target_addr_t address, uint8_t *value)
Definition: target.c:2598
int target_read_u16(struct target *target, target_addr_t address, uint16_t *value)
Definition: target.c:2574
int target_read_u32(struct target *target, target_addr_t address, uint32_t *value)
Definition: target.c:2550
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
#define NULL
Definition: usb.h:16
uint8_t status[4]
Definition: vdebug.c:17