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

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)