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

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)