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

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)