/* Top level stuff for GDB, the GNU debugger.
- Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995
Free Software Foundation, Inc.
This file is part of GDB.
#include <sys/stat.h>
#include <ctype.h>
+extern void initialize_targets PARAMS ((void));
+
+extern void initialize_utils PARAMS ((void));
+
/* Prototypes for local functions */
static char * line_completion_function PARAMS ((char *, int, char *, int));
static void if_command PARAMS ((char *, int));
-static enum command_control_type
-execute_control_command PARAMS ((struct command_line *));
-
static struct command_line *
build_command_line PARAMS ((enum command_control_type, char *));
static enum command_control_type
recurse_read_control_structure PARAMS ((struct command_line *));
+static struct cleanup * setup_user_args PARAMS ((char *));
+
+static char * locate_arg PARAMS ((char *));
+
+static char * insert_args PARAMS ((char *));
+
+static void arg_cleanup PARAMS ((void));
+
static void init_main PARAMS ((void));
static void init_cmd_lists PARAMS ((void));
#define GDBINIT_FILENAME ".gdbinit"
#endif
char gdbinit[] = GDBINIT_FILENAME;
+
int inhibit_gdbinit = 0;
-/* Disable windows if non-zero */
+/* If nonzero, and GDB has been configured to be able to use windows,
+ attempt to open them upon startup. */
-int use_windows = 0; /* Defaults to off for now */
+int use_windows = 1;
/* Version number of GDB, as a string. */
int caution = 1; /* Default is yes, sigh. */
-/*
- * Define all cmd_list_element's
- */
+/* Define all cmd_list_elements. */
/* Chain containing all defined commands. */
/* Level of control structure. */
static int control_level;
+/* Structure for arguments to user defined functions. */
+#define MAXUSERARGS 10
+struct user_args
+{
+ struct user_args *next;
+ struct
+ {
+ char *arg;
+ int len;
+ } a[MAXUSERARGS];
+ int count;
+} *user_args;
+
/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
#ifndef STOP_SIGNAL
/* Called instead of fputs for all output. */
-void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer));
+void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, FILE *stream));
/* Called from print_frame_info to list the line we stopped in. */
void (*create_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
-void (*enable_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
-void (*disable_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
+void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
/* Called during long calculations to allow GUI to repair window damage, and to
check for stop buttons, etc... */
void (*interactive_hook) PARAMS ((void));
+/* Called when the registers have changed, as a hint to a GUI
+ to minimize window update. */
+
+void (*registers_changed_hook) PARAMS ((void));
+
/* Called when going to wait for the target. Usually allows the GUI to run
while waiting for target events. */
void (*call_command_hook) PARAMS ((struct cmd_list_element *c, char *cmd,
int from_tty));
+
+/* Takes control from error (). Typically used to prevent longjmps out of the
+ middle of the GUI. Usually used in conjunction with a catch routine. */
+
+NORETURN void (*error_hook) PARAMS (());
+
\f
/* Where to go for return_to_top_level (RETURN_ERROR). */
jmp_buf error_return;
int val;
struct cleanup *saved_cleanup_chain;
char *saved_error_pre_print;
+ char *saved_quit_pre_print;
saved_cleanup_chain = save_cleanups ();
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 (jmp_buf));
+ {
+ memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf));
+ error_pre_print = errstring;
+ }
if (mask & RETURN_MASK_QUIT)
- memcpy (saved_quit, quit_return, sizeof (jmp_buf));
- error_pre_print = errstring;
+ {
+ memcpy (saved_quit, quit_return, sizeof (jmp_buf));
+ quit_pre_print = errstring;
+ }
if (setjmp (tmp_jmp) == 0)
{
restore_cleanups (saved_cleanup_chain);
- error_pre_print = saved_error_pre_print;
if (mask & RETURN_MASK_ERROR)
- memcpy (error_return, saved_error, sizeof (jmp_buf));
+ {
+ memcpy (error_return, saved_error, sizeof (jmp_buf));
+ error_pre_print = saved_error_pre_print;
+ }
if (mask & RETURN_MASK_QUIT)
- memcpy (quit_return, saved_quit, sizeof (jmp_buf));
+ {
+ memcpy (quit_return, saved_quit, sizeof (jmp_buf));
+ quit_pre_print = saved_quit_pre_print;
+ }
return val;
}
return cmd;
}
+/* Recursively print a command (including full control structures). */
+void
+print_command_line (cmd, depth)
+ struct command_line *cmd;
+ unsigned int depth;
+{
+ unsigned int i;
+
+ if (depth)
+ {
+ for (i = 0; i < depth; i++)
+ fputs_filtered (" ", gdb_stdout);
+ }
+
+ /* A simple command, print it and return. */
+ if (cmd->control_type == simple_control)
+ {
+ fputs_filtered (cmd->line, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ return;
+ }
+
+ /* loop_continue to jump to the start of a while loop, print it
+ and return. */
+ if (cmd->control_type == continue_control)
+ {
+ fputs_filtered ("loop_continue\n", gdb_stdout);
+ return;
+ }
+
+ /* loop_break to break out of a while loop, print it and return. */
+ if (cmd->control_type == break_control)
+ {
+ fputs_filtered ("loop_break\n", gdb_stdout);
+ return;
+ }
+
+ /* A while command. Recursively print its subcommands before returning. */
+ if (cmd->control_type == while_control)
+ {
+ struct command_line *list;
+ fputs_filtered ("while ", gdb_stdout);
+ fputs_filtered (cmd->line, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ list = *cmd->body_list;
+ while (list)
+ {
+ print_command_line (list, depth + 1);
+ list = list->next;
+ }
+ }
+
+ /* An if command. Recursively print both arms before returning. */
+ if (cmd->control_type == if_control)
+ {
+ fputs_filtered ("if ", gdb_stdout);
+ fputs_filtered (cmd->line, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ /* The true arm. */
+ print_command_line (cmd->body_list[0], depth + 1);
+
+ /* Show the false arm if it exists. */
+ if (cmd->body_count == 2)
+ {
+ if (depth)
+ {
+ for (i = 0; i < depth; i++)
+ fputs_filtered (" ", gdb_stdout);
+ }
+ fputs_filtered ("else\n", gdb_stdout);
+ print_command_line (cmd->body_list[1], depth + 1);
+ }
+ if (depth)
+ {
+ for (i = 0; i < depth; i++)
+ fputs_filtered (" ", gdb_stdout);
+ }
+ fputs_filtered ("end\n", gdb_stdout);
+ }
+}
+
/* Execute the command in CMD. */
-static enum command_control_type
+enum command_control_type
execute_control_command (cmd)
struct command_line *cmd;
{
struct expression *expr;
struct command_line *current;
struct cleanup *old_chain = 0;
- struct cleanup *tmp_chain;
value_ptr val;
int loop;
enum command_control_type ret;
+ char *new_line;
switch (cmd->control_type)
{
case simple_control:
/* A simple command, execute it and return. */
- execute_command (cmd->line, 0);
- return cmd->control_type;
+ new_line = insert_args (cmd->line);
+ if (!new_line)
+ return invalid_control;
+ old_chain = make_cleanup (free_current_contents, &new_line);
+ execute_command (new_line, 0);
+ ret = cmd->control_type;
+ break;
case continue_control:
case break_control:
/* Return for "continue", and "break" so we can either
continue the loop at the top, or break out. */
- return cmd->control_type;
+ ret = cmd->control_type;
+ break;
case while_control:
{
/* Parse the loop control expression for the while statement. */
- expr = parse_expression (cmd->line);
- tmp_chain = make_cleanup (free_current_contents, &expr);
- if (!old_chain)
- old_chain = tmp_chain;
-
+ new_line = insert_args (cmd->line);
+ if (!new_line)
+ return invalid_control;
+ old_chain = make_cleanup (free_current_contents, &new_line);
+ expr = parse_expression (new_line);
+ make_cleanup (free_current_contents, &expr);
+
ret = simple_control;
loop = true;
case if_control:
{
+ new_line = insert_args (cmd->line);
+ if (!new_line)
+ return invalid_control;
+ old_chain = make_cleanup (free_current_contents, &new_line);
/* Parse the conditional for the if statement. */
- expr = parse_expression (cmd->line);
- old_chain = make_cleanup (free_current_contents, &expr);
+ expr = parse_expression (new_line);
+ make_cleanup (free_current_contents, &expr);
current = NULL;
ret = simple_control;
/* Get the next statement in the body. */
current = current->next;
}
+
break;
}
free_command_lines (&command);
}
+/* Cleanup */
+static void
+arg_cleanup ()
+{
+ struct user_args *oargs = user_args;
+ if (!user_args)
+ fatal ("Internal error, arg_cleanup called with no user args.\n");
+
+ user_args = user_args->next;
+ free (oargs);
+}
+
+/* Bind the incomming arguments for a user defined command to
+ $arg0, $arg1 ... $argMAXUSERARGS. */
+
+static struct cleanup *
+setup_user_args (p)
+ char *p;
+{
+ struct user_args *args;
+ struct cleanup *old_chain;
+ unsigned int arg_count = 0;
+
+ args = (struct user_args *)xmalloc (sizeof (struct user_args));
+ memset (args, 0, sizeof (struct user_args));
+
+ args->next = user_args;
+ user_args = args;
+
+ old_chain = make_cleanup (arg_cleanup, 0);
+
+ if (p == NULL)
+ return old_chain;
+
+ while (*p)
+ {
+ char *start_arg;
+
+ if (arg_count >= MAXUSERARGS)
+ {
+ error ("user defined function may only have %d arguments.\n",
+ MAXUSERARGS);
+ return old_chain;
+ }
+
+ /* Strip whitespace. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* P now points to an argument. */
+ start_arg = p;
+ user_args->a[arg_count].arg = p;
+
+ /* Get to the end of this argument. */
+ while (*p && *p != ' ' && *p != '\t')
+ p++;
+
+ user_args->a[arg_count].len = p - start_arg;
+ arg_count++;
+ user_args->count++;
+ }
+ return old_chain;
+}
+
+/* Given character string P, return a point to the first argument ($arg),
+ or NULL if P contains no arguments. */
+
+static char *
+locate_arg (p)
+ char *p;
+{
+ while ((p = strchr (p, '$')))
+ {
+ if (strncmp (p, "$arg", 4) == 0 && isdigit (p[4]))
+ return p;
+ p++;
+ }
+ return NULL;
+}
+
+/* Insert the user defined arguments stored in user_arg into the $arg
+ arguments found in line, with the updated copy being placed into nline. */
+
+static char *
+insert_args (line)
+ char *line;
+{
+ char *p, *save_line, *new_line;
+ unsigned len, i;
+
+ /* First we need to know how much memory to allocate for the new line. */
+ save_line = line;
+ len = 0;
+ while ((p = locate_arg (line)))
+ {
+ len += p - line;
+ i = p[4] - '0';
+
+ if (i >= user_args->count)
+ {
+ error ("Missing argument %d in user function.\n", i);
+ return NULL;
+ }
+ len += user_args->a[i].len;
+ line = p + 5;
+ }
+
+ /* Don't forget the tail. */
+ len += strlen (line);
+
+ /* Allocate space for the new line and fill it in. */
+ new_line = (char *)xmalloc (len + 1);
+ if (new_line == NULL)
+ return NULL;
+
+ /* Restore pointer to beginning of old line. */
+ line = save_line;
+
+ /* Save pointer to beginning of new line. */
+ save_line = new_line;
+
+ while ((p = locate_arg (line)))
+ {
+ int i, len;
+
+ memcpy (new_line, line, p - line);
+ new_line += p - line;
+ i = p[4] - '0';
+
+ len = user_args->a[i].len;
+ if (len)
+ {
+ memcpy (new_line, user_args->a[i].arg, len);
+ new_line += len;
+ }
+ line = p + 5;
+ }
+ /* Don't forget the tail. */
+ strcpy (new_line, line);
+
+ /* Return a pointer to the beginning of the new line. */
+ return save_line;
+}
+
void
execute_user_command (c, args)
struct cmd_list_element *c;
struct cleanup *old_chain;
enum command_control_type ret;
- if (args)
- error ("User-defined commands cannot take arguments.");
+ old_chain = setup_user_args (args);
cmdlines = c->user_commands;
if (cmdlines == 0)
char *command;
int stdin_is_tty = ISATTY (stdin);
long time_at_cmd_start;
+ long space_at_cmd_start;
extern int display_time;
extern int display_space;
time_at_cmd_start = get_run_time ();
+ if (display_space)
+ {
+ extern char **environ;
+ char *lim = (char *) sbrk (0);
+
+ space_at_cmd_start = (long) (lim - (char *) &environ);
+ }
+
execute_command (command, instream == stdin);
/* Do any commands attached to breakpoint we stopped at. */
bpstat_do_actions (&stop_bpstat);
{
extern char **environ;
char *lim = (char *) sbrk (0);
+ long space_now = lim - (char *) &environ;
+ long space_diff = space_now - space_at_cmd_start;
- printf_unfiltered ("Post-command data size: %ld\n",
- (long) (lim - (char *) &environ));
+ printf_unfiltered ("Space used: %ld (%c%ld for this command)\n",
+ space_now,
+ (space_diff >= 0 ? '+' : '-'),
+ space_diff);
}
}
}
rl_completer_word_break_characters =
gdb_completer_command_word_break_characters;
}
+ else if (c->enums)
+ {
+ list = complete_on_enum (c->enums, p, word);
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
else
{
/* It is a normal command; what comes after it is
e.g. "info adsfkdj". */
list = NULL;
}
+ else if (c->enums)
+ {
+ list = complete_on_enum (c->enums, p, word);
+ }
else
{
/* It is a normal command. */
char *nline;
char got_eof = 0;
+ /* The annotation suffix must be non-NULL. */
+ if (annotation_suffix == NULL)
+ annotation_suffix = "";
+
if (annotation_level > 1 && instream == stdin)
{
local_prompt = alloca ((prrompt == NULL ? 0 : strlen (prrompt))
else
prompt_ptr = NULL;
- p = command_line_input (prompt_ptr, instream == stdin, NULL);
+ p = command_line_input (prompt_ptr, instream == stdin, "commands");
/* Not sure what to do here. */
if (p == NULL)
fprintf_filtered (stream, "), ");
wrap_here("");
- fprintf_filtered (stream, "Copyright 1994 Free Software Foundation, Inc.");
+ fprintf_filtered (stream, "Copyright 1995 Free Software Foundation, Inc.");
}
/* ARGSUSED */
Definition appears on following lines, one command per line.\n\
End with a line of just \"end\".\n\
Use the \"document\" command to give documentation for the new command.\n\
-Commands defined in this way do not take arguments.");
+Commands defined in this way may have up to ten arguments.");
#ifdef __STDC__
c = add_cmd ("source", class_support, source_command,