1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
7 * Copyright (C) 2007,2008 Øyvind Harboe *
8 * oyvind.harboe@zylin.com *
10 * Copyright (C) 2008, Duane Ellis *
11 * openocd@duaneeellis.com *
13 * part of this file is taken from libcli (libcli.sourceforge.net) *
14 * Copyright (C) David Parrish (david@dparrish.com) *
15 ***************************************************************************/
21 /* @todo the inclusion of target.h here is a layering violation */
22 #include <jtag/jtag.h>
23 #include <target/target.h>
25 #include "configuration.h"
27 #include "time_support.h"
28 #include "jim-eventloop.h"
30 /* nice short description of source file */
31 #define __THIS__FILE__ "command.c"
33 struct log_capture_state
{
38 static int unregister_command(struct command_context
*context
,
39 const char *cmd_prefix
, const char *name
);
40 static int jim_command_dispatch(Jim_Interp
*interp
, int argc
, Jim_Obj
* const *argv
);
41 static int help_add_command(struct command_context
*cmd_ctx
,
42 const char *cmd_name
, const char *help_text
, const char *usage_text
);
43 static int help_del_command(struct command_context
*cmd_ctx
, const char *cmd_name
);
45 /* set of functions to wrap jimtcl internal data */
46 static inline bool jimcmd_is_proc(Jim_Cmd
*cmd
)
51 bool jimcmd_is_oocd_command(Jim_Cmd
*cmd
)
53 return !cmd
->isproc
&& cmd
->u
.native
.cmdProc
== jim_command_dispatch
;
56 void *jimcmd_privdata(Jim_Cmd
*cmd
)
58 return cmd
->isproc
? NULL
: cmd
->u
.native
.privData
;
61 static void tcl_output(void *privData
, const char *file
, unsigned line
,
62 const char *function
, const char *string
)
64 struct log_capture_state
*state
= privData
;
65 Jim_AppendString(state
->interp
, state
->output
, string
, strlen(string
));
68 static struct log_capture_state
*command_log_capture_start(Jim_Interp
*interp
)
70 /* capture log output and return it. A garbage collect can
71 * happen, so we need a reference count to this object */
72 Jim_Obj
*jim_output
= Jim_NewStringObj(interp
, "", 0);
76 Jim_IncrRefCount(jim_output
);
78 struct log_capture_state
*state
= malloc(sizeof(*state
));
80 LOG_ERROR("Out of memory");
81 Jim_DecrRefCount(interp
, jim_output
);
85 state
->interp
= interp
;
86 state
->output
= jim_output
;
88 log_add_callback(tcl_output
, state
);
93 /* Classic openocd commands provide progress output which we
94 * will capture and return as a Tcl return value.
96 * However, if a non-openocd command has been invoked, then it
97 * makes sense to return the tcl return value from that command.
99 * The tcl return value is empty for openocd commands that provide
102 * For other commands, we prepend the logs to the tcl return value.
104 static void command_log_capture_finish(struct log_capture_state
*state
)
109 log_remove_callback(tcl_output
, state
);
112 const char *log_result
= Jim_GetString(state
->output
, &loglen
);
114 const char *cmd_result
= Jim_GetString(Jim_GetResult(state
->interp
), &reslen
);
116 // Just in case the log doesn't end with a newline, we add it
117 if (loglen
!= 0 && reslen
!= 0 && log_result
[loglen
- 1] != '\n')
118 Jim_AppendString(state
->interp
, state
->output
, "\n", 1);
120 Jim_AppendString(state
->interp
, state
->output
, cmd_result
, reslen
);
122 Jim_SetResult(state
->interp
, state
->output
);
123 Jim_DecrRefCount(state
->interp
, state
->output
);
128 static int command_retval_set(Jim_Interp
*interp
, int retval
)
130 int *return_retval
= Jim_GetAssocData(interp
, "retval");
132 *return_retval
= retval
;
134 return (retval
== ERROR_OK
) ? JIM_OK
: retval
;
137 extern struct command_context
*global_cmd_ctx
;
139 /* dump a single line to the log for the command.
140 * Do nothing in case we are not at debug level 3 */
141 static void script_debug(Jim_Interp
*interp
, unsigned int argc
, Jim_Obj
* const *argv
)
143 if (debug_level
< LOG_LVL_DEBUG
)
146 char *dbg
= alloc_printf("command -");
147 for (unsigned i
= 0; i
< argc
; i
++) {
148 const char *w
= Jim_GetString(argv
[i
], NULL
);
149 char *t
= alloc_printf("%s %s", dbg
, w
);
153 LOG_DEBUG("%s", dbg
);
157 struct command_context
*current_command_context(Jim_Interp
*interp
)
159 /* grab the command context from the associated data */
160 struct command_context
*cmd_ctx
= Jim_GetAssocData(interp
, "context");
162 /* Tcl can invoke commands directly instead of via command_run_line(). This would
163 * happen when the Jim Tcl interpreter is provided by eCos or if we are running
164 * commands in a startup script.
166 * A telnet or gdb server would provide a non-default command context to
167 * handle piping of error output, have a separate current target, etc.
169 cmd_ctx
= global_cmd_ctx
;
175 * Find a openocd command from fullname.
176 * @returns Returns the named command if it is registred in interp.
177 * Returns NULL otherwise.
179 static struct command
*command_find_from_name(Jim_Interp
*interp
, const char *name
)
184 Jim_Obj
*jim_name
= Jim_NewStringObj(interp
, name
, -1);
185 Jim_IncrRefCount(jim_name
);
186 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, jim_name
, JIM_NONE
);
187 Jim_DecrRefCount(interp
, jim_name
);
188 if (!cmd
|| jimcmd_is_proc(cmd
) || !jimcmd_is_oocd_command(cmd
))
191 return jimcmd_privdata(cmd
);
194 static struct command
*command_new(struct command_context
*cmd_ctx
,
195 const char *full_name
, const struct command_registration
*cr
)
200 * If it is a non-jim command with no .usage specified,
203 * strlen(.usage) == 0 means that the command takes no
206 if (!cr
->jim_handler
&& !cr
->usage
)
207 LOG_ERROR("BUG: command '%s' does not have the "
208 "'.usage' field filled out",
211 struct command
*c
= calloc(1, sizeof(struct command
));
215 c
->name
= strdup(cr
->name
);
221 c
->handler
= cr
->handler
;
222 c
->jim_handler
= cr
->jim_handler
;
225 if (cr
->help
|| cr
->usage
)
226 help_add_command(cmd_ctx
, full_name
, cr
->help
, cr
->usage
);
231 static void command_free(struct Jim_Interp
*interp
, void *priv
)
233 struct command
*c
= priv
;
239 static struct command
*register_command(struct command_context
*context
,
240 const char *cmd_prefix
, const struct command_registration
*cr
)
244 if (!context
|| !cr
->name
)
248 full_name
= alloc_printf("%s %s", cmd_prefix
, cr
->name
);
250 full_name
= strdup(cr
->name
);
254 struct command
*c
= command_find_from_name(context
->interp
, full_name
);
256 /* TODO: originally we treated attempting to register a cmd twice as an error
257 * Sometimes we need this behaviour, such as with flash banks.
258 * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */
259 LOG_DEBUG("command '%s' is already registered", full_name
);
264 c
= command_new(context
, full_name
, cr
);
270 if (false) /* too noisy with debug_level 3 */
271 LOG_DEBUG("registering '%s'...", full_name
);
272 int retval
= Jim_CreateCommand(context
->interp
, full_name
,
273 jim_command_dispatch
, c
, command_free
);
274 if (retval
!= JIM_OK
) {
275 command_run_linef(context
, "del_help_text {%s}", full_name
);
276 command_run_linef(context
, "del_usage_text {%s}", full_name
);
286 int __register_commands(struct command_context
*cmd_ctx
, const char *cmd_prefix
,
287 const struct command_registration
*cmds
, void *data
,
288 struct target
*override_target
)
290 int retval
= ERROR_OK
;
292 for (i
= 0; cmds
[i
].name
|| cmds
[i
].chain
; i
++) {
293 const struct command_registration
*cr
= cmds
+ i
;
295 struct command
*c
= NULL
;
297 c
= register_command(cmd_ctx
, cmd_prefix
, cr
);
302 c
->jim_handler_data
= data
;
303 c
->jim_override_target
= override_target
;
308 char *new_prefix
= alloc_printf("%s %s", cmd_prefix
, cr
->name
);
313 retval
= __register_commands(cmd_ctx
, new_prefix
, cr
->chain
, data
, override_target
);
316 retval
= __register_commands(cmd_ctx
, cr
->name
, cr
->chain
, data
, override_target
);
319 retval
= __register_commands(cmd_ctx
, cmd_prefix
, cr
->chain
, data
, override_target
);
321 if (retval
!= ERROR_OK
)
325 if (retval
!= ERROR_OK
) {
326 for (unsigned j
= 0; j
< i
; j
++)
327 unregister_command(cmd_ctx
, cmd_prefix
, cmds
[j
].name
);
332 static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT
, 2, 3)))
333 int unregister_commands_match(struct command_context
*cmd_ctx
, const char *format
, ...)
335 Jim_Interp
*interp
= cmd_ctx
->interp
;
338 va_start(ap
, format
);
339 char *query
= alloc_vprintf(format
, ap
);
344 char *query_cmd
= alloc_printf("info commands {%s}", query
);
349 int retval
= Jim_EvalSource(interp
, __THIS__FILE__
, __LINE__
, query_cmd
);
351 if (retval
!= JIM_OK
)
354 Jim_Obj
*list
= Jim_GetResult(interp
);
355 Jim_IncrRefCount(list
);
357 int len
= Jim_ListLength(interp
, list
);
358 for (int i
= 0; i
< len
; i
++) {
359 Jim_Obj
*elem
= Jim_ListGetIndex(interp
, list
, i
);
360 Jim_IncrRefCount(elem
);
362 const char *name
= Jim_GetString(elem
, NULL
);
363 struct command
*c
= command_find_from_name(interp
, name
);
365 /* not openocd command */
366 Jim_DecrRefCount(interp
, elem
);
369 if (false) /* too noisy with debug_level 3 */
370 LOG_DEBUG("delete command \"%s\"", name
);
371 #if JIM_VERSION >= 80
372 Jim_DeleteCommand(interp
, elem
);
374 Jim_DeleteCommand(interp
, name
);
377 help_del_command(cmd_ctx
, name
);
379 Jim_DecrRefCount(interp
, elem
);
382 Jim_DecrRefCount(interp
, list
);
386 int unregister_all_commands(struct command_context
*context
,
387 const char *cmd_prefix
)
392 if (!cmd_prefix
|| !*cmd_prefix
)
393 return unregister_commands_match(context
, "*");
395 int retval
= unregister_commands_match(context
, "%s *", cmd_prefix
);
396 if (retval
!= ERROR_OK
)
399 return unregister_commands_match(context
, "%s", cmd_prefix
);
402 static int unregister_command(struct command_context
*context
,
403 const char *cmd_prefix
, const char *name
)
405 if (!context
|| !name
)
406 return ERROR_COMMAND_SYNTAX_ERROR
;
408 if (!cmd_prefix
|| !*cmd_prefix
)
409 return unregister_commands_match(context
, "%s", name
);
411 return unregister_commands_match(context
, "%s %s", cmd_prefix
, name
);
414 void command_output_text(struct command_context
*context
, const char *data
)
416 if (context
&& context
->output_handler
&& data
)
417 context
->output_handler(context
, data
);
420 void command_print_sameline(struct command_invocation
*cmd
, const char *format
, ...)
425 va_start(ap
, format
);
427 string
= alloc_vprintf(format
, ap
);
429 /* we want this collected in the log + we also want to pick it up as a tcl return
432 * The latter bit isn't precisely neat, but will do for now.
434 Jim_AppendString(cmd
->ctx
->interp
, cmd
->output
, string
, -1);
435 /* We already printed it above
436 * command_output_text(context, string); */
443 void command_print(struct command_invocation
*cmd
, const char *format
, ...)
448 va_start(ap
, format
);
450 string
= alloc_vprintf(format
, ap
);
452 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one
454 /* we want this collected in the log + we also want to pick it up as a tcl return
457 * The latter bit isn't precisely neat, but will do for now.
459 Jim_AppendString(cmd
->ctx
->interp
, cmd
->output
, string
, -1);
460 /* We already printed it above
461 * command_output_text(context, string); */
468 static bool command_can_run(struct command_context
*cmd_ctx
, struct command
*c
, const char *full_name
)
470 if (c
->mode
== COMMAND_ANY
|| c
->mode
== cmd_ctx
->mode
)
473 /* Many commands may be run only before/after 'init' */
482 /* handle the impossible with humor; it guarantees a bug report! */
484 when
= "if Cthulhu is summoned by";
487 LOG_ERROR("The '%s' command must be used %s 'init'.",
488 full_name
? full_name
: c
->name
, when
);
492 static int exec_command(Jim_Interp
*interp
, struct command_context
*context
,
493 struct command
*c
, int argc
, Jim_Obj
* const *argv
)
496 return c
->jim_handler(interp
, argc
, argv
);
499 const char **words
= malloc(argc
* sizeof(char *));
501 LOG_ERROR("Out of memory");
505 for (int i
= 0; i
< argc
; i
++)
506 words
[i
] = Jim_GetString(argv
[i
], NULL
);
508 struct command_invocation cmd
= {
514 .jimtcl_argv
= argv
+ 1,
517 cmd
.output
= Jim_NewEmptyStringObj(context
->interp
);
518 Jim_IncrRefCount(cmd
.output
);
520 int retval
= c
->handler(&cmd
);
521 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
522 /* Print help for command */
523 command_run_linef(context
, "usage %s", words
[0]);
524 } else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
) {
525 /* just fall through for a shutdown request */
527 if (retval
!= ERROR_OK
)
528 LOG_DEBUG("Command '%s' failed with error code %d",
531 * Use the command output as the Tcl result.
532 * Drop last '\n' to allow command output concatenation
533 * while keep using command_print() everywhere.
535 const char *output_txt
= Jim_String(cmd
.output
);
536 int len
= strlen(output_txt
);
537 if (len
&& output_txt
[len
- 1] == '\n')
539 Jim_SetResultString(context
->interp
, output_txt
, len
);
541 Jim_DecrRefCount(context
->interp
, cmd
.output
);
544 return command_retval_set(interp
, retval
);
547 int command_run_line(struct command_context
*context
, char *line
)
549 /* all the parent commands have been registered with the interpreter
550 * so, can just evaluate the line as a script and check for
553 /* run the line thru a script engine */
554 int retval
= ERROR_FAIL
;
556 /* Beware! This code needs to be reentrant. It is also possible
557 * for OpenOCD commands to be invoked directly from Tcl. This would
558 * happen when the Jim Tcl interpreter is provided by eCos for
561 struct target
*saved_target_override
= context
->current_target_override
;
562 context
->current_target_override
= NULL
;
564 Jim_Interp
*interp
= context
->interp
;
565 struct command_context
*old_context
= Jim_GetAssocData(interp
, "context");
566 Jim_DeleteAssocData(interp
, "context");
567 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
568 if (retcode
== JIM_OK
) {
569 /* associated the return value */
570 Jim_DeleteAssocData(interp
, "retval");
571 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
572 if (retcode
== JIM_OK
) {
573 retcode
= Jim_Eval_Named(interp
, line
, NULL
, 0);
575 Jim_DeleteAssocData(interp
, "retval");
577 Jim_DeleteAssocData(interp
, "context");
578 int inner_retcode
= Jim_SetAssocData(interp
, "context", NULL
, old_context
);
579 if (retcode
== JIM_OK
)
580 retcode
= inner_retcode
;
582 context
->current_target_override
= saved_target_override
;
583 if (retcode
== JIM_OK
) {
587 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
589 command_output_text(context
, result
);
590 command_output_text(context
, "\n");
593 } else if (retcode
== JIM_EXIT
) {
595 * exit(Jim_GetExitCode(interp)); */
596 } else if (retcode
== ERROR_COMMAND_CLOSE_CONNECTION
) {
599 Jim_MakeErrorMessage(interp
);
600 /* error is broadcast */
601 LOG_USER("%s", Jim_GetString(Jim_GetResult(interp
), NULL
));
603 if (retval
== ERROR_OK
) {
604 /* It wasn't a low level OpenOCD command that failed */
613 int command_run_linef(struct command_context
*context
, const char *format
, ...)
615 int retval
= ERROR_FAIL
;
618 va_start(ap
, format
);
619 string
= alloc_vprintf(format
, ap
);
621 retval
= command_run_line(context
, string
);
628 void command_set_output_handler(struct command_context
*context
,
629 command_output_handler_t output_handler
, void *priv
)
631 context
->output_handler
= output_handler
;
632 context
->output_handler_priv
= priv
;
635 struct command_context
*copy_command_context(struct command_context
*context
)
637 struct command_context
*copy_context
= malloc(sizeof(struct command_context
));
639 *copy_context
= *context
;
644 void command_done(struct command_context
*cmd_ctx
)
652 /* find full path to file */
653 COMMAND_HANDLER(handle_find
)
656 return ERROR_COMMAND_SYNTAX_ERROR
;
658 char *full_path
= find_file(CMD_ARGV
[0]);
660 return ERROR_COMMAND_ARGUMENT_INVALID
;
662 command_print(CMD
, "%s", full_path
);
668 COMMAND_HANDLER(handle_echo
)
670 if (CMD_ARGC
== 2 && !strcmp(CMD_ARGV
[0], "-n")) {
671 LOG_USER_N("%s", CMD_ARGV
[1]);
678 LOG_USER("%s", CMD_ARGV
[0]);
682 /* Return both the progress output (LOG_INFO and higher)
683 * and the tcl return value of a command.
685 static int jim_capture(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
690 struct log_capture_state
*state
= command_log_capture_start(interp
);
692 /* disable polling during capture. This avoids capturing output
695 * This is necessary in order to avoid accidentally getting a non-empty
696 * string for tcl fn's.
698 bool save_poll_mask
= jtag_poll_mask();
700 const char *str
= Jim_GetString(argv
[1], NULL
);
701 int retcode
= Jim_Eval_Named(interp
, str
, __THIS__FILE__
, __LINE__
);
703 jtag_poll_unmask(save_poll_mask
);
705 command_log_capture_finish(state
);
717 static COMMAND_HELPER(command_help_show
, struct help_entry
*c
,
718 bool show_help
, const char *cmd_match
);
720 static COMMAND_HELPER(command_help_show_list
, bool show_help
, const char *cmd_match
)
722 struct help_entry
*entry
;
724 list_for_each_entry(entry
, CMD_CTX
->help_list
, lh
)
725 CALL_COMMAND_HANDLER(command_help_show
, entry
, show_help
, cmd_match
);
729 #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
731 static void command_help_show_indent(unsigned n
)
733 for (unsigned i
= 0; i
< n
; i
++)
736 static void command_help_show_wrap(const char *str
, unsigned n
, unsigned n2
)
738 const char *cp
= str
, *last
= str
;
740 const char *next
= last
;
745 } while (*next
!= ' ' && *next
!= '\t' && *next
!= '\0');
746 } while ((next
- last
< HELP_LINE_WIDTH(n
)) && *next
!= '\0');
747 if (next
- last
< HELP_LINE_WIDTH(n
))
749 command_help_show_indent(n
);
750 LOG_USER("%.*s", (int)(cp
- last
), last
);
756 static COMMAND_HELPER(command_help_show
, struct help_entry
*c
,
757 bool show_help
, const char *cmd_match
)
760 for (const char *s
= strchr(c
->cmd_name
, ' '); s
; s
= strchr(s
+ 1, ' '))
763 /* If the match string occurs anywhere, we print out
764 * stuff for this command. */
765 bool is_match
= strstr(c
->cmd_name
, cmd_match
) ||
766 (c
->usage
&& strstr(c
->usage
, cmd_match
)) ||
767 (c
->help
&& strstr(c
->help
, cmd_match
));
770 if (c
->usage
&& strlen(c
->usage
) > 0) {
771 char *msg
= alloc_printf("%s %s", c
->cmd_name
, c
->usage
);
772 command_help_show_wrap(msg
, n
, n
+ 5);
775 command_help_show_wrap(c
->cmd_name
, n
, n
+ 5);
779 if (is_match
&& show_help
) {
782 /* TODO: factorize jim_command_mode() to avoid running jim command here */
783 char *request
= alloc_printf("command mode %s", c
->cmd_name
);
785 LOG_ERROR("Out of memory");
788 int retval
= Jim_Eval(CMD_CTX
->interp
, request
);
790 enum command_mode mode
= COMMAND_UNKNOWN
;
791 if (retval
!= JIM_ERR
) {
792 const char *result
= Jim_GetString(Jim_GetResult(CMD_CTX
->interp
), NULL
);
793 if (!strcmp(result
, "any"))
795 else if (!strcmp(result
, "config"))
796 mode
= COMMAND_CONFIG
;
797 else if (!strcmp(result
, "exec"))
801 /* Normal commands are runtime-only; highlight exceptions */
802 if (mode
!= COMMAND_EXEC
) {
803 const char *stage_msg
= "";
807 stage_msg
= " (configuration command)";
810 stage_msg
= " (command valid any time)";
813 stage_msg
= " (?mode error?)";
816 msg
= alloc_printf("%s%s", c
->help
? c
->help
: "", stage_msg
);
818 msg
= alloc_printf("%s", c
->help
? c
->help
: "");
821 command_help_show_wrap(msg
, n
+ 3, n
+ 3);
830 COMMAND_HANDLER(handle_help_command
)
832 bool full
= strcmp(CMD_NAME
, "help") == 0;
837 cmd_match
= strdup("");
840 cmd_match
= strdup(CMD_ARGV
[0]);
842 for (unsigned int i
= 1; i
< CMD_ARGC
&& cmd_match
; ++i
) {
843 char *prev
= cmd_match
;
844 cmd_match
= alloc_printf("%s %s", prev
, CMD_ARGV
[i
]);
850 LOG_ERROR("unable to build search string");
853 retval
= CALL_COMMAND_HANDLER(command_help_show_list
, full
, cmd_match
);
859 static char *alloc_concatenate_strings(int argc
, Jim_Obj
* const *argv
)
866 all
= strdup(Jim_GetString(argv
[0], NULL
));
868 LOG_ERROR("Out of memory");
872 for (i
= 1; i
< argc
; ++i
) {
874 all
= alloc_printf("%s %s", all
, Jim_GetString(argv
[i
], NULL
));
877 LOG_ERROR("Out of memory");
885 static int jim_command_dispatch(Jim_Interp
*interp
, int argc
, Jim_Obj
* const *argv
)
887 /* check subcommands */
889 char *s
= alloc_printf("%s %s", Jim_GetString(argv
[0], NULL
), Jim_GetString(argv
[1], NULL
));
890 Jim_Obj
*js
= Jim_NewStringObj(interp
, s
, -1);
891 Jim_IncrRefCount(js
);
893 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, js
, JIM_NONE
);
895 int retval
= Jim_EvalObjPrefix(interp
, js
, argc
- 2, argv
+ 2);
896 Jim_DecrRefCount(interp
, js
);
899 Jim_DecrRefCount(interp
, js
);
902 script_debug(interp
, argc
, argv
);
904 struct command
*c
= jim_to_command(interp
);
905 if (!c
->jim_handler
&& !c
->handler
) {
906 Jim_EvalObjPrefix(interp
, Jim_NewStringObj(interp
, "usage", -1), 1, argv
);
910 struct command_context
*cmd_ctx
= current_command_context(interp
);
912 if (!command_can_run(cmd_ctx
, c
, Jim_GetString(argv
[0], NULL
)))
915 target_call_timer_callbacks();
918 * Black magic of overridden current target:
919 * If the command we are going to handle has a target prefix,
920 * override the current target temporarily for the time
921 * of processing the command.
922 * current_target_override is used also for event handlers
923 * therefore we prevent touching it if command has no prefix.
924 * Previous override is saved and restored back to ensure
925 * correct work when jim_command_dispatch() is re-entered.
927 struct target
*saved_target_override
= cmd_ctx
->current_target_override
;
928 if (c
->jim_override_target
)
929 cmd_ctx
->current_target_override
= c
->jim_override_target
;
931 int retval
= exec_command(interp
, cmd_ctx
, c
, argc
, argv
);
933 if (c
->jim_override_target
)
934 cmd_ctx
->current_target_override
= saved_target_override
;
939 static int jim_command_mode(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
941 struct command_context
*cmd_ctx
= current_command_context(interp
);
942 enum command_mode mode
;
945 char *full_name
= alloc_concatenate_strings(argc
- 1, argv
+ 1);
948 Jim_Obj
*s
= Jim_NewStringObj(interp
, full_name
, -1);
950 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, s
, JIM_NONE
);
951 Jim_DecrRefCount(interp
, s
);
953 if (!cmd
|| !(jimcmd_is_proc(cmd
) || jimcmd_is_oocd_command(cmd
))) {
954 Jim_SetResultString(interp
, "unknown", -1);
958 if (jimcmd_is_proc(cmd
)) {
962 struct command
*c
= jimcmd_privdata(cmd
);
967 mode
= cmd_ctx
->mode
;
969 const char *mode_str
;
981 mode_str
= "unknown";
984 Jim_SetResultString(interp
, mode_str
, -1);
988 int help_del_all_commands(struct command_context
*cmd_ctx
)
990 struct help_entry
*curr
, *n
;
992 list_for_each_entry_safe(curr
, n
, cmd_ctx
->help_list
, lh
) {
994 free(curr
->cmd_name
);
1002 static int help_del_command(struct command_context
*cmd_ctx
, const char *cmd_name
)
1004 struct help_entry
*curr
;
1006 list_for_each_entry(curr
, cmd_ctx
->help_list
, lh
) {
1007 if (!strcmp(cmd_name
, curr
->cmd_name
)) {
1008 list_del(&curr
->lh
);
1009 free(curr
->cmd_name
);
1020 static int help_add_command(struct command_context
*cmd_ctx
,
1021 const char *cmd_name
, const char *help_text
, const char *usage_text
)
1023 int cmp
= -1; /* add after curr */
1024 struct help_entry
*curr
;
1026 list_for_each_entry_reverse(curr
, cmd_ctx
->help_list
, lh
) {
1027 cmp
= strcmp(cmd_name
, curr
->cmd_name
);
1032 struct help_entry
*entry
;
1034 entry
= calloc(1, sizeof(*entry
));
1036 LOG_ERROR("Out of memory");
1039 entry
->cmd_name
= strdup(cmd_name
);
1040 if (!entry
->cmd_name
) {
1041 LOG_ERROR("Out of memory");
1045 list_add(&entry
->lh
, &curr
->lh
);
1051 char *text
= strdup(help_text
);
1053 LOG_ERROR("Out of memory");
1061 char *text
= strdup(usage_text
);
1063 LOG_ERROR("Out of memory");
1067 entry
->usage
= text
;
1073 COMMAND_HANDLER(handle_help_add_command
)
1076 return ERROR_COMMAND_SYNTAX_ERROR
;
1078 const char *help
= !strcmp(CMD_NAME
, "add_help_text") ? CMD_ARGV
[1] : NULL
;
1079 const char *usage
= !strcmp(CMD_NAME
, "add_usage_text") ? CMD_ARGV
[1] : NULL
;
1080 if (!help
&& !usage
) {
1081 LOG_ERROR("command name '%s' is unknown", CMD_NAME
);
1082 return ERROR_COMMAND_SYNTAX_ERROR
;
1084 const char *cmd_name
= CMD_ARGV
[0];
1085 return help_add_command(CMD_CTX
, cmd_name
, help
, usage
);
1088 /* sleep command sleeps for <n> milliseconds
1089 * this is useful in target startup scripts
1091 COMMAND_HANDLER(handle_sleep_command
)
1094 if (CMD_ARGC
== 2) {
1095 if (strcmp(CMD_ARGV
[1], "busy") == 0)
1098 return ERROR_COMMAND_SYNTAX_ERROR
;
1099 } else if (CMD_ARGC
< 1 || CMD_ARGC
> 2)
1100 return ERROR_COMMAND_SYNTAX_ERROR
;
1102 unsigned long duration
= 0;
1103 int retval
= parse_ulong(CMD_ARGV
[0], &duration
);
1104 if (retval
!= ERROR_OK
)
1108 int64_t then
= timeval_ms();
1109 while (timeval_ms() - then
< (int64_t)duration
) {
1110 target_call_timer_callbacks_now();
1115 busy_sleep(duration
);
1120 static const struct command_registration command_subcommand_handlers
[] = {
1123 .mode
= COMMAND_ANY
,
1124 .jim_handler
= jim_command_mode
,
1125 .usage
= "[command_name ...]",
1126 .help
= "Returns the command modes allowed by a command: "
1127 "'any', 'config', or 'exec'. If no command is "
1128 "specified, returns the current command mode. "
1129 "Returns 'unknown' if an unknown command is given. "
1130 "Command can be multiple tokens.",
1132 COMMAND_REGISTRATION_DONE
1135 static const struct command_registration command_builtin_handlers
[] = {
1138 .mode
= COMMAND_ANY
,
1139 .handler
= handle_find
,
1140 .help
= "find full path to file",
1145 .mode
= COMMAND_ANY
,
1146 .jim_handler
= jim_capture
,
1147 .help
= "Capture progress output and return as tcl return value. If the "
1148 "progress output was empty, return tcl return value.",
1153 .handler
= handle_echo
,
1154 .mode
= COMMAND_ANY
,
1155 .help
= "Logs a message at \"user\" priority. "
1156 "Option \"-n\" suppresses trailing newline",
1157 .usage
= "[-n] string",
1160 .name
= "add_help_text",
1161 .handler
= handle_help_add_command
,
1162 .mode
= COMMAND_ANY
,
1163 .help
= "Add new command help text; "
1164 "Command can be multiple tokens.",
1165 .usage
= "command_name helptext_string",
1168 .name
= "add_usage_text",
1169 .handler
= handle_help_add_command
,
1170 .mode
= COMMAND_ANY
,
1171 .help
= "Add new command usage text; "
1172 "command can be multiple tokens.",
1173 .usage
= "command_name usage_string",
1177 .handler
= handle_sleep_command
,
1178 .mode
= COMMAND_ANY
,
1179 .help
= "Sleep for specified number of milliseconds. "
1180 "\"busy\" will busy wait instead (avoid this).",
1181 .usage
= "milliseconds ['busy']",
1185 .handler
= handle_help_command
,
1186 .mode
= COMMAND_ANY
,
1187 .help
= "Show full command help; "
1188 "command can be multiple tokens.",
1189 .usage
= "[command_name]",
1193 .handler
= handle_help_command
,
1194 .mode
= COMMAND_ANY
,
1195 .help
= "Show basic command usage; "
1196 "command can be multiple tokens.",
1197 .usage
= "[command_name]",
1201 .mode
= COMMAND_ANY
,
1202 .help
= "core command group (introspection)",
1203 .chain
= command_subcommand_handlers
,
1206 COMMAND_REGISTRATION_DONE
1209 struct command_context
*command_init(const char *startup_tcl
, Jim_Interp
*interp
)
1211 struct command_context
*context
= calloc(1, sizeof(struct command_context
));
1213 context
->mode
= COMMAND_EXEC
;
1215 /* context can be duplicated. Put list head on separate mem-chunk to keep list consistent */
1216 context
->help_list
= malloc(sizeof(*context
->help_list
));
1217 INIT_LIST_HEAD(context
->help_list
);
1219 /* Create a jim interpreter if we were not handed one */
1221 /* Create an interpreter */
1222 interp
= Jim_CreateInterp();
1223 /* Add all the Jim core commands */
1224 Jim_RegisterCoreCommands(interp
);
1225 Jim_InitStaticExtensions(interp
);
1228 context
->interp
= interp
;
1230 register_commands(context
, NULL
, command_builtin_handlers
);
1232 Jim_SetAssocData(interp
, "context", NULL
, context
);
1233 if (Jim_Eval_Named(interp
, startup_tcl
, "embedded:startup.tcl", 1) == JIM_ERR
) {
1234 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1235 Jim_MakeErrorMessage(interp
);
1236 LOG_USER_N("%s", Jim_GetString(Jim_GetResult(interp
), NULL
));
1239 Jim_DeleteAssocData(interp
, "context");
1244 void command_exit(struct command_context
*context
)
1249 Jim_FreeInterp(context
->interp
);
1250 free(context
->help_list
);
1251 command_done(context
);
1254 int command_context_mode(struct command_context
*cmd_ctx
, enum command_mode mode
)
1257 return ERROR_COMMAND_SYNTAX_ERROR
;
1259 cmd_ctx
->mode
= mode
;
1263 void process_jim_events(struct command_context
*cmd_ctx
)
1265 static int recursion
;
1270 Jim_ProcessEvents(cmd_ctx
->interp
, JIM_ALL_EVENTS
| JIM_DONT_WAIT
);
1274 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1275 int parse ## name(const char *str, type * ul) \
1278 LOG_ERROR("Invalid command argument"); \
1279 return ERROR_COMMAND_ARGUMENT_INVALID; \
1283 *ul = func(str, &end, 0); \
1285 LOG_ERROR("Invalid command argument"); \
1286 return ERROR_COMMAND_ARGUMENT_INVALID; \
1288 if ((max == *ul) && (errno == ERANGE)) { \
1289 LOG_ERROR("Argument overflow"); \
1290 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1292 if (min && (min == *ul) && (errno == ERANGE)) { \
1293 LOG_ERROR("Argument underflow"); \
1294 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1298 DEFINE_PARSE_NUM_TYPE(_ulong
, unsigned long, strtoul
, 0, ULONG_MAX
)
1299 DEFINE_PARSE_NUM_TYPE(_ullong
, unsigned long long, strtoull
, 0, ULLONG_MAX
)
1300 DEFINE_PARSE_NUM_TYPE(_long
, long, strtol
, LONG_MIN
, LONG_MAX
)
1301 DEFINE_PARSE_NUM_TYPE(_llong
, long long, strtoll
, LLONG_MIN
, LLONG_MAX
)
1303 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1304 int parse ## name(const char *str, type * ul) \
1307 int retval = parse ## funcname(str, &n); \
1308 if (retval != ERROR_OK) \
1311 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1313 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1318 #define DEFINE_PARSE_ULONGLONG(name, type, min, max) \
1319 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long long, _ullong)
1320 DEFINE_PARSE_ULONGLONG(_uint
, unsigned, 0, UINT_MAX
)
1321 DEFINE_PARSE_ULONGLONG(_u64
, uint64_t, 0, UINT64_MAX
)
1322 DEFINE_PARSE_ULONGLONG(_u32
, uint32_t, 0, UINT32_MAX
)
1323 DEFINE_PARSE_ULONGLONG(_u16
, uint16_t, 0, UINT16_MAX
)
1324 DEFINE_PARSE_ULONGLONG(_u8
, uint8_t, 0, UINT8_MAX
)
1326 DEFINE_PARSE_ULONGLONG(_target_addr
, target_addr_t
, 0, TARGET_ADDR_MAX
)
1328 #define DEFINE_PARSE_LONGLONG(name, type, min, max) \
1329 DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong)
1330 DEFINE_PARSE_LONGLONG(_int
, int, n
< INT_MIN
, INT_MAX
)
1331 DEFINE_PARSE_LONGLONG(_s64
, int64_t, n
< INT64_MIN
, INT64_MAX
)
1332 DEFINE_PARSE_LONGLONG(_s32
, int32_t, n
< INT32_MIN
, INT32_MAX
)
1333 DEFINE_PARSE_LONGLONG(_s16
, int16_t, n
< INT16_MIN
, INT16_MAX
)
1334 DEFINE_PARSE_LONGLONG(_s8
, int8_t, n
< INT8_MIN
, INT8_MAX
)
1336 static int command_parse_bool(const char *in
, bool *out
,
1337 const char *on
, const char *off
)
1339 if (strcasecmp(in
, on
) == 0)
1341 else if (strcasecmp(in
, off
) == 0)
1344 return ERROR_COMMAND_SYNTAX_ERROR
;
1348 int command_parse_bool_arg(const char *in
, bool *out
)
1350 if (command_parse_bool(in
, out
, "on", "off") == ERROR_OK
)
1352 if (command_parse_bool(in
, out
, "enable", "disable") == ERROR_OK
)
1354 if (command_parse_bool(in
, out
, "true", "false") == ERROR_OK
)
1356 if (command_parse_bool(in
, out
, "yes", "no") == ERROR_OK
)
1358 if (command_parse_bool(in
, out
, "1", "0") == ERROR_OK
)
1360 return ERROR_COMMAND_SYNTAX_ERROR
;
1363 COMMAND_HELPER(handle_command_parse_bool
, bool *out
, const char *label
)
1367 const char *in
= CMD_ARGV
[0];
1368 if (command_parse_bool_arg(in
, out
) != ERROR_OK
) {
1369 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME
, in
);
1370 return ERROR_COMMAND_SYNTAX_ERROR
;
1375 LOG_INFO("%s is %s", label
, *out
? "enabled" : "disabled");
1378 return ERROR_COMMAND_SYNTAX_ERROR
;
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)