rtos: Support looking up .lto_priv.0 appended to symbol name
[openocd.git] / src / rtos / rtos.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4 * Copyright (C) 2011 by Broadcom Corporation *
5 * Evan Hunter - ehunter@broadcom.com *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "rtos.h"
13 #include "target/target.h"
14 #include "helper/log.h"
15 #include "helper/binarybuffer.h"
16 #include "server/gdb_server.h"
17
18 /* RTOSs */
19 extern struct rtos_type freertos_rtos;
20 extern struct rtos_type threadx_rtos;
21 extern struct rtos_type ecos_rtos;
22 extern struct rtos_type linux_rtos;
23 extern struct rtos_type chibios_rtos;
24 extern struct rtos_type chromium_ec_rtos;
25 extern struct rtos_type embkernel_rtos;
26 extern struct rtos_type mqx_rtos;
27 extern struct rtos_type ucos_iii_rtos;
28 extern struct rtos_type nuttx_rtos;
29 extern struct rtos_type hwthread_rtos;
30 extern struct rtos_type riot_rtos;
31 extern struct rtos_type zephyr_rtos;
32
33 static struct rtos_type *rtos_types[] = {
34 &threadx_rtos,
35 &freertos_rtos,
36 &ecos_rtos,
37 &linux_rtos,
38 &chibios_rtos,
39 &chromium_ec_rtos,
40 &embkernel_rtos,
41 &mqx_rtos,
42 &ucos_iii_rtos,
43 &nuttx_rtos,
44 &riot_rtos,
45 &zephyr_rtos,
46 /* keep this as last, as it always matches with rtos auto */
47 &hwthread_rtos,
48 NULL
49 };
50
51 static int rtos_try_next(struct target *target);
52
53 int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
54
55 int rtos_smp_init(struct target *target)
56 {
57 if (target->rtos->type->smp_init)
58 return target->rtos->type->smp_init(target);
59 return ERROR_TARGET_INIT_FAILED;
60 }
61
62 static int rtos_target_for_threadid(struct connection *connection, int64_t threadid, struct target **t)
63 {
64 struct target *curr = get_target_from_connection(connection);
65 if (t)
66 *t = curr;
67
68 return ERROR_OK;
69 }
70
71 static int os_alloc(struct target *target, struct rtos_type *ostype)
72 {
73 struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos));
74
75 if (!os)
76 return JIM_ERR;
77
78 os->type = ostype;
79 os->current_threadid = -1;
80 os->current_thread = 0;
81 os->symbols = NULL;
82 os->target = target;
83
84 /* RTOS drivers can override the packet handler in _create(). */
85 os->gdb_thread_packet = rtos_thread_packet;
86 os->gdb_target_for_threadid = rtos_target_for_threadid;
87
88 return JIM_OK;
89 }
90
91 static void os_free(struct target *target)
92 {
93 if (!target->rtos)
94 return;
95
96 free(target->rtos->symbols);
97 free(target->rtos);
98 target->rtos = NULL;
99 }
100
101 static int os_alloc_create(struct target *target, struct rtos_type *ostype)
102 {
103 int ret = os_alloc(target, ostype);
104
105 if (ret == JIM_OK) {
106 ret = target->rtos->type->create(target);
107 if (ret != JIM_OK)
108 os_free(target);
109 }
110
111 return ret;
112 }
113
114 int rtos_create(struct jim_getopt_info *goi, struct target *target)
115 {
116 int x;
117 const char *cp;
118 Jim_Obj *res;
119 int e;
120
121 if (!goi->isconfigure && goi->argc != 0) {
122 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
123 return JIM_ERR;
124 }
125
126 os_free(target);
127
128 e = jim_getopt_string(goi, &cp, NULL);
129 if (e != JIM_OK)
130 return e;
131
132 if (strcmp(cp, "none") == 0)
133 return JIM_OK;
134
135 if (strcmp(cp, "auto") == 0) {
136 /* Auto detect tries to look up all symbols for each RTOS,
137 * and runs the RTOS driver's _detect() function when GDB
138 * finds all symbols for any RTOS. See rtos_qsymbol(). */
139 target->rtos_auto_detect = true;
140
141 /* rtos_qsymbol() will iterate over all RTOSes. Allocate
142 * target->rtos here, and set it to the first RTOS type. */
143 return os_alloc(target, rtos_types[0]);
144 }
145
146 for (x = 0; rtos_types[x]; x++)
147 if (strcmp(cp, rtos_types[x]->name) == 0)
148 return os_alloc_create(target, rtos_types[x]);
149
150 Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp);
151 res = Jim_GetResult(goi->interp);
152 for (x = 0; rtos_types[x]; x++)
153 Jim_AppendStrings(goi->interp, res, rtos_types[x]->name, ", ", NULL);
154 Jim_AppendStrings(goi->interp, res, ", auto or none", NULL);
155
156 return JIM_ERR;
157 }
158
159 void rtos_destroy(struct target *target)
160 {
161 os_free(target);
162 }
163
164 int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size)
165 {
166 struct target *target = get_target_from_connection(connection);
167 if (!target->rtos)
168 return rtos_thread_packet(connection, packet, packet_size); /* thread not
169 *found*/
170 return target->rtos->gdb_thread_packet(connection, packet, packet_size);
171 }
172
173 static struct symbol_table_elem *find_symbol(const struct rtos *os, const char *symbol)
174 {
175 struct symbol_table_elem *s;
176
177 for (s = os->symbols; s->symbol_name; s++)
178 if (!strcmp(s->symbol_name, symbol))
179 return s;
180
181 return NULL;
182 }
183
184 static struct symbol_table_elem *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr)
185 {
186 if (!os->symbols)
187 os->type->get_symbol_list_to_lookup(&os->symbols);
188
189 if (!cur_symbol[0])
190 return &os->symbols[0];
191
192 struct symbol_table_elem *s = find_symbol(os, cur_symbol);
193 if (!s)
194 return NULL;
195
196 s->address = cur_addr;
197 s++;
198 return s;
199 }
200
201 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
202 *
203 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
204 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
205 *
206 * If the qSymbol packet has no address that means GDB did not find the
207 * symbol, in which case auto-detect will move on to try the next RTOS.
208 *
209 * rtos_qsymbol() then calls the next_symbol() helper function, which
210 * iterates over symbol names for the current RTOS until it finds the
211 * symbol in the received GDB packet, and then returns the next entry
212 * in the list of symbols.
213 *
214 * If GDB replied about the last symbol for the RTOS and the RTOS was
215 * specified explicitly, then no further symbol lookup is done. When
216 * auto-detecting, the RTOS driver _detect() function must return success.
217 *
218 * The symbol is tried twice to handle the -flto case with gcc. The first
219 * attempt uses the symbol as-is, and the second attempt tries the symbol
220 * with ".lto_priv.0" appended to it. We only consider the first static
221 * symbol here from the -flto case. (Each subsequent static symbol with
222 * the same name is exported as .lto_priv.1, .lto_priv.2, etc.)
223 *
224 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
225 */
226 int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size)
227 {
228 int rtos_detected = 0;
229 uint64_t addr = 0;
230 size_t reply_len;
231 char reply[GDB_BUFFER_SIZE + 1], cur_sym[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
232 struct symbol_table_elem *next_sym = NULL;
233 struct target *target = get_target_from_connection(connection);
234 struct rtos *os = target->rtos;
235
236 reply_len = sprintf(reply, "OK");
237
238 if (!os)
239 goto done;
240
241 /* Decode any symbol name in the packet*/
242 size_t len = unhexify((uint8_t *)cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1));
243 cur_sym[len] = 0;
244
245 const char no_suffix[] = "";
246 const char lto_suffix[] = ".lto_priv.0";
247 const size_t lto_suffix_len = strlen(lto_suffix);
248
249 const char *cur_suffix;
250 const char *next_suffix;
251
252 /* Detect what suffix was used during the previous symbol lookup attempt, and
253 * speculatively determine the next suffix (only used for the unknown address case) */
254 if (len > lto_suffix_len && !strcmp(cur_sym + len - lto_suffix_len, lto_suffix)) {
255 /* Trim the suffix from cur_sym for comparison purposes below */
256 cur_sym[len - lto_suffix_len] = '\0';
257 cur_suffix = lto_suffix;
258 next_suffix = NULL;
259 } else {
260 cur_suffix = no_suffix;
261 next_suffix = lto_suffix;
262 }
263
264 if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
265 (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr))) { /* GDB did not find an address for a symbol */
266
267 /* GDB could not find an address for the previous symbol */
268 struct symbol_table_elem *sym = find_symbol(os, cur_sym);
269
270 if (next_suffix) {
271 next_sym = sym;
272 } else if (sym && !sym->optional) { /* the symbol is mandatory for this RTOS */
273 if (!target->rtos_auto_detect) {
274 LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym);
275 goto done;
276 } else {
277 /* Autodetecting RTOS - try next RTOS */
278 if (!rtos_try_next(target)) {
279 LOG_WARNING("No RTOS could be auto-detected!");
280 goto done;
281 }
282
283 /* Next RTOS selected - invalidate current symbol */
284 cur_sym[0] = '\x00';
285 }
286 }
287 }
288
289 LOG_DEBUG("RTOS: Address of symbol '%s%s' is 0x%" PRIx64, cur_sym, cur_suffix, addr);
290
291 if (!next_sym) {
292 next_sym = next_symbol(os, cur_sym, addr);
293 next_suffix = no_suffix;
294 }
295
296 /* Should never happen unless the debugger misbehaves */
297 if (!next_sym) {
298 LOG_WARNING("RTOS: Debugger sent us qSymbol with '%s%s' that we did not ask for", cur_sym, cur_suffix);
299 goto done;
300 }
301
302 if (!next_sym->symbol_name) {
303 /* No more symbols need looking up */
304
305 if (!target->rtos_auto_detect) {
306 rtos_detected = 1;
307 goto done;
308 }
309
310 if (os->type->detect_rtos(target)) {
311 LOG_INFO("Auto-detected RTOS: %s", os->type->name);
312 rtos_detected = 1;
313 goto done;
314 } else {
315 LOG_WARNING("No RTOS could be auto-detected!");
316 goto done;
317 }
318 }
319
320 assert(next_suffix);
321
322 reply_len = 8; /* snprintf(..., "qSymbol:") */
323 reply_len += 2 * strlen(next_sym->symbol_name); /* hexify(..., next_sym->symbol_name, ...) */
324 reply_len += 2 * strlen(next_suffix); /* hexify(..., next_suffix, ...) */
325 reply_len += 1; /* Terminating NUL */
326 if (reply_len > sizeof(reply)) {
327 LOG_ERROR("ERROR: RTOS symbol '%s%s' name is too long for GDB!", next_sym->symbol_name, next_suffix);
328 goto done;
329 }
330
331 LOG_DEBUG("RTOS: Requesting symbol lookup of '%s%s' from the debugger", next_sym->symbol_name, next_suffix);
332
333 reply_len = snprintf(reply, sizeof(reply), "qSymbol:");
334 reply_len += hexify(reply + reply_len,
335 (const uint8_t *)next_sym->symbol_name, strlen(next_sym->symbol_name),
336 sizeof(reply) - reply_len);
337 reply_len += hexify(reply + reply_len,
338 (const uint8_t *)next_suffix, strlen(next_suffix),
339 sizeof(reply) - reply_len);
340
341 done:
342 gdb_put_packet(connection, reply, reply_len);
343 return rtos_detected;
344 }
345
346 int rtos_thread_packet(struct connection *connection, char const *packet, int packet_size)
347 {
348 struct target *target = get_target_from_connection(connection);
349
350 if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) {
351 if ((target->rtos) && (target->rtos->thread_details) &&
352 (target->rtos->thread_count != 0)) {
353 threadid_t threadid = 0;
354 int found = -1;
355 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
356
357 if ((target->rtos) && (target->rtos->thread_details)) {
358 int thread_num;
359 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
360 if (target->rtos->thread_details[thread_num].threadid == threadid) {
361 if (target->rtos->thread_details[thread_num].exists)
362 found = thread_num;
363 }
364 }
365 }
366 if (found == -1) {
367 gdb_put_packet(connection, "E01", 3); /* thread not found */
368 return ERROR_OK;
369 }
370
371 struct thread_detail *detail = &target->rtos->thread_details[found];
372
373 int str_size = 0;
374 if (detail->thread_name_str)
375 str_size += strlen(detail->thread_name_str);
376 if (detail->extra_info_str)
377 str_size += strlen(detail->extra_info_str);
378
379 char *tmp_str = calloc(str_size + 9, sizeof(char));
380 char *tmp_str_ptr = tmp_str;
381
382 if (detail->thread_name_str)
383 tmp_str_ptr += sprintf(tmp_str_ptr, "Name: %s", detail->thread_name_str);
384 if (detail->extra_info_str) {
385 if (tmp_str_ptr != tmp_str)
386 tmp_str_ptr += sprintf(tmp_str_ptr, ", ");
387 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->extra_info_str);
388 }
389
390 assert(strlen(tmp_str) ==
391 (size_t) (tmp_str_ptr - tmp_str));
392
393 char *hex_str = malloc(strlen(tmp_str) * 2 + 1);
394 size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str,
395 strlen(tmp_str), strlen(tmp_str) * 2 + 1);
396
397 gdb_put_packet(connection, hex_str, pkt_len);
398 free(hex_str);
399 free(tmp_str);
400 return ERROR_OK;
401
402 }
403 gdb_put_packet(connection, "", 0);
404 return ERROR_OK;
405 } else if (strncmp(packet, "qSymbol", 7) == 0) {
406 if (rtos_qsymbol(connection, packet, packet_size) == 1) {
407 if (target->rtos_auto_detect == true) {
408 target->rtos_auto_detect = false;
409 target->rtos->type->create(target);
410 }
411 target->rtos->type->update_threads(target->rtos);
412 }
413 return ERROR_OK;
414 } else if (strncmp(packet, "qfThreadInfo", 12) == 0) {
415 int i;
416 if (target->rtos) {
417 if (target->rtos->thread_count == 0) {
418 gdb_put_packet(connection, "l", 1);
419 } else {
420 /*thread id are 16 char +1 for ',' */
421 char *out_str = malloc(17 * target->rtos->thread_count + 1);
422 char *tmp_str = out_str;
423 for (i = 0; i < target->rtos->thread_count; i++) {
424 tmp_str += sprintf(tmp_str, "%c%016" PRIx64, i == 0 ? 'm' : ',',
425 target->rtos->thread_details[i].threadid);
426 }
427 gdb_put_packet(connection, out_str, strlen(out_str));
428 free(out_str);
429 }
430 } else
431 gdb_put_packet(connection, "l", 1);
432
433 return ERROR_OK;
434 } else if (strncmp(packet, "qsThreadInfo", 12) == 0) {
435 gdb_put_packet(connection, "l", 1);
436 return ERROR_OK;
437 } else if (strncmp(packet, "qAttached", 9) == 0) {
438 gdb_put_packet(connection, "1", 1);
439 return ERROR_OK;
440 } else if (strncmp(packet, "qOffsets", 8) == 0) {
441 char offsets[] = "Text=0;Data=0;Bss=0";
442 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
443 return ERROR_OK;
444 } else if (strncmp(packet, "qCRC:", 5) == 0) {
445 /* make sure we check this before "qC" packet below
446 * otherwise it gets incorrectly handled */
447 return GDB_THREAD_PACKET_NOT_CONSUMED;
448 } else if (strncmp(packet, "qC", 2) == 0) {
449 if (target->rtos) {
450 char buffer[19];
451 int size;
452 size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread);
453 gdb_put_packet(connection, buffer, size);
454 } else
455 gdb_put_packet(connection, "QC0", 3);
456 return ERROR_OK;
457 } else if (packet[0] == 'T') { /* Is thread alive? */
458 threadid_t threadid;
459 int found = -1;
460 sscanf(packet, "T%" SCNx64, &threadid);
461 if ((target->rtos) && (target->rtos->thread_details)) {
462 int thread_num;
463 for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) {
464 if (target->rtos->thread_details[thread_num].threadid == threadid) {
465 if (target->rtos->thread_details[thread_num].exists)
466 found = thread_num;
467 }
468 }
469 }
470 if (found != -1)
471 gdb_put_packet(connection, "OK", 2); /* thread alive */
472 else
473 gdb_put_packet(connection, "E01", 3); /* thread not found */
474 return ERROR_OK;
475 } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
476 * all other operations ) */
477 if ((packet[1] == 'g') && (target->rtos)) {
478 threadid_t threadid;
479 sscanf(packet, "Hg%16" SCNx64, &threadid);
480 LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64, threadid);
481 /* threadid of 0 indicates target should choose */
482 if (threadid == 0)
483 target->rtos->current_threadid = target->rtos->current_thread;
484 else
485 target->rtos->current_threadid = threadid;
486 }
487 gdb_put_packet(connection, "OK", 2);
488 return ERROR_OK;
489 }
490
491 return GDB_THREAD_PACKET_NOT_CONSUMED;
492 }
493
494 static int rtos_put_gdb_reg_list(struct connection *connection,
495 struct rtos_reg *reg_list, int num_regs)
496 {
497 size_t num_bytes = 1; /* NUL */
498 for (int i = 0; i < num_regs; ++i)
499 num_bytes += DIV_ROUND_UP(reg_list[i].size, 8) * 2;
500
501 char *hex = malloc(num_bytes);
502 char *hex_p = hex;
503
504 for (int i = 0; i < num_regs; ++i) {
505 size_t count = DIV_ROUND_UP(reg_list[i].size, 8);
506 size_t n = hexify(hex_p, reg_list[i].value, count, num_bytes);
507 hex_p += n;
508 num_bytes -= n;
509 }
510
511 gdb_put_packet(connection, hex, strlen(hex));
512 free(hex);
513
514 return ERROR_OK;
515 }
516
517 /** Look through all registers to find this register. */
518 int rtos_get_gdb_reg(struct connection *connection, int reg_num)
519 {
520 struct target *target = get_target_from_connection(connection);
521 int64_t current_threadid = target->rtos->current_threadid;
522 if ((target->rtos) && (current_threadid != -1) &&
523 (current_threadid != 0) &&
524 ((current_threadid != target->rtos->current_thread) ||
525 (target->smp))) { /* in smp several current thread are possible */
526 struct rtos_reg *reg_list;
527 int num_regs;
528
529 LOG_DEBUG("getting register %d for thread 0x%" PRIx64
530 ", target->rtos->current_thread=0x%" PRIx64,
531 reg_num,
532 current_threadid,
533 target->rtos->current_thread);
534
535 int retval;
536 if (target->rtos->type->get_thread_reg) {
537 reg_list = calloc(1, sizeof(*reg_list));
538 num_regs = 1;
539 retval = target->rtos->type->get_thread_reg(target->rtos,
540 current_threadid, reg_num, &reg_list[0]);
541 if (retval != ERROR_OK) {
542 LOG_ERROR("RTOS: failed to get register %d", reg_num);
543 return retval;
544 }
545 } else {
546 retval = target->rtos->type->get_thread_reg_list(target->rtos,
547 current_threadid,
548 &reg_list,
549 &num_regs);
550 if (retval != ERROR_OK) {
551 LOG_ERROR("RTOS: failed to get register list");
552 return retval;
553 }
554 }
555
556 for (int i = 0; i < num_regs; ++i) {
557 if (reg_list[i].number == (uint32_t)reg_num) {
558 rtos_put_gdb_reg_list(connection, reg_list + i, 1);
559 free(reg_list);
560 return ERROR_OK;
561 }
562 }
563
564 free(reg_list);
565 }
566 return ERROR_FAIL;
567 }
568
569 /** Return a list of general registers. */
570 int rtos_get_gdb_reg_list(struct connection *connection)
571 {
572 struct target *target = get_target_from_connection(connection);
573 int64_t current_threadid = target->rtos->current_threadid;
574 if ((target->rtos) && (current_threadid != -1) &&
575 (current_threadid != 0) &&
576 ((current_threadid != target->rtos->current_thread) ||
577 (target->smp))) { /* in smp several current thread are possible */
578 struct rtos_reg *reg_list;
579 int num_regs;
580
581 LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
582 ", target->rtos->current_thread=0x%" PRIx64 "\r\n",
583 current_threadid,
584 target->rtos->current_thread);
585
586 int retval = target->rtos->type->get_thread_reg_list(target->rtos,
587 current_threadid,
588 &reg_list,
589 &num_regs);
590 if (retval != ERROR_OK) {
591 LOG_ERROR("RTOS: failed to get register list");
592 return retval;
593 }
594
595 rtos_put_gdb_reg_list(connection, reg_list, num_regs);
596 free(reg_list);
597
598 return ERROR_OK;
599 }
600 return ERROR_FAIL;
601 }
602
603 int rtos_set_reg(struct connection *connection, int reg_num,
604 uint8_t *reg_value)
605 {
606 struct target *target = get_target_from_connection(connection);
607 int64_t current_threadid = target->rtos->current_threadid;
608 if ((target->rtos) &&
609 (target->rtos->type->set_reg) &&
610 (current_threadid != -1) &&
611 (current_threadid != 0)) {
612 return target->rtos->type->set_reg(target->rtos, reg_num, reg_value);
613 }
614 return ERROR_FAIL;
615 }
616
617 int rtos_generic_stack_read(struct target *target,
618 const struct rtos_register_stacking *stacking,
619 int64_t stack_ptr,
620 struct rtos_reg **reg_list,
621 int *num_regs)
622 {
623 int retval;
624
625 if (stack_ptr == 0) {
626 LOG_ERROR("Error: null stack pointer in thread");
627 return -5;
628 }
629 /* Read the stack */
630 uint8_t *stack_data = malloc(stacking->stack_registers_size);
631 uint32_t address = stack_ptr;
632
633 if (stacking->stack_growth_direction == 1)
634 address -= stacking->stack_registers_size;
635 retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
636 if (retval != ERROR_OK) {
637 free(stack_data);
638 LOG_ERROR("Error reading stack frame from thread");
639 return retval;
640 }
641 LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32, address);
642
643 #if 0
644 LOG_OUTPUT("Stack Data :");
645 for (i = 0; i < stacking->stack_registers_size; i++)
646 LOG_OUTPUT("%02X", stack_data[i]);
647 LOG_OUTPUT("\r\n");
648 #endif
649
650 target_addr_t new_stack_ptr;
651 if (stacking->calculate_process_stack) {
652 new_stack_ptr = stacking->calculate_process_stack(target,
653 stack_data, stacking, stack_ptr);
654 } else {
655 new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
656 stacking->stack_registers_size;
657 }
658
659 *reg_list = calloc(stacking->num_output_registers, sizeof(struct rtos_reg));
660 *num_regs = stacking->num_output_registers;
661
662 for (int i = 0; i < stacking->num_output_registers; ++i) {
663 (*reg_list)[i].number = stacking->register_offsets[i].number;
664 (*reg_list)[i].size = stacking->register_offsets[i].width_bits;
665
666 int offset = stacking->register_offsets[i].offset;
667 if (offset == -2)
668 buf_cpy(&new_stack_ptr, (*reg_list)[i].value, (*reg_list)[i].size);
669 else if (offset != -1)
670 buf_cpy(stack_data + offset, (*reg_list)[i].value, (*reg_list)[i].size);
671 }
672
673 free(stack_data);
674 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
675 return ERROR_OK;
676 }
677
678 static int rtos_try_next(struct target *target)
679 {
680 struct rtos *os = target->rtos;
681 struct rtos_type **type = rtos_types;
682
683 if (!os)
684 return 0;
685
686 while (*type && os->type != *type)
687 type++;
688
689 if (!*type || !*(++type))
690 return 0;
691
692 os->type = *type;
693
694 free(os->symbols);
695 os->symbols = NULL;
696
697 return 1;
698 }
699
700 int rtos_update_threads(struct target *target)
701 {
702 if ((target->rtos) && (target->rtos->type))
703 target->rtos->type->update_threads(target->rtos);
704 return ERROR_OK;
705 }
706
707 void rtos_free_threadlist(struct rtos *rtos)
708 {
709 if (rtos->thread_details) {
710 int j;
711
712 for (j = 0; j < rtos->thread_count; j++) {
713 struct thread_detail *current_thread = &rtos->thread_details[j];
714 free(current_thread->thread_name_str);
715 free(current_thread->extra_info_str);
716 }
717 free(rtos->thread_details);
718 rtos->thread_details = NULL;
719 rtos->thread_count = 0;
720 rtos->current_threadid = -1;
721 rtos->current_thread = 0;
722 }
723 }
724
725 int rtos_read_buffer(struct target *target, target_addr_t address,
726 uint32_t size, uint8_t *buffer)
727 {
728 if (target->rtos->type->read_buffer)
729 return target->rtos->type->read_buffer(target->rtos, address, size, buffer);
730 return ERROR_NOT_IMPLEMENTED;
731 }
732
733 int rtos_write_buffer(struct target *target, target_addr_t address,
734 uint32_t size, const uint8_t *buffer)
735 {
736 if (target->rtos->type->write_buffer)
737 return target->rtos->type->write_buffer(target->rtos, address, size, buffer);
738 return ERROR_NOT_IMPLEMENTED;
739 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)