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

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)