From 552c04a7423afb694bd4948e8896b3c4cc4be816 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 22 Nov 2001 00:23:13 +0000 Subject: [PATCH] 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. --- gdb/ChangeLog | 25 +++++++++++++++ gdb/cli/cli-decode.h | 6 +++- gdb/cli/cli-setshow.c | 4 +++ gdb/command.h | 6 +++- gdb/fork-child.c | 71 +++++++++++++++++++++++++++++++++++++++++++ gdb/gdbarch.c | 26 ++++++++++++++++ gdb/gdbarch.h | 13 ++++++++ gdb/gdbarch.sh | 9 ++++++ gdb/infcmd.c | 63 +++++++++++++++++++++++++++++++++++--- gdb/inferior.h | 4 +++ gdb/main.c | 69 ++++++++++++++++++++++++++++------------- 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 + + 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 * 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,8 +736,12 @@ 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\ -- 2.30.2