/* Top level stuff for GDB, the GNU debugger.
- Copyright 1986, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999
- Free Software Foundation, Inc.
+ Copyright 1986-2000 Free Software Foundation, Inc.
This file is part of GDB.
#include <sys/types.h>
-#include "event-loop.h"
+#include <setjmp.h>
+
#include "event-top.h"
#include "gdb_string.h"
#include "gdb_stat.h"
#include <ctype.h>
+#ifdef UI_OUT
+#include "ui-out.h"
+#include "cli-out.h"
+#endif
/* Prototypes for local functions */
static void do_nothing PARAMS ((int));
+static void show_debug PARAMS ((char *, int));
+
+static void set_debug PARAMS ((char *, int));
+
#ifdef SIGHUP
/* NOTE 1999-04-29: This function will be static again, once we modify
gdb to use the event loop as the default command loop and we merge
struct cmd_list_element *showprintlist;
+struct cmd_list_element *setdebuglist;
+
+struct cmd_list_element *showdebuglist;
+
struct cmd_list_element *setchecklist;
struct cmd_list_element *showchecklist;
int linesize = 100;
/* Nonzero if the current command is modified by "server ". This
- affects things like recording into the command history, comamnds
+ affects things like recording into the command history, commands
repeating on RETURN, etc. This is so a user interface (emacs, GUI,
whatever) can issue its own commands and also send along commands
from the user, and have the user not notice that the user interface
/* Timeout limit for response from target. */
-int remote_timeout = 20; /* Set default to 20 */
+/* The default value has been changed many times over the years. It
+ was originally 5 seconds. But that was thought to be a long time
+ to sit and wait, so it was changed to 2 seconds. That was thought
+ to be plenty unless the connection was going through some terminal
+ server or multiplexer or other form of hairy serial connection.
+
+ In mid-1996, remote_timeout was moved from remote.c to top.c and
+ it began being used in other remote-* targets. It appears that the
+ default was changed to 20 seconds at that time, perhaps because the
+ Hitachi E7000 ICE didn't always respond in a timely manner.
+
+ But if 5 seconds is a long time to sit and wait for retransmissions,
+ 20 seconds is far worse. This demonstrates the difficulty of using
+ a single variable for all protocol timeouts.
+
+ As remote.c is used much more than remote-e7000.c, it was changed
+ back to 2 seconds in 1999. */
+
+int remote_timeout = 2;
/* Non-zero tells remote* modules to output debugging info. */
void (*command_loop_hook) PARAMS ((void));
-/* Called instead of fputs for all output. */
-
-void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, GDB_FILE * stream));
-
/* Called from print_frame_info to list the line we stopped in. */
void (*print_frame_info_listing_hook) PARAMS ((struct symtab * s, int line,
void (*warning_hook) PARAMS ((const char *, va_list));
-/* Called from gdb_flush to flush output. */
-
-void (*flush_hook) PARAMS ((GDB_FILE * stream));
-
/* These three functions support getting lines of text from the user. They
are used in sequence. First readline_begin_hook is called with a text
string that might be (for example) a message for the user to type in a
void (*delete_breakpoint_hook) PARAMS ((struct breakpoint * bpt));
void (*modify_breakpoint_hook) PARAMS ((struct breakpoint * bpt));
+/* Called as appropriate to notify the interface that we have attached
+ to or detached from an already running process. */
+
+void (*attach_hook) PARAMS ((void));
+void (*detach_hook) PARAMS ((void));
+
/* Called during long calculations to allow GUI to repair window damage, and to
check for stop buttons, etc... */
PARAMS ((void)) ATTR_NORETURN;
\f
-/* Where to go for return_to_top_level (RETURN_ERROR). */
- SIGJMP_BUF error_return;
-/* Where to go for return_to_top_level (RETURN_QUIT). */
- SIGJMP_BUF quit_return;
+/* One should use catch_errors rather than manipulating these
+ directly. */
+#if defined(HAVE_SIGSETJMP)
+#define SIGJMP_BUF sigjmp_buf
+#define SIGSETJMP(buf) sigsetjmp(buf, 1)
+#define SIGLONGJMP(buf,val) siglongjmp(buf,val)
+#else
+#define SIGJMP_BUF jmp_buf
+#define SIGSETJMP(buf) setjmp(buf)
+#define SIGLONGJMP(buf,val) longjmp(buf,val)
+#endif
-/* Return for reason REASON. This generally gets back to the command
- loop, but can be caught via catch_errors. */
+/* Where to go for return_to_top_level. */
+static SIGJMP_BUF *catch_return;
- NORETURN void
- return_to_top_level (reason)
+/* Return for reason REASON to the nearest containing catch_errors(). */
+
+NORETURN void
+return_to_top_level (reason)
enum return_reason reason;
{
quit_flag = 0;
disable_current_display ();
do_cleanups (ALL_CLEANUPS);
- if (async_p && target_has_async)
+ if (event_loop_p && target_can_async_p () && !target_executing)
do_exec_cleanups (ALL_CLEANUPS);
+ if (event_loop_p && sync_execution)
+ do_exec_error_cleanups (ALL_CLEANUPS);
if (annotation_level > 1)
switch (reason)
break;
}
- (NORETURN void) SIGLONGJMP
- (reason == RETURN_ERROR ? error_return : quit_return, 1);
+ /* Jump to the containing catch_errors() call, communicating REASON
+ to that call via setjmp's return value. Note that REASON can't
+ be zero, by definition in defs.h. */
+
+ (NORETURN void) SIGLONGJMP (*catch_return, (int)reason);
}
/* Call FUNC with arg ARGS, catching any errors. If there is no
catch_errors. Note that quit should return to the command line
fairly quickly, even if some further processing is being done. */
+/* MAYBE: cagney/1999-11-05: catch_errors() in conjunction with
+ error() et.al. could maintain a set of flags that indicate the the
+ current state of each of the longjmp buffers. This would give the
+ longjmp code the chance to detect a longjmp botch (before it gets
+ to longjmperror()). Prior to 1999-11-05 this wasn't possible as
+ code also randomly used a SET_TOP_LEVEL macro that directly
+ initialize the longjmp buffers. */
+
+/* MAYBE: cagney/1999-11-05: Should the catch_erros and cleanups code
+ be consolidated into a single file instead of being distributed
+ between utils.c and top.c? */
+
int
catch_errors (func, args, errstring, mask)
catch_errors_ftype *func;
char *errstring;
return_mask mask;
{
- SIGJMP_BUF saved_error;
- SIGJMP_BUF saved_quit;
- SIGJMP_BUF tmp_jmp;
+ SIGJMP_BUF *saved_catch;
+ SIGJMP_BUF catch;
int val;
struct cleanup *saved_cleanup_chain;
char *saved_error_pre_print;
char *saved_quit_pre_print;
- saved_cleanup_chain = save_cleanups ();
+ /* Return value from SIGSETJMP(): enum return_reason if error or
+ quit caught, 0 otherwise. */
+ int caught;
+
+ /* Override error/quit messages during FUNC. */
+
saved_error_pre_print = error_pre_print;
saved_quit_pre_print = quit_pre_print;
if (mask & RETURN_MASK_ERROR)
- {
- memcpy ((char *) saved_error, (char *) error_return, sizeof (SIGJMP_BUF));
- error_pre_print = errstring;
- }
+ error_pre_print = errstring;
if (mask & RETURN_MASK_QUIT)
- {
- memcpy (saved_quit, quit_return, sizeof (SIGJMP_BUF));
- quit_pre_print = errstring;
- }
+ quit_pre_print = errstring;
- if (SIGSETJMP (tmp_jmp) == 0)
- {
- if (mask & RETURN_MASK_ERROR)
- memcpy (error_return, tmp_jmp, sizeof (SIGJMP_BUF));
- if (mask & RETURN_MASK_QUIT)
- memcpy (quit_return, tmp_jmp, sizeof (SIGJMP_BUF));
- val = (*func) (args);
- }
- else
- val = 0;
+ /* Prevent error/quit during FUNC from calling cleanups established
+ prior to here. */
+
+ saved_cleanup_chain = save_cleanups ();
+
+ /* Call FUNC, catching error/quit events. */
+
+ saved_catch = catch_return;
+ catch_return = &catch;
+ caught = SIGSETJMP (catch);
+ if (!caught)
+ val = (*func) (args);
+ catch_return = saved_catch;
+
+ /* FIXME: cagney/1999-11-05: A correct FUNC implementaton will
+ clean things up (restoring the cleanup chain) to the state they
+ were just prior to the call. Unfortunatly, many FUNC's are not
+ that well behaved. This could be fixed by adding either a
+ do_cleanups call (to cover the problem) or an assertion check to
+ detect bad FUNCs code. */
+
+ /* Restore the cleanup chain and error/quit messages to their
+ original states. */
restore_cleanups (saved_cleanup_chain);
- if (mask & RETURN_MASK_ERROR)
- {
- memcpy (error_return, saved_error, sizeof (SIGJMP_BUF));
- error_pre_print = saved_error_pre_print;
- }
if (mask & RETURN_MASK_QUIT)
- {
- memcpy (quit_return, saved_quit, sizeof (SIGJMP_BUF));
- quit_pre_print = saved_quit_pre_print;
- }
- return val;
+ quit_pre_print = saved_quit_pre_print;
+ if (mask & RETURN_MASK_ERROR)
+ error_pre_print = saved_error_pre_print;
+
+ /* Return normally if no error/quit event occurred. */
+
+ if (!caught)
+ return val;
+
+ /* If the caller didn't request that the event be caught, relay the
+ event to the next containing catch_errors(). */
+
+ if (!(mask & RETURN_MASK (caught)))
+ return_to_top_level (caught);
+
+ /* Tell the caller that an event was caught.
+
+ FIXME: nsd/2000-02-22: When MASK is RETURN_MASK_ALL, the caller
+ can't tell what type of event occurred.
+
+ A possible fix is to add a new interface, catch_event(), that
+ returns enum return_reason after catching an error or a quit.
+
+ When returning normally, i.e. without catching an error or a
+ quit, catch_event() could return RETURN_NORMAL, which would be
+ added to enum return_reason. FUNC would return information
+ exclusively via ARGS.
+
+ Alternatively, normal catch_event() could return FUNC's return
+ value. The caller would need to be aware of potential overlap
+ with enum return_reason, which could be publicly restricted to
+ negative values to simplify return value processing in FUNC and
+ in the caller. */
+
+ return 0;
}
+struct captured_command_args
+ {
+ catch_command_errors_ftype *command;
+ char *arg;
+ int from_tty;
+ };
+
+static int
+do_captured_command (void *data)
+{
+ struct captured_command_args *context = data;
+ context->command (context->arg, context->from_tty);
+ /* FIXME: cagney/1999-11-07: Technically this do_cleanups() call
+ isn't needed. Instead an assertion check could be made that
+ simply confirmed that the called function correctly cleaned up
+ after its self. Unfortunatly, old code (prior to 1999-11-04) in
+ main.c was calling SET_TOP_LEVEL(), calling the command function,
+ and then *always* calling do_cleanups(). For the moment we
+ remain ``bug compatible'' with that old code.. */
+ do_cleanups (ALL_CLEANUPS);
+ return 1;
+}
+
+int
+catch_command_errors (catch_command_errors_ftype *command,
+ char *arg, int from_tty, return_mask mask)
+{
+ struct captured_command_args args;
+ args.command = command;
+ args.arg = arg;
+ args.from_tty = from_tty;
+ return catch_errors (do_captured_command, &args, "", mask);
+}
+
+
/* Handler for SIGHUP. */
#ifdef SIGHUP
initialize_targets (); /* Setup target_terminal macros for utils.c */
initialize_utils (); /* Make errors and warnings possible */
initialize_all_files ();
+ initialize_current_architecture ();
init_main (); /* But that omits this file! Do it now */
/* The signal handling mechanism is different depending whether or
not the async version is run. NOTE: in the future we plan to make
the event loop be the default engine of gdb, and this difference
will disappear. */
- if (async_p)
+ if (event_loop_p)
async_init_signals ();
else
init_signals ();
set_language (language_c);
expected_language = current_language; /* don't warn about the change. */
+#ifdef UI_OUT
+ /* Install the default UI */
+ uiout = cli_out_new (gdb_stdout);
+#endif
+
+#ifdef UI_OUT
/* All the interpreters should have had a look at things by now.
Initialize the selected interpreter. */
+ if (interpreter_p && !init_ui_hook)
+ {
+ fprintf_unfiltered (gdb_stderr, "Interpreter `%s' unrecognized.\n",
+ interpreter_p);
+ exit (1);
+ }
+#endif
+
if (init_ui_hook)
init_ui_hook (argv0);
}
}
/* Recursively print a command (including full control structures). */
+#ifdef UI_OUT
+void
+print_command_lines (uiout, cmd, depth)
+ struct ui_out *uiout;
+ struct command_line *cmd;
+ unsigned int depth;
+{
+ struct command_line *list;
+
+ list = cmd;
+ while (list)
+ {
+
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+
+ /* A simple command, print it and continue. */
+ if (list->control_type == simple_control)
+ {
+ ui_out_field_string (uiout, NULL, list->line);
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* loop_continue to jump to the start of a while loop, print it
+ and continue. */
+ if (list->control_type == continue_control)
+ {
+ ui_out_field_string (uiout, NULL, "loop_continue");
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* loop_break to break out of a while loop, print it and continue. */
+ if (list->control_type == break_control)
+ {
+ ui_out_field_string (uiout, NULL, "loop_break");
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* A while command. Recursively print its subcommands and continue. */
+ if (list->control_type == while_control)
+ {
+ ui_out_text (uiout, "while ");
+ ui_out_field_fmt (uiout, NULL, "while %s", list->line);
+ ui_out_text (uiout, "\n");
+ print_command_lines (uiout, *list->body_list, depth + 1);
+ ui_out_field_string (uiout, NULL, "end");
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+ ui_out_text (uiout, "end\n");
+ list = list->next;
+ continue;
+ }
+
+ /* An if command. Recursively print both arms before continueing. */
+ if (list->control_type == if_control)
+ {
+ ui_out_text (uiout, "if ");
+ ui_out_field_fmt (uiout, NULL, "if %s", list->line);
+ ui_out_text (uiout, "\n");
+ /* The true arm. */
+ print_command_lines (uiout, list->body_list[0], depth + 1);
+
+ /* Show the false arm if it exists. */
+ if (list->body_count == 2)
+ {
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+ ui_out_field_string (uiout, NULL, "else");
+ ui_out_text (uiout, "else\n");
+ print_command_lines (uiout, list->body_list[1], depth + 1);
+ }
+
+ ui_out_field_string (uiout, NULL, "end");
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+ ui_out_text (uiout, "end\n");
+ list = list->next;
+ continue;
+ }
+
+ /* ignore illegal command type and try next */
+ list = list->next;
+ } /* while (list) */
+}
+#else
void
print_command_line (cmd, depth, stream)
struct command_line *cmd;
unsigned int depth;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
unsigned int i;
fputs_filtered ("end\n", stream);
}
}
+#endif
/* Execute the command in CMD. */
register struct cmd_list_element *c;
register enum language flang;
static int warned = 0;
+ char *line;
/* FIXME: These should really be in an appropriate header file */
extern void serial_log_command PARAMS ((const char *));
if (*p)
{
char *arg;
-
+ line = p;
+
c = lookup_cmd (&p, cmdlist, "", 0, 1);
/* If the target is running, we allow only a limited set of
commands. */
- if (async_p && target_has_async && target_executing)
+ if (event_loop_p && target_can_async_p () && target_executing)
if (!strcmp (c->name, "help")
&& !strcmp (c->name, "pwd")
&& !strcmp (c->name, "show")
p--;
*(p + 1) = '\0';
}
-
+
/* If this command has been hooked, run the hook first. */
if (c->hook)
execute_user_command (c->hook, (char *) 0);
+ if (c->flags & DEPRECATED_WARN_USER)
+ deprecated_cmd_warning (&line);
+
if (c->class == class_user)
execute_user_command (c, arg);
else if (c->type == set_cmd || c->type == show_cmd)
}
}
+/* Read commands from `instream' and execute them until end of file or
+ error reading instream. This command loop doesnt care about any
+ such things as displaying time and space usage. If the user asks
+ for those, they won't work. */
+void
+simplified_command_loop (read_input_func, execute_command_func)
+ char *(*read_input_func) (char *);
+ void (*execute_command_func) (char *, int);
+{
+ struct cleanup *old_chain;
+ char *command;
+ int stdin_is_tty = ISATTY (stdin);
+
+ while (instream && !feof (instream))
+ {
+ quit_flag = 0;
+ if (instream == stdin && stdin_is_tty)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup ((make_cleanup_func) command_loop_marker, 0);
+
+ /* Get a command-line. */
+ command = (*read_input_func) (instream == stdin ?
+ get_prompt () : (char *) NULL);
+
+ if (command == 0)
+ return;
+
+ (*execute_command_func) (command, instream == stdin);
+
+ /* Do any commands attached to breakpoint we stopped at. */
+ bpstat_do_actions (&stop_bpstat);
+
+ do_cleanups (old_chain);
+ }
+}
\f
/* Commands call this if they do not want to be repeated by null lines. */
#ifdef STOP_SIGNAL
if (job_control)
{
- if (async_p)
+ if (event_loop_p)
signal (STOP_SIGNAL, handle_stop_sig);
else
signal (STOP_SIGNAL, stop_sig);
\f
/* Add an element to the list of info subcommands. */
-void
+struct cmd_list_element *
add_info (name, fun, doc)
char *name;
void (*fun) PARAMS ((char *, int));
char *doc;
{
- add_cmd (name, no_class, fun, doc, &infolist);
+ return add_cmd (name, no_class, fun, doc, &infolist);
}
/* Add an alias to the list of info subcommands. */
-void
+struct cmd_list_element *
add_info_alias (name, oldname, abbrev_flag)
char *name;
char *oldname;
int abbrev_flag;
{
- add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
+ return add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
}
/* The "info" command is defined as a prefix, with allow_unknown = 0.
\f
/* Add an element to the list of commands. */
-void
+struct cmd_list_element *
add_com (name, class, fun, doc)
char *name;
enum command_class class;
void (*fun) PARAMS ((char *, int));
char *doc;
{
- add_cmd (name, class, fun, doc, &cmdlist);
+ return add_cmd (name, class, fun, doc, &cmdlist);
}
/* Add an alias or abbreviation command to the list of commands. */
-void
+struct cmd_list_element *
add_com_alias (name, oldname, class, abbrev_flag)
char *name;
char *oldname;
enum command_class class;
int abbrev_flag;
{
- add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
+ return add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
}
void
/* Print the GDB banner. */
void
print_gdb_version (stream)
- GDB_FILE *stream;
+ struct ui_file *stream;
{
/* From GNU coding standards, first line is meant to be easy for a
program to parse, and is just canonical program name and version
number, which starts after last space. */
+#ifdef UI_OUT
+ /* Print it console style until a format is defined */
+ fprintf_filtered (stream, "GNU gdb %s (UI_OUT)\n", version);
+#else
fprintf_filtered (stream, "GNU gdb %s\n", version);
+#endif
/* Second line is a copyright notice. */
- fprintf_filtered (stream, "Copyright 1998 Free Software Foundation, Inc.\n");
+ fprintf_filtered (stream, "Copyright 2000 Free Software Foundation, Inc.\n");
/* Following the copyright is a brief statement that the program is
free software, that users are free to copy and change it on
{
char *local_prompt;
- if (async_p)
+ if (event_loop_p)
local_prompt = PROMPT (0);
else
local_prompt = gdb_prompt_string;
else
{
/* Prompt could not be formatted. */
- if (async_p)
+ if (event_loop_p)
return PROMPT (0);
else
return gdb_prompt_string;
if (prompt != NULL)
free (prompt);
*/
- if (async_p)
+ if (event_loop_p)
PROMPT (0) = savestring (s, strlen (s));
else
gdb_prompt_string = savestring (s, strlen (s));
signal (SIGFPE, float_handler);
error ("Erroneous arithmetic operation.");
}
-\f
+
+static void
+set_debug (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf_unfiltered (
+ "\"set debug\" must be followed by the name of a print subcommand.\n");
+ help_list (setdebuglist, "set debug ", -1, gdb_stdout);
+}
+
+static void
+show_debug (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ cmd_show_list (showdebuglist, from_tty, "");
+}
static void
init_cmd_lists ()
/* If we are running the asynchronous version,
we initialize the prompts differently. */
- if (!async_p)
+ if (!event_loop_p)
{
gdb_prompt_string = savestring (DEFAULT_PROMPT, strlen (DEFAULT_PROMPT));
}
async version is run. NOTE: this difference is going to
disappear as we make the event loop be the default engine of
gdb. */
- if (!async_p)
+ if (!event_loop_p)
{
add_show_from_set
(add_set_cmd ("prompt", class_support, var_string,
/* The set editing command is different depending whether or not the
async version is run. NOTE: this difference is going to disappear
as we make the event loop be the default engine of gdb. */
- if (!async_p)
+ if (!event_loop_p)
{
add_show_from_set
(add_set_cmd ("editing", class_support, var_boolean, (char *) &command_editing_p,
using remote targets.", &setlist),
&showlist);
+ c = add_set_cmd("remotedebug", no_class, var_zinteger, (char *) &remote_debug, "Set debugging of remote protocol.\n\
+When enabled, each packet sent or received with the remote target\n\
+is displayed.",&setlist);
+ deprecate_cmd(c,"set debug remote");
+ deprecate_cmd(add_show_from_set(c,&showlist),"show debug remote");
+
add_show_from_set (
- add_set_cmd ("remotedebug", no_class, var_zinteger, (char *) &remote_debug,
+ add_set_cmd ("remote", no_class, var_zinteger, (char *) &remote_debug,
"Set debugging of remote protocol.\n\
When enabled, each packet sent or received with the remote target\n\
-is displayed.", &setlist),
- &showlist);
+is displayed.", &setdebuglist),
+ &showdebuglist);
add_show_from_set (
add_set_cmd ("remotetimeout", no_class, var_integer, (char *) &remote_timeout,
the async version is run. NOTE: this difference is going to
disappear as we make the event loop be the default engine of
gdb. */
- if (!async_p)
+ if (!event_loop_p)
{
c = add_set_cmd ("annotate", class_obscure, var_zinteger,
(char *) &annotation_level, "Set annotation_level.\n\
add_show_from_set (c, &showlist);
c->function.sfunc = set_async_annotation_level;
}
- if (async_p)
+ if (event_loop_p)
{
add_show_from_set
(add_set_cmd ("exec-done-display", class_support, var_boolean, (char *) &exec_done_display_p,
Use \"on\" to enable the notification, and \"off\" to disable it.", &setlist),
&showlist);
}
+ add_prefix_cmd("debug",no_class,set_debug, "Generic command for setting gdb debugging flags", &setdebuglist, "set debug ", 0, &setlist);
+
+ add_prefix_cmd("debug",no_class,show_debug,"Generic command for showing gdb debugging flags", &showdebuglist, "show debug ", 0, &showlist);
}