Collect output from openocd commands into openocd_output local variable
[openocd.git] / src / openocd.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
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, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "log.h"
28 #include "types.h"
29 #include "jtag.h"
30 #include "configuration.h"
31 #include "xsvf.h"
32 #include "target.h"
33 #include "flash.h"
34 #include "nand.h"
35 #include "pld.h"
36
37 #include "command.h"
38 #include "server.h"
39 #include "telnet_server.h"
40 #include "gdb_server.h"
41 #include "tcl_server.h"
42
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <strings.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <errno.h>
51
52 #ifdef _WIN32
53 #include <malloc.h>
54 #else
55 #include <alloca.h>
56 #endif
57
58 #ifdef __ECOS
59 /* Jim is provied by eCos */
60 #include <cyg/jimtcl/jim.h>
61 #else
62 #define JIM_EMBEDDED
63 #include "jim.h"
64 #endif
65
66 #include "replacements.h"
67
68
69 /* Give TELNET a way to find out what version this is */
70 int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
71 {
72 command_print(cmd_ctx, OPENOCD_VERSION);
73
74 return ERROR_OK;
75 }
76
77 static int daemon_startup = 0;
78
79 int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
80 {
81 if (argc==0)
82 return ERROR_OK;
83 if (argc > 1 )
84 return ERROR_COMMAND_SYNTAX_ERROR;
85
86 daemon_startup = strcmp("reset", args[0])==0;
87
88 command_print(cmd_ctx, OPENOCD_VERSION);
89
90 return ERROR_OK;
91 }
92
93 void exit_handler(void)
94 {
95 /* close JTAG interface */
96 if (jtag && jtag->quit)
97 jtag->quit();
98 }
99
100 /* OpenOCD can't really handle failure of this command. Patches welcome! :-) */
101 int handle_init_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
102 {
103 int retval;
104 static int initialized=0;
105 if (initialized)
106 return ERROR_OK;
107
108 initialized=1;
109
110 atexit(exit_handler);
111
112 if (target_init(cmd_ctx) != ERROR_OK)
113 return ERROR_FAIL;
114 LOG_DEBUG("target init complete");
115
116 if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK)
117 {
118 /* we must be able to set up the jtag interface */
119 return retval;
120 }
121 LOG_DEBUG("jtag interface init complete");
122
123 /* Try to initialize & examine the JTAG chain at this point, but
124 * continue startup regardless */
125 if (jtag_init(cmd_ctx) == ERROR_OK)
126 {
127 LOG_DEBUG("jtag init complete");
128 if (target_examine(cmd_ctx) == ERROR_OK)
129 {
130 LOG_DEBUG("jtag examine complete");
131 }
132 }
133
134 if (flash_init_drivers(cmd_ctx) != ERROR_OK)
135 return ERROR_FAIL;
136 LOG_DEBUG("flash init complete");
137
138 if (nand_init(cmd_ctx) != ERROR_OK)
139 return ERROR_FAIL;
140 LOG_DEBUG("NAND init complete");
141
142 if (pld_init(cmd_ctx) != ERROR_OK)
143 return ERROR_FAIL;
144 LOG_DEBUG("pld init complete");
145
146 /* initialize tcp server */
147 server_init();
148
149 /* initialize telnet subsystem */
150 telnet_init("Open On-Chip Debugger");
151 gdb_init();
152 tcl_init(); /* allows tcl to just connect without going thru telnet */
153
154 return ERROR_OK;
155 }
156
157 Jim_Interp *interp;
158 command_context_t *active_cmd_ctx;
159
160 static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 val)
161 {
162 char *namebuf;
163 Jim_Obj *nameObjPtr, *valObjPtr;
164 int result;
165
166 namebuf = alloc_printf("%s(%d)", varname, idx);
167 if (!namebuf)
168 return JIM_ERR;
169
170 nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
171 valObjPtr = Jim_NewIntObj(interp, val);
172 if (!nameObjPtr || !valObjPtr)
173 {
174 free(namebuf);
175 return JIM_ERR;
176 }
177
178 Jim_IncrRefCount(nameObjPtr);
179 Jim_IncrRefCount(valObjPtr);
180 result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
181 Jim_DecrRefCount(interp, nameObjPtr);
182 Jim_DecrRefCount(interp, valObjPtr);
183 free(namebuf);
184 /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */
185 return result;
186 }
187
188 static int Jim_Command_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
189 {
190 target_t *target;
191 long l;
192 u32 width;
193 u32 len;
194 u32 addr;
195 u32 count;
196 u32 v;
197 const char *varname;
198 u8 buffer[4096];
199 int i, n, e, retval;
200
201 /* argv[1] = name of array to receive the data
202 * argv[2] = desired width
203 * argv[3] = memory address
204 * argv[4] = count of times to read
205 */
206 if (argc != 5) {
207 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
208 return JIM_ERR;
209 }
210 varname = Jim_GetString(argv[1], &len);
211 /* given "foo" get space for worse case "foo(%d)" .. add 20 */
212
213 e = Jim_GetLong(interp, argv[2], &l);
214 width = l;
215 if (e != JIM_OK) {
216 return e;
217 }
218
219 e = Jim_GetLong(interp, argv[3], &l);
220 addr = l;
221 if (e != JIM_OK) {
222 return e;
223 }
224 e = Jim_GetLong(interp, argv[4], &l);
225 len = l;
226 if (e != JIM_OK) {
227 return e;
228 }
229 switch (width) {
230 case 8:
231 width = 1;
232 break;
233 case 16:
234 width = 2;
235 break;
236 case 32:
237 width = 4;
238 break;
239 default:
240 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
241 Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
242 return JIM_ERR;
243 }
244 if (len == 0) {
245 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
246 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
247 return JIM_ERR;
248 }
249 if ((addr + (len * width)) < addr) {
250 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
251 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
252 return JIM_ERR;
253 }
254 /* absurd transfer size? */
255 if (len > 65536) {
256 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
257 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
258 return JIM_ERR;
259 }
260
261 if ((width == 1) ||
262 ((width == 2) && ((addr & 1) == 0)) ||
263 ((width == 4) && ((addr & 3) == 0))) {
264 /* all is well */
265 } else {
266 char buf[100];
267 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
268 sprintf(buf, "mem2array address: 0x%08x is not aligned for %d byte reads", addr, width);
269 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
270 return JIM_ERR;
271 }
272
273 target = get_current_target(active_cmd_ctx);
274
275 /* Transfer loop */
276
277 /* index counter */
278 n = 0;
279 /* assume ok */
280 e = JIM_OK;
281 while (len) {
282 /* Slurp... in buffer size chunks */
283
284 count = len; /* in objects.. */
285 if (count > (sizeof(buffer)/width)) {
286 count = (sizeof(buffer)/width);
287 }
288
289 retval = target->type->read_memory( target, addr, width, count, buffer );
290 if (retval != ERROR_OK) {
291 /* BOO !*/
292 LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
293 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
294 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
295 e = JIM_ERR;
296 len = 0;
297 } else {
298 v = 0; /* shut up gcc */
299 for (i = 0 ;i < count ;i++, n++) {
300 switch (width) {
301 case 4:
302 v = target_buffer_get_u32(target, &buffer[i*width]);
303 break;
304 case 2:
305 v = target_buffer_get_u16(target, &buffer[i*width]);
306 break;
307 case 1:
308 v = buffer[i] & 0x0ff;
309 break;
310 }
311 new_int_array_element(interp, varname, n, v);
312 }
313 len -= count;
314 }
315 }
316
317 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
318
319 return JIM_OK;
320 }
321
322 static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 *val)
323 {
324 char *namebuf;
325 Jim_Obj *nameObjPtr, *valObjPtr;
326 int result;
327 long l;
328
329 namebuf = alloc_printf("%s(%d)", varname, idx);
330 if (!namebuf)
331 return JIM_ERR;
332
333 nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
334 if (!nameObjPtr)
335 {
336 free(namebuf);
337 return JIM_ERR;
338 }
339
340 Jim_IncrRefCount(nameObjPtr);
341 valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
342 Jim_DecrRefCount(interp, nameObjPtr);
343 free(namebuf);
344 if (valObjPtr == NULL)
345 return JIM_ERR;
346
347 result = Jim_GetLong(interp, valObjPtr, &l);
348 /* printf("%s(%d) => 0%08x\n", varname, idx, val); */
349 *val = l;
350 return result;
351 }
352
353 static int Jim_Command_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
354 {
355 target_t *target;
356 long l;
357 u32 width;
358 u32 len;
359 u32 addr;
360 u32 count;
361 u32 v;
362 const char *varname;
363 u8 buffer[4096];
364 int i, n, e, retval;
365
366 /* argv[1] = name of array to get the data
367 * argv[2] = desired width
368 * argv[3] = memory address
369 * argv[4] = count to write
370 */
371 if (argc != 5) {
372 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
373 return JIM_ERR;
374 }
375 varname = Jim_GetString(argv[1], &len);
376 /* given "foo" get space for worse case "foo(%d)" .. add 20 */
377
378 e = Jim_GetLong(interp, argv[2], &l);
379 width = l;
380 if (e != JIM_OK) {
381 return e;
382 }
383
384 e = Jim_GetLong(interp, argv[3], &l);
385 addr = l;
386 if (e != JIM_OK) {
387 return e;
388 }
389 e = Jim_GetLong(interp, argv[4], &l);
390 len = l;
391 if (e != JIM_OK) {
392 return e;
393 }
394 switch (width) {
395 case 8:
396 width = 1;
397 break;
398 case 16:
399 width = 2;
400 break;
401 case 32:
402 width = 4;
403 break;
404 default:
405 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
406 Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
407 return JIM_ERR;
408 }
409 if (len == 0) {
410 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
411 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL);
412 return JIM_ERR;
413 }
414 if ((addr + (len * width)) < addr) {
415 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
416 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL);
417 return JIM_ERR;
418 }
419 /* absurd transfer size? */
420 if (len > 65536) {
421 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
422 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL);
423 return JIM_ERR;
424 }
425
426 if ((width == 1) ||
427 ((width == 2) && ((addr & 1) == 0)) ||
428 ((width == 4) && ((addr & 3) == 0))) {
429 /* all is well */
430 } else {
431 char buf[100];
432 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
433 sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads", addr, width);
434 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
435 return JIM_ERR;
436 }
437
438 target = get_current_target(active_cmd_ctx);
439
440 /* Transfer loop */
441
442 /* index counter */
443 n = 0;
444 /* assume ok */
445 e = JIM_OK;
446 while (len) {
447 /* Slurp... in buffer size chunks */
448
449 count = len; /* in objects.. */
450 if (count > (sizeof(buffer)/width)) {
451 count = (sizeof(buffer)/width);
452 }
453
454 v = 0; /* shut up gcc */
455 for (i = 0 ;i < count ;i++, n++) {
456 get_int_array_element(interp, varname, n, &v);
457 switch (width) {
458 case 4:
459 target_buffer_set_u32(target, &buffer[i*width], v);
460 break;
461 case 2:
462 target_buffer_set_u16(target, &buffer[i*width], v);
463 break;
464 case 1:
465 buffer[i] = v & 0x0ff;
466 break;
467 }
468 }
469 len -= count;
470
471 retval = target->type->write_memory(target, addr, width, count, buffer);
472 if (retval != ERROR_OK) {
473 /* BOO !*/
474 LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
475 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
476 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
477 e = JIM_ERR;
478 len = 0;
479 }
480 }
481
482 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
483
484 return JIM_OK;
485 }
486
487
488
489 /* find full path to file */
490 static int Jim_Command_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
491 {
492 if (argc != 2)
493 return JIM_ERR;
494 const char *file = Jim_GetString(argv[1], NULL);
495 char *full_path = find_file(file);
496 if (full_path == NULL)
497 return JIM_ERR;
498 Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
499 free(full_path);
500
501 Jim_SetResult(interp, result);
502 return JIM_OK;
503 }
504
505 static int Jim_Command_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
506 {
507 if (argc != 2)
508 return JIM_ERR;
509 char *str = (char*)Jim_GetString(argv[1], NULL);
510 LOG_USER("%s", str);
511 return JIM_OK;
512 }
513
514
515
516 static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
517 {
518 size_t nbytes;
519 const char *ptr;
520
521 /* make it a char easier to read code */
522 ptr = _ptr;
523
524 nbytes = size * n;
525 if (nbytes == 0) {
526 return 0;
527 }
528
529 if (!active_cmd_ctx) {
530 /* TODO: Where should this go? */
531 return n;
532 }
533
534 /* do we have to chunk it? */
535 if (ptr[nbytes] == 0) {
536 /* no it is a C style string */
537 command_output_text(active_cmd_ctx, ptr);
538 return strlen(ptr);
539 }
540 /* GRR we must chunk - not null terminated */
541 while (nbytes) {
542 char chunk[128+1];
543 int x;
544
545 x = nbytes;
546 if (x > 128) {
547 x = 128;
548 }
549 /* copy it */
550 memcpy(chunk, ptr, x);
551 /* terminate it */
552 chunk[n] = 0;
553 /* output it */
554 command_output_text(active_cmd_ctx, chunk);
555 ptr += x;
556 nbytes -= x;
557 }
558
559 return n;
560 }
561
562 static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie )
563 {
564 /* TCL wants to read... tell him no */
565 return 0;
566 }
567
568 static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
569 {
570 char *cp;
571 int n;
572
573 n = -1;
574 if (active_cmd_ctx) {
575 cp = alloc_vprintf(fmt, ap);
576 if (cp) {
577 command_output_text(active_cmd_ctx, cp);
578 n = strlen(cp);
579 free(cp);
580 }
581 }
582 return n;
583 }
584
585 static int openocd_jim_fflush(void *cookie)
586 {
587 /* nothing to flush */
588 return 0;
589 }
590
591 static char* openocd_jim_fgets(char *s, int size, void *cookie)
592 {
593 /* not supported */
594 errno = ENOTSUP;
595 return NULL;
596 }
597
598 void add_jim(const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
599 {
600 Jim_CreateCommand(interp, name, cmd, NULL, NULL);
601
602 /* FIX!!! it would be prettier to invoke add_help_text...
603 accumulate help text in Tcl helptext list. */
604 Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
605 if (Jim_IsShared(helptext))
606 helptext = Jim_DuplicateObj(interp, helptext);
607
608 Jim_Obj *cmd_entry=Jim_NewListObj(interp, NULL, 0);
609
610 Jim_Obj *cmd_list=Jim_NewListObj(interp, NULL, 0);
611 Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, name, -1));
612
613 Jim_ListAppendElement(interp, cmd_entry, cmd_list);
614 Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
615 Jim_ListAppendElement(interp, helptext, cmd_entry);
616 }
617
618 extern unsigned const char startup_tcl[];
619
620 void initJim(void)
621 {
622 Jim_CreateCommand(interp, "openocd_find", Jim_Command_find, NULL, NULL);
623 Jim_CreateCommand(interp, "echo", Jim_Command_echo, NULL, NULL);
624 Jim_CreateCommand(interp, "mem2array", Jim_Command_mem2array, NULL, NULL );
625 Jim_CreateCommand(interp, "array2mem", Jim_Command_array2mem, NULL, NULL );
626
627 /* Set Jim's STDIO */
628 interp->cookie_stdin = NULL;
629 interp->cookie_stdout = NULL;
630 interp->cookie_stderr = NULL;
631 interp->cb_fwrite = openocd_jim_fwrite;
632 interp->cb_fread = openocd_jim_fread ;
633 interp->cb_vfprintf = openocd_jim_vfprintf;
634 interp->cb_fflush = openocd_jim_fflush;
635 interp->cb_fgets = openocd_jim_fgets;
636
637 add_default_dirs();
638
639 if (Jim_Eval(interp, startup_tcl)==JIM_ERR)
640 {
641 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD compile time)");
642 Jim_PrintErrorMessage(interp);
643 exit(-1);
644 }
645 }
646
647 command_context_t *setup_command_handler(void)
648 {
649 command_context_t *cmd_ctx;
650
651 cmd_ctx = command_init();
652
653 register_command(cmd_ctx, NULL, "version", handle_version_command,
654 COMMAND_EXEC, "show OpenOCD version");
655 register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG,
656 "deprecated - use \"init\" and \"reset\" at end of startup script instead");
657
658 /* register subsystem commands */
659 server_register_commands(cmd_ctx);
660 telnet_register_commands(cmd_ctx);
661 gdb_register_commands(cmd_ctx);
662 tcl_register_commands(cmd_ctx); /* tcl server commands */
663 log_register_commands(cmd_ctx);
664 jtag_register_commands(cmd_ctx);
665 xsvf_register_commands(cmd_ctx);
666 target_register_commands(cmd_ctx);
667 flash_register_commands(cmd_ctx);
668 nand_register_commands(cmd_ctx);
669 pld_register_commands(cmd_ctx);
670
671 if (log_init(cmd_ctx) != ERROR_OK)
672 {
673 exit(-1);
674 }
675 LOG_DEBUG("log init complete");
676
677 LOG_OUTPUT( OPENOCD_VERSION "\n" );
678
679
680 register_command(cmd_ctx, NULL, "init", handle_init_command,
681 COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");
682
683 return cmd_ctx;
684 }
685
686 /* normally this is the main() function entry, but if OpenOCD is linked
687 * into application, then this fn will not be invoked, but rather that
688 * application will have it's own implementation of main(). */
689 int openocd_main(int argc, char *argv[])
690 {
691 #ifdef JIM_EMBEDDED
692 Jim_InitEmbedded();
693 /* Create an interpreter */
694 interp = Jim_CreateInterp();
695 /* Add all the Jim core commands */
696 Jim_RegisterCoreCommands(interp);
697 #endif
698
699 initJim();
700
701 /* initialize commandline interface */
702 command_context_t *cmd_ctx;
703 cmd_ctx=setup_command_handler();
704
705 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
706 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
707 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
708 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
709 /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
710 LOG_OUTPUT( "$URL$\n");
711 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
712 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
713 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
714 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
715 /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
716
717 command_context_mode(cmd_ctx, COMMAND_CONFIG);
718 command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
719
720 if (parse_cmdline_args(cmd_ctx, argc, argv) != ERROR_OK)
721 return EXIT_FAILURE;
722
723 if (parse_config_file(cmd_ctx) != ERROR_OK)
724 return EXIT_FAILURE;
725
726 command_context_mode(cmd_ctx, COMMAND_EXEC);
727 if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
728 return EXIT_FAILURE;
729
730 if (daemon_startup)
731 command_run_line(cmd_ctx, "reset");
732
733 /* handle network connections */
734 server_loop(cmd_ctx);
735
736 /* shut server down */
737 server_quit();
738
739 unregister_all_commands(cmd_ctx);
740
741 /* free commandline interface */
742 command_done(cmd_ctx);
743
744 return EXIT_SUCCESS;
745 }

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)