1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2017 by Intel Corporation
5 * Leandro Pereira <leandro.pereira@intel.com>
6 * Daniel Glöckner <dg@emlix.com>*
7 * Copyright (C) 2021 by Synopsys, Inc.
8 * Evgeniy Didin <didin@synopsys.com>
9 ***************************************************************************/
15 #include <helper/time_support.h>
16 #include <jtag/jtag.h>
18 #include "helper/log.h"
19 #include "helper/types.h"
21 #include "rtos_standard_stackings.h"
22 #include "target/target.h"
23 #include "target/target_type.h"
24 #include "target/armv7m.h"
25 #include "target/arc.h"
27 #define UNIMPLEMENTED 0xFFFFFFFFU
29 /* ARC specific defines */
30 #define ARC_AUX_SEC_BUILD_REG 0xdb
31 #define ARC_REG_NUM 38
33 /* ARM specific defines */
34 #define ARM_XPSR_OFFSET 28
36 struct zephyr_thread
{
37 uint32_t ptr
, next_ptr
;
39 uint32_t stack_pointer
;
53 OFFSET_T_USER_OPTIONS
,
55 OFFSET_T_STACK_POINTER
,
58 OFFSET_T_PREEMPT_FLOAT
,
60 OFFSET_T_ARM_EXC_RETURN
,
64 struct zephyr_params
{
65 const char *target_name
;
67 uint8_t pointer_width
;
69 uint32_t offsets
[OFFSET_MAX
];
70 const struct rtos_register_stacking
*callee_saved_stacking
;
71 const struct rtos_register_stacking
*cpu_saved_nofp_stacking
;
72 const struct rtos_register_stacking
*cpu_saved_fp_stacking
;
73 int (*get_cpu_state
)(struct rtos
*rtos
, target_addr_t
*addr
,
74 struct zephyr_params
*params
,
75 struct rtos_reg
*callee_saved_reg_list
,
76 struct rtos_reg
**reg_list
, int *num_regs
);
79 static const struct stack_register_offset arm_callee_saved
[] = {
80 { ARMV7M_R13
, 32, 32 },
84 { ARMV7M_R7
, 12, 32 },
85 { ARMV7M_R8
, 16, 32 },
86 { ARMV7M_R9
, 20, 32 },
87 { ARMV7M_R10
, 24, 32 },
88 { ARMV7M_R11
, 28, 32 },
91 static const struct stack_register_offset arc_callee_saved
[] = {
109 static const struct rtos_register_stacking arm_callee_saved_stacking
= {
110 .stack_registers_size
= 36,
111 .stack_growth_direction
= -1,
112 .num_output_registers
= ARRAY_SIZE(arm_callee_saved
),
113 .register_offsets
= arm_callee_saved
,
116 static const struct rtos_register_stacking arc_callee_saved_stacking
= {
117 .stack_registers_size
= 64,
118 .stack_growth_direction
= -1,
119 .num_output_registers
= ARRAY_SIZE(arc_callee_saved
),
120 .register_offsets
= arc_callee_saved
,
123 static const struct stack_register_offset arm_cpu_saved
[] = {
124 { ARMV7M_R0
, 0, 32 },
125 { ARMV7M_R1
, 4, 32 },
126 { ARMV7M_R2
, 8, 32 },
127 { ARMV7M_R3
, 12, 32 },
128 { ARMV7M_R4
, -1, 32 },
129 { ARMV7M_R5
, -1, 32 },
130 { ARMV7M_R6
, -1, 32 },
131 { ARMV7M_R7
, -1, 32 },
132 { ARMV7M_R8
, -1, 32 },
133 { ARMV7M_R9
, -1, 32 },
134 { ARMV7M_R10
, -1, 32 },
135 { ARMV7M_R11
, -1, 32 },
136 { ARMV7M_R12
, 16, 32 },
137 { ARMV7M_R13
, -2, 32 },
138 { ARMV7M_R14
, 20, 32 },
139 { ARMV7M_PC
, 24, 32 },
140 { ARMV7M_XPSR
, 28, 32 },
143 static struct stack_register_offset arc_cpu_saved
[] = {
173 { ARC_ILINK
, -1, 32 },
175 { ARC_BLINK
, 0, 32 },
176 { ARC_LP_COUNT
, -1, 32 },
179 { ARC_LP_START
, -1, 32 },
180 { ARC_LP_END
, -1, 32 },
181 { ARC_STATUS32
, 4, 32 }
185 enum zephyr_symbol_values
{
187 ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
,
188 ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE
,
189 ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS
,
193 static target_addr_t
zephyr_cortex_m_stack_align(struct target
*target
,
194 const uint8_t *stack_data
,
195 const struct rtos_register_stacking
*stacking
, target_addr_t stack_ptr
)
197 return rtos_cortex_m_stack_align(target
, stack_data
, stacking
,
198 stack_ptr
, ARM_XPSR_OFFSET
);
201 static const struct rtos_register_stacking arm_cpu_saved_nofp_stacking
= {
202 .stack_registers_size
= 32,
203 .stack_growth_direction
= -1,
204 .num_output_registers
= ARRAY_SIZE(arm_cpu_saved
),
205 .calculate_process_stack
= zephyr_cortex_m_stack_align
,
206 .register_offsets
= arm_cpu_saved
,
209 static const struct rtos_register_stacking arm_cpu_saved_fp_stacking
= {
210 .stack_registers_size
= 32 + 18 * 4,
211 .stack_growth_direction
= -1,
212 .num_output_registers
= ARRAY_SIZE(arm_cpu_saved
),
213 .calculate_process_stack
= zephyr_cortex_m_stack_align
,
214 .register_offsets
= arm_cpu_saved
,
217 /* stack_registers_size is 8 because besides caller registers
218 * there are only blink and Status32 registers on stack left */
219 static struct rtos_register_stacking arc_cpu_saved_stacking
= {
220 .stack_registers_size
= 8,
221 .stack_growth_direction
= -1,
222 .num_output_registers
= ARRAY_SIZE(arc_cpu_saved
),
223 .register_offsets
= arc_cpu_saved
,
226 /* ARCv2 specific implementation */
227 static int zephyr_get_arc_state(struct rtos
*rtos
, target_addr_t
*addr
,
228 struct zephyr_params
*params
,
229 struct rtos_reg
*callee_saved_reg_list
,
230 struct rtos_reg
**reg_list
, int *num_regs
)
233 uint32_t real_stack_addr
;
235 int num_callee_saved_regs
;
236 const struct rtos_register_stacking
*stacking
;
238 /* Getting real stack address from Kernel thread struct */
239 retval
= target_read_u32(rtos
->target
, *addr
, &real_stack_addr
);
240 if (retval
!= ERROR_OK
)
243 /* Getting callee registers */
244 retval
= rtos_generic_stack_read(rtos
->target
,
245 params
->callee_saved_stacking
,
246 real_stack_addr
, &callee_saved_reg_list
,
247 &num_callee_saved_regs
);
248 if (retval
!= ERROR_OK
)
251 stacking
= params
->cpu_saved_nofp_stacking
;
253 /* Getting blink and status32 registers */
254 retval
= rtos_generic_stack_read(rtos
->target
, stacking
,
255 real_stack_addr
+ num_callee_saved_regs
* 4,
257 if (retval
!= ERROR_OK
)
260 for (int i
= 0; i
< num_callee_saved_regs
; i
++)
261 buf_cpy(callee_saved_reg_list
[i
].value
,
262 (*reg_list
)[callee_saved_reg_list
[i
].number
].value
,
263 callee_saved_reg_list
[i
].size
);
265 /* The blink, sp, pc offsets in arc_cpu_saved structure may be changed,
266 * but the registers number shall not. So the next code searches the
267 * offsetst of these registers in arc_cpu_saved structure. */
268 unsigned short blink_offset
= 0, pc_offset
= 0, sp_offset
= 0;
269 for (size_t i
= 0; i
< ARRAY_SIZE(arc_cpu_saved
); i
++) {
270 if (arc_cpu_saved
[i
].number
== ARC_BLINK
)
272 if (arc_cpu_saved
[i
].number
== ARC_SP
)
274 if (arc_cpu_saved
[i
].number
== ARC_PC
)
278 if (blink_offset
== 0 || sp_offset
== 0 || pc_offset
== 0) {
279 LOG_ERROR("Basic registers offsets are missing, check <arc_cpu_saved> struct");
283 /* Put blink value into PC */
284 buf_cpy((*reg_list
)[blink_offset
].value
,
285 (*reg_list
)[pc_offset
].value
, sizeof((*reg_list
)[blink_offset
].value
));
287 /* Put address after callee/caller in SP. */
290 stack_top
= real_stack_addr
+ num_callee_saved_regs
* 4
291 + arc_cpu_saved_stacking
.stack_registers_size
;
292 buf_cpy(&stack_top
, (*reg_list
)[sp_offset
].value
, sizeof(stack_top
));
297 /* ARM Cortex-M-specific implementation */
298 static int zephyr_get_arm_state(struct rtos
*rtos
, target_addr_t
*addr
,
299 struct zephyr_params
*params
,
300 struct rtos_reg
*callee_saved_reg_list
,
301 struct rtos_reg
**reg_list
, int *num_regs
)
305 int num_callee_saved_regs
;
306 const struct rtos_register_stacking
*stacking
;
308 retval
= rtos_generic_stack_read(rtos
->target
,
309 params
->callee_saved_stacking
,
310 *addr
, &callee_saved_reg_list
,
311 &num_callee_saved_regs
);
312 if (retval
!= ERROR_OK
)
315 *addr
= target_buffer_get_u32(rtos
->target
,
316 callee_saved_reg_list
[0].value
);
318 if (params
->offsets
[OFFSET_T_PREEMPT_FLOAT
] != UNIMPLEMENTED
)
319 stacking
= params
->cpu_saved_fp_stacking
;
321 stacking
= params
->cpu_saved_nofp_stacking
;
323 retval
= rtos_generic_stack_read(rtos
->target
, stacking
, *addr
, reg_list
,
325 if (retval
!= ERROR_OK
)
328 for (int i
= 1; i
< num_callee_saved_regs
; i
++)
329 buf_cpy(callee_saved_reg_list
[i
].value
,
330 (*reg_list
)[callee_saved_reg_list
[i
].number
].value
,
331 callee_saved_reg_list
[i
].size
);
335 static struct zephyr_params zephyr_params_list
[] = {
337 .target_name
= "cortex_m",
339 .callee_saved_stacking
= &arm_callee_saved_stacking
,
340 .cpu_saved_nofp_stacking
= &arm_cpu_saved_nofp_stacking
,
341 .cpu_saved_fp_stacking
= &arm_cpu_saved_fp_stacking
,
342 .get_cpu_state
= &zephyr_get_arm_state
,
345 .target_name
= "cortex_r4",
347 .callee_saved_stacking
= &arm_callee_saved_stacking
,
348 .cpu_saved_nofp_stacking
= &arm_cpu_saved_nofp_stacking
,
349 .cpu_saved_fp_stacking
= &arm_cpu_saved_fp_stacking
,
350 .get_cpu_state
= &zephyr_get_arm_state
,
353 .target_name
= "hla_target",
355 .callee_saved_stacking
= &arm_callee_saved_stacking
,
356 .cpu_saved_nofp_stacking
= &arm_cpu_saved_nofp_stacking
,
357 .cpu_saved_fp_stacking
= &arm_cpu_saved_fp_stacking
,
358 .get_cpu_state
= &zephyr_get_arm_state
,
362 .target_name
= "arcv2",
364 .callee_saved_stacking
= &arc_callee_saved_stacking
,
365 .cpu_saved_nofp_stacking
= &arc_cpu_saved_stacking
,
366 .get_cpu_state
= &zephyr_get_arc_state
,
373 static const struct symbol_table_elem zephyr_symbol_list
[] = {
375 .symbol_name
= "_kernel",
379 .symbol_name
= "_kernel_thread_info_offsets",
383 .symbol_name
= "_kernel_thread_info_size_t_size",
387 .symbol_name
= "_kernel_thread_info_num_offsets",
395 static bool zephyr_detect_rtos(struct target
*target
)
397 if (!target
->rtos
->symbols
) {
398 LOG_INFO("Zephyr: no symbols while detecting RTOS");
402 for (enum zephyr_symbol_values symbol
= ZEPHYR_VAL__KERNEL
;
403 symbol
!= ZEPHYR_VAL_COUNT
; symbol
++) {
404 LOG_INFO("Zephyr: does it have symbol %d (%s)?", symbol
,
405 target
->rtos
->symbols
[symbol
].optional
? "optional" : "mandatory");
407 if (target
->rtos
->symbols
[symbol
].optional
)
409 if (target
->rtos
->symbols
[symbol
].address
== 0)
413 LOG_INFO("Zephyr: all mandatory symbols found");
418 static int zephyr_create(struct target
*target
)
422 name
= target_type_name(target
);
424 LOG_INFO("Zephyr: looking for target: %s", name
);
426 /* ARC specific, check if EM target has security subsystem
427 * In case of ARC_HAS_SECURE zephyr option enabled
428 * the thread stack contains blink,sec_stat,status32 register
429 * values. If ARC_HAS_SECURE is disabled, only blink and status32
430 * register values are saved on stack. */
431 if (!strcmp(name
, "arcv2")) {
433 struct arc_common
*arc
= target_to_arc(target
);
434 /* Reading SEC_BUILD bcr */
435 CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc
->jtag_info
, ARC_AUX_SEC_BUILD_REG
, &value
));
437 LOG_DEBUG("ARC EM board has security subsystem, changing offsets");
438 arc_cpu_saved
[ARC_REG_NUM
- 1].offset
= 8;
439 /* After reading callee registers in stack
440 * now blink,sec_stat,status32 registers
442 arc_cpu_saved_stacking
.stack_registers_size
= 12;
446 for (struct zephyr_params
*p
= zephyr_params_list
; p
->target_name
; p
++) {
447 if (!strcmp(p
->target_name
, name
)) {
448 LOG_INFO("Zephyr: target known, params at %p", p
);
449 target
->rtos
->rtos_specific_params
= p
;
454 LOG_ERROR("Could not find target in Zephyr compatibility list");
458 struct zephyr_array
{
463 static void zephyr_array_init(struct zephyr_array
*array
)
469 static void zephyr_array_free(struct zephyr_array
*array
)
472 zephyr_array_init(array
);
475 static void *zephyr_array_append(struct zephyr_array
*array
, size_t size
)
477 if (!(array
->elements
% 16)) {
478 void *ptr
= realloc(array
->ptr
, (array
->elements
+ 16) * size
);
481 LOG_ERROR("Out of memory");
488 return (unsigned char *)array
->ptr
+ (array
->elements
++) * size
;
491 static void *zephyr_array_detach_ptr(struct zephyr_array
*array
)
493 void *ptr
= array
->ptr
;
495 zephyr_array_init(array
);
500 static uint32_t zephyr_kptr(const struct rtos
*rtos
, enum zephyr_offsets off
)
502 const struct zephyr_params
*params
= rtos
->rtos_specific_params
;
504 return rtos
->symbols
[ZEPHYR_VAL__KERNEL
].address
+ params
->offsets
[off
];
507 static int zephyr_fetch_thread(const struct rtos
*rtos
,
508 struct zephyr_thread
*thread
, uint32_t ptr
)
510 const struct zephyr_params
*param
= rtos
->rtos_specific_params
;
515 retval
= target_read_u32(rtos
->target
, ptr
+ param
->offsets
[OFFSET_T_ENTRY
],
517 if (retval
!= ERROR_OK
)
520 retval
= target_read_u32(rtos
->target
,
521 ptr
+ param
->offsets
[OFFSET_T_NEXT_THREAD
],
523 if (retval
!= ERROR_OK
)
526 retval
= target_read_u32(rtos
->target
,
527 ptr
+ param
->offsets
[OFFSET_T_STACK_POINTER
],
528 &thread
->stack_pointer
);
529 if (retval
!= ERROR_OK
)
532 retval
= target_read_u8(rtos
->target
, ptr
+ param
->offsets
[OFFSET_T_STATE
],
534 if (retval
!= ERROR_OK
)
537 retval
= target_read_u8(rtos
->target
,
538 ptr
+ param
->offsets
[OFFSET_T_USER_OPTIONS
],
539 &thread
->user_options
);
540 if (retval
!= ERROR_OK
)
544 retval
= target_read_u8(rtos
->target
,
545 ptr
+ param
->offsets
[OFFSET_T_PRIO
], &prio
);
546 if (retval
!= ERROR_OK
)
550 thread
->name
[0] = '\0';
551 if (param
->offsets
[OFFSET_T_NAME
] != UNIMPLEMENTED
) {
552 retval
= target_read_buffer(rtos
->target
,
553 ptr
+ param
->offsets
[OFFSET_T_NAME
],
554 sizeof(thread
->name
) - 1, (uint8_t *)thread
->name
);
555 if (retval
!= ERROR_OK
)
558 thread
->name
[sizeof(thread
->name
) - 1] = '\0';
561 LOG_DEBUG("Fetched thread%" PRIx32
": {entry@0x%" PRIx32
562 ", state=%" PRIu8
", useropts=%" PRIu8
", prio=%" PRId8
"}",
563 ptr
, thread
->entry
, thread
->state
, thread
->user_options
, thread
->prio
);
568 static int zephyr_fetch_thread_list(struct rtos
*rtos
, uint32_t current_thread
)
570 struct zephyr_array thread_array
;
571 struct zephyr_thread thread
;
572 struct thread_detail
*td
;
573 int64_t curr_id
= -1;
577 retval
= target_read_u32(rtos
->target
, zephyr_kptr(rtos
, OFFSET_K_THREADS
),
579 if (retval
!= ERROR_OK
) {
580 LOG_ERROR("Could not fetch current thread pointer");
584 zephyr_array_init(&thread_array
);
586 for (; curr
; curr
= thread
.next_ptr
) {
587 retval
= zephyr_fetch_thread(rtos
, &thread
, curr
);
588 if (retval
!= ERROR_OK
)
591 td
= zephyr_array_append(&thread_array
, sizeof(*td
));
595 td
->threadid
= thread
.ptr
;
599 td
->thread_name_str
= strdup(thread
.name
);
601 td
->thread_name_str
= alloc_printf("thr_%" PRIx32
"_%" PRIx32
,
602 thread
.entry
, thread
.ptr
);
603 td
->extra_info_str
= alloc_printf("prio:%" PRId8
",useropts:%" PRIu8
,
604 thread
.prio
, thread
.user_options
);
605 if (!td
->thread_name_str
|| !td
->extra_info_str
)
608 if (td
->threadid
== current_thread
)
609 curr_id
= (int64_t)thread_array
.elements
- 1;
612 LOG_DEBUG("Got information for %zu threads", thread_array
.elements
);
614 rtos_free_threadlist(rtos
);
616 rtos
->thread_count
= (int)thread_array
.elements
;
617 rtos
->thread_details
= zephyr_array_detach_ptr(&thread_array
);
619 rtos
->current_threadid
= curr_id
;
620 rtos
->current_thread
= current_thread
;
625 td
= thread_array
.ptr
;
626 for (size_t i
= 0; i
< thread_array
.elements
; i
++) {
627 free(td
[i
].thread_name_str
);
628 free(td
[i
].extra_info_str
);
631 zephyr_array_free(&thread_array
);
636 static int zephyr_update_threads(struct rtos
*rtos
)
638 struct zephyr_params
*param
;
641 if (!rtos
->rtos_specific_params
)
644 param
= (struct zephyr_params
*)rtos
->rtos_specific_params
;
646 if (!rtos
->symbols
) {
647 LOG_ERROR("No symbols for Zephyr");
651 if (rtos
->symbols
[ZEPHYR_VAL__KERNEL
].address
== 0) {
652 LOG_ERROR("Can't obtain kernel struct from Zephyr");
656 if (rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
].address
== 0) {
657 LOG_ERROR("Please build Zephyr with CONFIG_OPENOCD option set");
661 retval
= target_read_u8(rtos
->target
,
662 rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE
].address
,
664 if (retval
!= ERROR_OK
) {
665 LOG_ERROR("Couldn't determine size of size_t from host");
669 if (param
->size_width
!= 4) {
670 LOG_ERROR("Only size_t of 4 bytes are supported");
674 if (rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS
].address
) {
675 retval
= target_read_u32(rtos
->target
,
676 rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS
].address
,
677 ¶m
->num_offsets
);
678 if (retval
!= ERROR_OK
) {
679 LOG_ERROR("Couldn't not fetch number of offsets from Zephyr");
683 if (param
->num_offsets
<= OFFSET_T_STACK_POINTER
) {
684 LOG_ERROR("Number of offsets too small");
688 retval
= target_read_u32(rtos
->target
,
689 rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
].address
,
690 ¶m
->offsets
[OFFSET_VERSION
]);
691 if (retval
!= ERROR_OK
) {
692 LOG_ERROR("Couldn't not fetch offsets from Zephyr");
696 if (param
->offsets
[OFFSET_VERSION
] > 1) {
697 LOG_ERROR("Unexpected OpenOCD support version %" PRIu32
,
698 param
->offsets
[OFFSET_VERSION
]);
701 switch (param
->offsets
[OFFSET_VERSION
]) {
703 param
->num_offsets
= OFFSET_T_STACK_POINTER
+ 1;
706 param
->num_offsets
= OFFSET_T_COOP_FLOAT
+ 1;
710 /* We can fetch the whole array for version 0, as they're supposed
713 address
= rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
].address
;
714 for (size_t i
= 0; i
< OFFSET_MAX
; i
++, address
+= param
->size_width
) {
715 if (i
>= param
->num_offsets
) {
716 param
->offsets
[i
] = UNIMPLEMENTED
;
720 retval
= target_read_u32(rtos
->target
, address
, ¶m
->offsets
[i
]);
721 if (retval
!= ERROR_OK
) {
722 LOG_ERROR("Could not fetch offsets from Zephyr");
727 LOG_DEBUG("Zephyr OpenOCD support version %" PRId32
,
728 param
->offsets
[OFFSET_VERSION
]);
730 uint32_t current_thread
;
731 retval
= target_read_u32(rtos
->target
,
732 zephyr_kptr(rtos
, OFFSET_K_CURR_THREAD
), ¤t_thread
);
733 if (retval
!= ERROR_OK
) {
734 LOG_ERROR("Could not obtain current thread ID");
738 retval
= zephyr_fetch_thread_list(rtos
, current_thread
);
739 if (retval
!= ERROR_OK
) {
740 LOG_ERROR("Could not obtain thread list");
747 static int zephyr_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
748 struct rtos_reg
**reg_list
, int *num_regs
)
750 struct zephyr_params
*params
;
751 struct rtos_reg
*callee_saved_reg_list
= NULL
;
755 LOG_INFO("Getting thread %" PRId64
" reg list", thread_id
);
763 params
= rtos
->rtos_specific_params
;
767 addr
= thread_id
+ params
->offsets
[OFFSET_T_STACK_POINTER
]
768 - params
->callee_saved_stacking
->register_offsets
[0].offset
;
770 retval
= params
->get_cpu_state(rtos
, &addr
, params
, callee_saved_reg_list
, reg_list
, num_regs
);
772 free(callee_saved_reg_list
);
777 static int zephyr_get_symbol_list_to_lookup(struct symbol_table_elem
**symbol_list
)
779 *symbol_list
= malloc(sizeof(zephyr_symbol_list
));
781 LOG_ERROR("Out of memory");
785 memcpy(*symbol_list
, zephyr_symbol_list
, sizeof(zephyr_symbol_list
));
789 const struct rtos_type zephyr_rtos
= {
792 .detect_rtos
= zephyr_detect_rtos
,
793 .create
= zephyr_create
,
794 .update_threads
= zephyr_update_threads
,
795 .get_thread_reg_list
= zephyr_get_thread_reg_list
,
796 .get_symbol_list_to_lookup
= zephyr_get_symbol_list_to_lookup
,
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)