summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog25
-rw-r--r--gdb/cli/cli-decode.h6
-rw-r--r--gdb/cli/cli-setshow.c4
-rw-r--r--gdb/command.h6
-rw-r--r--gdb/fork-child.c71
-rw-r--r--gdb/gdbarch.c26
-rw-r--r--gdb/gdbarch.h13
-rwxr-xr-xgdb/gdbarch.sh9
-rw-r--r--gdb/infcmd.c63
-rw-r--r--gdb/inferior.h4
-rw-r--r--gdb/main.c69
11 files changed, 268 insertions, 28 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index bc8d70e29a7..2b0a1c29991 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,28 @@
+2001-11-21 Tom Tromey <tromey@redhat.com>
+
+ Fix for PR gdb/209, PR gdb/156:
+ * gdbarch.c, gdbarch.h: Rebuilt.
+ * gdbarch.sh: Added `construct_inferior_arguments'.
+ * cli/cli-decode.h (cmd_list_element): Added pre_show_hook.
+ Typo fix.
+ * cli/cli-setshow.c (do_setshow_command): Call the pre_show_hook.
+ * infcmd.c (_initialize_infcmd): Set sfunc on `set args' command.
+ (inferior_argc, inferior_argv): New globals.
+ (notice_args_set): New function.
+ (set_inferior_args): Clear inferior_argc and inferior_argv.
+ (set_inferior_args_vector): New function.
+ (get_inferior_args): Handle inferior argument vector.
+ (run_command): Use get_inferior_args().
+ (notice_args_read): New function.
+ (_initialize_infcmd): Don't call set_inferior_args.
+ * command.h: Typo fix.
+ (cmd_list_element): Added pre_show_hook.
+ * main.c (captured_main): Added --args option.
+ (print_gdb_help): Document --args.
+ * inferior.h (construct_inferior_arguments): Declare.
+ (set_inferior_args_vector): Likewise.
+ * fork-child.c (construct_inferior_arguments): New function.
+
2001-11-21 Kevin Buettner <kevinb@redhat.com>
* lin-lwp.c (lin_lwp_attach_lwp): Make sure SIGCHLD is in set of
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index d35685c4f92..e9e354eec0f 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -128,7 +128,7 @@ struct cmd_list_element
/* If type is not_set_cmd, call it like this: */
void (*cfunc) (char *args, int from_tty);
- /* If type is cmd_set or show_cmd, first set the variables, and
+ /* If type is set_cmd or show_cmd, first set the variables, and
then call this. */
void (*sfunc) (char *args, int from_tty, struct cmd_list_element * c);
}
@@ -166,6 +166,10 @@ struct cmd_list_element
/* if this command is deprecated, this is the replacement name */
char *replacement;
+ /* If this command represents a show command, then this function
+ is called before the variable's value is examined. */
+ void (*pre_show_hook) (struct cmd_list_element *c);
+
/* Hook for another command to be executed before this command. */
struct cmd_list_element *hook_pre;
diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index bd3dd1a8c7b..3489fc059de 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -267,6 +267,10 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
old_chain = make_cleanup_ui_out_stream_delete (stb);
#endif /* UI_OUT */
+ /* Possibly call the pre hook. */
+ if (c->pre_show_hook)
+ (c->pre_show_hook) (c);
+
/* Print doc minus "show" at start. */
print_doc_line (gdb_stdout, c->doc + 5);
diff --git a/gdb/command.h b/gdb/command.h
index 20ebef2b46f..ffbabba061e 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -134,7 +134,7 @@ struct cmd_list_element
/* If type is not_set_cmd, call it like this: */
void (*cfunc) (char *args, int from_tty);
- /* If type is cmd_set or show_cmd, first set the variables, and
+ /* If type is set_cmd or show_cmd, first set the variables, and
then call this. */
void (*sfunc) (char *args, int from_tty, struct cmd_list_element * c);
}
@@ -172,6 +172,10 @@ struct cmd_list_element
/* if this command is deprecated, this is the replacement name */
char *replacement;
+ /* If this command represents a show command, then this function
+ is called before the variable's value is examined. */
+ void (*pre_show_hook) (struct cmd_list_element *c);
+
/* Hook for another command to be executed before this command. */
struct cmd_list_element *hook_pre;
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 21e508939b6..24cd00a5b1d 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -568,3 +568,74 @@ startup_inferior (int ntraps)
#endif /* STARTUP_INFERIOR */
stop_soon_quietly = 0;
}
+
+/* Compute command-line string given argument vector. This does the
+ same shell processing as fork_inferior. */
+/* ARGSUSED */
+char *
+construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv)
+{
+ char *result;
+
+ if (STARTUP_WITH_SHELL)
+ {
+ /* This holds all the characters considered special to the
+ typical Unix shells. We include `^' because the SunOS
+ /bin/sh treats it as a synonym for `|'. */
+ char *special = "\"!#$&*()\\|[]{}<>?'\"`~^; \t\n";
+ int i;
+ int length = 0;
+ char *out, *cp;
+
+ /* We over-compute the size. It shouldn't matter. */
+ for (i = 0; i < argc; ++i)
+ length += 2 * strlen (argv[i]) + 1;
+
+ result = (char *) xmalloc (length);
+ out = result;
+
+ for (i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ *out++ = ' ';
+
+ for (cp = argv[i]; *cp; ++cp)
+ {
+ if (strchr (special, *cp) != NULL)
+ *out++ = '\\';
+ *out++ = *cp;
+ }
+ }
+ *out = '\0';
+ }
+ else
+ {
+ /* In this case we can't handle arguments that contain spaces,
+ tabs, or newlines -- see breakup_args(). */
+ int i;
+ int length = 0;
+
+ for (i = 0; i < argc; ++i)
+ {
+ char *cp = strchr (argv[i], ' ');
+ if (cp == NULL)
+ cp = strchr (argv[i], '\t');
+ if (cp == NULL)
+ cp = strchr (argv[i], '\n');
+ if (cp != NULL)
+ error ("can't handle command-line argument containing whitespace");
+ length += strlen (argv[i]) + 1;
+ }
+
+ result = (char *) xmalloc (length);
+ result[0] = '\0';
+ for (i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ strcat (result, " ");
+ strcat (result, argv[i]);
+ }
+ }
+
+ return result;
+}
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 1a86887c528..85ebde7dc1b 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -255,6 +255,7 @@ struct gdbarch
gdbarch_skip_trampoline_code_ftype *skip_trampoline_code;
gdbarch_in_solib_call_trampoline_ftype *in_solib_call_trampoline;
gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p;
+ gdbarch_construct_inferior_arguments_ftype *construct_inferior_arguments;
};
@@ -394,6 +395,7 @@ struct gdbarch startup_gdbarch =
0,
0,
generic_in_function_epilogue_p,
+ construct_inferior_arguments,
/* startup_gdbarch() */
};
@@ -504,6 +506,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
current_gdbarch->skip_trampoline_code = generic_skip_trampoline_code;
current_gdbarch->in_solib_call_trampoline = generic_in_solib_call_trampoline;
current_gdbarch->in_function_epilogue_p = generic_in_function_epilogue_p;
+ current_gdbarch->construct_inferior_arguments = construct_inferior_arguments;
/* gdbarch_alloc() */
return current_gdbarch;
@@ -755,6 +758,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of skip_trampoline_code, invalid_p == 0 */
/* Skip verify of in_solib_call_trampoline, invalid_p == 0 */
/* Skip verify of in_function_epilogue_p, invalid_p == 0 */
+ /* Skip verify of construct_inferior_arguments, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
if (strlen (buf) > 0)
@@ -962,6 +966,10 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
(long) current_gdbarch->coerce_float_to_double
/*COERCE_FLOAT_TO_DOUBLE ()*/);
#endif
+ if (GDB_MULTI_ARCH)
+ fprintf_unfiltered (file,
+ "gdbarch_dump: construct_inferior_arguments = 0x%08lx\n",
+ (long) current_gdbarch->construct_inferior_arguments);
#ifdef CONVERT_FROM_FUNC_PTR_ADDR
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
@@ -4270,6 +4278,24 @@ set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch,
gdbarch->in_function_epilogue_p = in_function_epilogue_p;
}
+char *
+gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv)
+{
+ if (gdbarch->construct_inferior_arguments == 0)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: gdbarch_construct_inferior_arguments invalid");
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_construct_inferior_arguments called\n");
+ return gdbarch->construct_inferior_arguments (gdbarch, argc, argv);
+}
+
+void
+set_gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch,
+ gdbarch_construct_inferior_arguments_ftype construct_inferior_arguments)
+{
+ gdbarch->construct_inferior_arguments = construct_inferior_arguments;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index c639476aa76..52fb9d719d5 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -2113,6 +2113,19 @@ typedef int (gdbarch_in_function_epilogue_p_ftype) (struct gdbarch *gdbarch, COR
extern int gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr);
extern void set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p);
+/* Given a vector of command-line arguments, return a newly allocated
+ string which, when passed to the create_inferior function, will be
+ parsed (on Unix systems, by the shell) to yield the same vector.
+ This function should call error() if the argument vector is not
+ representable for this target or if this target does not support
+ command-line arguments.
+ ARGC is the number of elements in the vector.
+ ARGV is an array of strings, one per argument. */
+
+typedef char * (gdbarch_construct_inferior_arguments_ftype) (struct gdbarch *gdbarch, int argc, char **argv);
+extern char * gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv);
+extern void set_gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, gdbarch_construct_inferior_arguments_ftype *construct_inferior_arguments);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index ad013cc367b..b77dacb0d12 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -560,6 +560,15 @@ f:2:IN_SOLIB_CALL_TRAMPOLINE:int:in_solib_call_trampoline:CORE_ADDR pc, char *na
# which don't suffer from that problem could just let this functionality
# untouched.
m:::int:in_function_epilogue_p:CORE_ADDR addr:addr::0:generic_in_function_epilogue_p::0
+# Given a vector of command-line arguments, return a newly allocated
+# string which, when passed to the create_inferior function, will be
+# parsed (on Unix systems, by the shell) to yield the same vector.
+# This function should call error() if the argument vector is not
+# representable for this target or if this target does not support
+# command-line arguments.
+# ARGC is the number of elements in the vector.
+# ARGV is an array of strings, one per argument.
+m::CONSTRUCT_INFERIOR_ARGUMENTS:char *:construct_inferior_arguments:int argc, char **argv:argc, argv:::construct_inferior_arguments::0
EOF
}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 67c57d0373b..b0d74eede2f 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -123,6 +123,12 @@ static void breakpoint_auto_delete_contents (PTR);
static char *inferior_args;
+/* The inferior arguments as a vector. If INFERIOR_ARGC is nonzero,
+ then we must compute INFERIOR_ARGS from this (via the target). */
+
+static int inferior_argc;
+static char **inferior_argv;
+
/* File name for default use for standard in/out in the inferior. */
char *inferior_io_terminal;
@@ -199,6 +205,19 @@ struct environ *inferior_environ;
char *
get_inferior_args (void)
{
+ if (inferior_argc != 0)
+ {
+ char *n, *old;
+
+ n = gdbarch_construct_inferior_arguments (current_gdbarch,
+ inferior_argc, inferior_argv);
+ old = set_inferior_args (n);
+ xfree (old);
+ }
+
+ if (inferior_args == NULL)
+ inferior_args = xstrdup ("");
+
return inferior_args;
}
@@ -208,10 +227,37 @@ set_inferior_args (char *newargs)
char *saved_args = inferior_args;
inferior_args = newargs;
+ inferior_argc = 0;
+ inferior_argv = 0;
return saved_args;
}
+void
+set_inferior_args_vector (int argc, char **argv)
+{
+ inferior_argc = argc;
+ inferior_argv = argv;
+}
+
+/* Notice when `set args' is run. */
+static void
+notice_args_set (char *args, int from_tty, struct cmd_list_element *c)
+{
+ inferior_argc = 0;
+ inferior_argv = 0;
+}
+
+/* Notice when `show args' is run. */
+static void
+notice_args_read (struct cmd_list_element *c)
+{
+ /* Might compute the value. */
+ get_inferior_args ();
+}
+
+
+
/* This function detects whether or not a '&' character (indicating
background execution) has been added as *the last* of the arguments ARGS
of a command. If it has, it removes it and returns 1. Otherwise it
@@ -331,7 +377,9 @@ Start it from the beginning? "))
if (exec_file)
ui_out_field_string (uiout, "execfile", exec_file);
ui_out_spaces (uiout, 1);
- ui_out_field_string (uiout, "infargs", inferior_args);
+ /* We call get_inferior_args() because we might need to compute
+ the value now. */
+ ui_out_field_string (uiout, "infargs", get_inferior_args ());
ui_out_text (uiout, "\n");
ui_out_flush (uiout);
#else
@@ -339,13 +387,17 @@ Start it from the beginning? "))
if (exec_file)
puts_filtered (exec_file);
puts_filtered (" ");
- puts_filtered (inferior_args);
+ /* We call get_inferior_args() because we might need to compute
+ the value now. */
+ puts_filtered (get_inferior_args ());
puts_filtered ("\n");
gdb_flush (gdb_stdout);
#endif
}
- target_create_inferior (exec_file, inferior_args,
+ /* We call get_inferior_args() because we might need to compute
+ the value now. */
+ target_create_inferior (exec_file, get_inferior_args (),
environ_vector (inferior_environ));
}
@@ -1785,8 +1837,10 @@ _initialize_infcmd (void)
"Set argument list to give program being debugged when it is started.\n\
Follow this command with any number of args, to be passed to the program.",
&setlist);
- add_show_from_set (c, &showlist);
c->completer = filename_completer;
+ c->function.sfunc = notice_args_set;
+ c = add_show_from_set (c, &showlist);
+ c->pre_show_hook = notice_args_read;
c = add_cmd
("environment", no_class, environment_info,
@@ -1952,7 +2006,6 @@ Register name as argument means describe only that register.");
add_info ("float", float_info,
"Print the status of the floating point unit\n");
- set_inferior_args (xstrdup ("")); /* Initially no args */
inferior_environ = make_environ ();
init_environ (inferior_environ);
}
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 502d3efbcc9..93c8d9b3b95 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -270,6 +270,8 @@ extern void clone_and_follow_inferior (int, int *);
extern void startup_inferior (int);
+extern char *construct_inferior_arguments (struct gdbarch *, int, char **);
+
/* From inflow.c */
extern void new_tty_prefork (char *);
@@ -307,6 +309,8 @@ extern char *get_inferior_args (void);
extern char *set_inferior_args (char *);
+extern void set_inferior_args_vector (int, char **);
+
/* Last signal that the inferior received (why it stopped). */
extern enum target_signal stop_signal;
diff --git a/gdb/main.c b/gdb/main.c
index 2e69d800a2c..0dbe83bccde 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -124,6 +124,7 @@ captured_main (void *data)
int count;
static int quiet = 0;
static int batch = 0;
+ static int set_args = 0;
/* Pointers to various arguments from command line. */
char *symarg = NULL;
@@ -263,6 +264,7 @@ captured_main (void *data)
{"windows", no_argument, &use_windows, 1},
{"statistics", no_argument, 0, 13},
{"write", no_argument, &write_files, 1},
+ {"args", no_argument, &set_args, 1},
/* Allow machine descriptions to add more options... */
#ifdef ADDITIONAL_OPTIONS
ADDITIONAL_OPTIONS
@@ -276,7 +278,7 @@ captured_main (void *data)
c = getopt_long_only (argc, argv, "",
long_options, &option_index);
- if (c == EOF)
+ if (c == EOF || set_args)
break;
/* Long option that takes an argument. */
@@ -432,25 +434,46 @@ extern int gdbtk_test (char *);
use_windows = 0;
#endif
- /* OK, that's all the options. The other arguments are filenames. */
- count = 0;
- for (; optind < argc; optind++)
- switch (++count)
- {
- case 1:
- symarg = argv[optind];
- execarg = argv[optind];
- break;
- case 2:
- /* FIXME: The documentation says this can be a "ProcID". as well. */
- corearg = argv[optind];
- break;
- case 3:
- fprintf_unfiltered (gdb_stderr,
- "Excess command line arguments ignored. (%s%s)\n",
- argv[optind], (optind == argc - 1) ? "" : " ...");
- break;
- }
+ if (set_args)
+ {
+ /* The remaining options are the command-line options for the
+ inferior. The first one is the sym/exec file, and the rest
+ are arguments. */
+ if (optind >= argc)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "%s: `--args' specified but no program specified\n",
+ argv[0]);
+ exit (1);
+ }
+ symarg = argv[optind];
+ execarg = argv[optind];
+ ++optind;
+ set_inferior_args_vector (argc - optind, &argv[optind]);
+ }
+ else
+ {
+ /* OK, that's all the options. The other arguments are filenames. */
+ count = 0;
+ for (; optind < argc; optind++)
+ switch (++count)
+ {
+ case 1:
+ symarg = argv[optind];
+ execarg = argv[optind];
+ break;
+ case 2:
+ /* FIXME: The documentation says this can be a
+ "ProcID". as well. */
+ corearg = argv[optind];
+ break;
+ case 3:
+ fprintf_unfiltered (gdb_stderr,
+ "Excess command line arguments ignored. (%s%s)\n",
+ argv[optind], (optind == argc - 1) ? "" : " ...");
+ break;
+ }
+ }
if (batch)
quiet = 1;
}
@@ -713,10 +736,14 @@ print_gdb_help (struct ui_file *stream)
{
fputs_unfiltered ("\
This is the GNU debugger. Usage:\n\n\
- gdb [options] [executable-file [core-file or process-id]]\n\n\
+ gdb [options] [executable-file [core-file or process-id]]\n\
+ gdb [options] --args executable-file [inferior-arguments ...]\n\n\
Options:\n\n\
", stream);
fputs_unfiltered ("\
+ --args Arguments after executable-file are passed to inferior\n\
+", stream);
+ fputs_unfiltered ("\
--[no]async Enable (disable) asynchronous version of CLI\n\
", stream);
fputs_unfiltered ("\