Fix for PR gdb/209, PR gdb/156:
authorTom Tromey <tromey@redhat.com>
Thu, 22 Nov 2001 00:23:13 +0000 (00:23 +0000)
committerTom Tromey <tromey@redhat.com>
Thu, 22 Nov 2001 00:23:13 +0000 (00:23 +0000)
* 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
gdb/cli/cli-decode.h
gdb/cli/cli-setshow.c
gdb/command.h
gdb/fork-child.c
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/infcmd.c
gdb/inferior.h
gdb/main.c

index bc8d70e..2b0a1c2 100644 (file)
@@ -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
index d35685c..e9e354e 100644 (file)
@@ -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;
 
index bd3dd1a..3489fc0 100644 (file)
@@ -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);
 
index 20ebef2..ffbabba 100644 (file)
@@ -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;
 
index 21e5089..24cd00a 100644 (file)
@@ -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;
+}
index 1a86887..85ebde7 100644 (file)
@@ -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. */
index c639476..52fb9d7 100644 (file)
@@ -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);
 
 
index ad013cc..b77dacb 100755 (executable)
@@ -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
 }
 
index 67c57d0..b0d74ee 100644 (file)
@@ -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 ();
+}
+
+\f
+
 /* 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);
 }
index 502d3ef..93c8d9b 100644 (file)
@@ -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;
index 2e69d80..0dbe83b 100644 (file)
@@ -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 ("\