On 10/05/2015 12:46 PM, Cleber Rosa wrote:
> +/* Helper function that attempts to open a file and if successful
> + redirects another file descriptor to the one just opened. If
> + file_name is not given, this returns -1 as a simple way to flag
> + a skip (user has not asked for a redirection). Seems OK since
> + this is a helper function. */
> +
> +static int
> +set_std_io_helper (const char *file_name, int std_io_fd, int flags, mode_t mode)
> +{
> + int fd;
> +
> + if (file_name == NULL)
> + return -1;
> +
> + fd = open (file_name, flags, mode);
> + if (fd < 0)
> + return 0;
> +
> + if (dup2 (fd, std_io_fd) == -1) {
{ goes on the next line, and the reindent block.
> + close (fd);
> + return 0;
> + }
> +
> + close (fd);
> + return 1;
> +}
> +
> +/* Attempts to redirect stdin, stdout and stderr. If redirection was
Double-space after period.
> + not requested by the user, it will be skipped in the helper function.
> + In case of errors, each requested and failed redirection error will
> + be passed on for individual error reporting (no details such as
> + errno/perror though). */
> +
> +#define SET_STDIO_ERROR_STDIN 0x01
> +#define SET_STDIO_ERROR_STDOUT 0x02
> +#define SET_STDIO_ERROR_STDERR 0x04
> +
> +static int
> +set_std_io (void)
> +{
> + int result = 0;
> + char *file_name = NULL;
> +
> + if (set_std_io_helper (get_inferior_io_stdin(), 0,
> + O_RDONLY, S_IRUSR | S_IWUSR) == 0)
> + result |= SET_STDIO_ERROR_STDIN;
> +
> + if (set_std_io_helper (get_inferior_io_stdout(), 1,
> + O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR) == 0)
> + result |= SET_STDIO_ERROR_STDOUT;
> +
> + if (set_std_io_helper (get_inferior_io_stderr(), 2,
> + O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR) == 0)
> + result |= SET_STDIO_ERROR_STDERR;
Shouldn't we specify O_APPEND? I'm thinking of the case of starting
multiple inferiors simultaneously under gdb. Not one after the other,
but really in parallel. E.g., run&; add-inferior ...; inferior 2; run&; etc.
> +
> + return result;
> +}
> +
> /* Start an inferior Unix child process and sets inferior_ptid to its
> pid. EXEC_FILE is the file to run. ALLARGS is a string containing
> the arguments to the program. ENV is the environment vector to
> @@ -141,6 +199,7 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
> struct inferior *inf;
> int i;
> int save_errno;
> + int io_redir_errors = 0;
>
> /* If no exec file handed to us, get it from the exec-file command
> -- with a good, common error message if none is specified. */
> @@ -358,6 +417,28 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
> path to find $SHELL. Rich Pixley says so, and I agree. */
> environ = env;
>
> + /* Sets the inferior process standard I/O (input, output, error)
> + redirection if set with the "set inferior std{in,out,err}"
> + commands. */
> + gdb_flush (gdb_stdout);
> + gdb_flush (gdb_stderr);
> + io_redir_errors = set_std_io();
Space before parens. More instances below.
> + if (io_redir_errors & SET_STDIO_ERROR_STDIN)
> + fprintf_unfiltered (gdb_stderr,
> + "Could not set %s as stdin for %s\n",
Wrap user-visible strings in _() for i18n. More instances below.
> + get_inferior_io_stdin(),
> + exec_file);
> + if (io_redir_errors & SET_STDIO_ERROR_STDOUT)
> + fprintf_unfiltered (gdb_stderr,
> + "Could not set %s as stdout for %s\n",
> + get_inferior_io_stdout(),
> + exec_file);
> + if (io_redir_errors & SET_STDIO_ERROR_STDERR)
> + fprintf_unfiltered (gdb_stderr,
> + "Could not set %s as stderr for %s\n",
> + get_inferior_io_stderr(),
> + exec_file);
> +
> if (exec_fun != NULL)
> (*exec_fun) (argv[0], argv, env);
> else
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 4713490..9941a98 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -115,6 +115,11 @@ static char *inferior_args_scratch;
>
> static char *inferior_io_terminal_scratch;
>
> +/* Scratch area where 'set inferior-{stdin,stdout,stderr}' will store
> + user provided value. */
> +
> +static char *inferior_io_std_scratch[3] = { NULL, NULL, NULL };
> +
> /* Pid of our debugged inferior, or 0 if no inferior now.
> Since various parts of infrun.c test this to see whether there is a program
> being debugged it should be nonzero (currently 3 is used) for remote
> @@ -182,6 +187,117 @@ show_inferior_tty_command (struct ui_file *file, int from_tty,
> "is \"%s\".\n"), inferior_io_terminal);
> }
>
New functions below need intro comments. For extern functions,
use "/* See whatever.h. */".
> +static void
> +set_inferior_io_helper (const char *file_name, int stdfd)
> +{
> + gdb_assert (0 <= stdfd && stdfd <= 2);
> + xfree (current_inferior ()->standard_io[stdfd]);
> + current_inferior ()->standard_io[stdfd] =
> + file_name != NULL ? xstrdup (file_name) : NULL;
> +}
> +
> +void
> +set_inferior_io_stdin (const char *file_name)
> +{
> + set_inferior_io_helper(file_name, 0);
Space before parens.
> diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
> index 4395c98..2ae4f90 100644
> --- a/gdb/testsuite/gdb.base/default.exp
> +++ b/gdb/testsuite/gdb.base/default.exp
> @@ -798,6 +798,12 @@ gdb_test "thread find" "Command requires an argument." "thread find"
> gdb_test "thread name" "No thread selected" "thread name"
> #test tty
> gdb_test "tty" "Argument required .filename to set it to\..*" "tty"
> +#test stdin
> +gdb_test "stdin" "Argument required .filename to set it to\..*" "stdin"
> +#test stdout
> +gdb_test "stdout" "Argument required .filename to set it to\..*" "stdout"
> +#test stderr
> +gdb_test "stderr" "Argument required .filename to set it to\..*" "stderr"
> #test until "u" abbreviation
> gdb_test "u" "The program is not being run." "until \"u\" abbreviation"
> #test until
>
It'd be great if we also tested that it actually works.
Thanks,
Pedro Alves
@@ -42,6 +42,21 @@ set remote multiprocess-extensions-packet
show remote multiprocess-extensions-packet
Set/show the use of the remote protocol multiprocess extensions.
+set inferior-stdin
+stdin
+show inferior-stdin
+ Set/show the standard input for the program being debugged.
+
+set inferior-stdout
+stdout
+show inferior-stdout
+ Set/show the standard output for the program being debugged.
+
+set inferior-stderr
+stderr
+show inferior-stderr
+ Set/show the standard error for the program being debugged.
+
* The "disassemble" command accepts a new modifier: /s.
It prints mixed source+disassembly like /m with two differences:
- disassembled instructions are now printed in program order, and
@@ -2443,6 +2443,12 @@ current working directory of the debuggee.
@cindex redirection
@cindex i/o
@cindex terminal
+@value{GDBN} supports different ways of redirecting your program's
+input and output, including setting a specific terminal (a
+@code{tty}), individually setting standard input, output and error
+(@code{stdin}, @code{stdout} and @code{stderr}) or using shell based
+redirection (@code{run > output}).
+
By default, the program you run under @value{GDBN} does input and output to
the same terminal that @value{GDBN} uses. @value{GDBN} switches the terminal
to its own terminal modes to interact with you, but it records the terminal
@@ -2456,19 +2462,9 @@ Displays information recorded by @value{GDBN} about the terminal modes your
program is using.
@end table
-You can redirect your program's input and/or output using shell
-redirection with the @code{run} command. For example,
-
-@smallexample
-run > outfile
-@end smallexample
-
-@noindent
-starts your program, diverting its output to the file @file{outfile}.
-
@kindex tty
@cindex controlling terminal
-Another way to specify where your program should do input and output is
+One way to specify where your program should do input and output is
with the @code{tty} command. This command accepts a file name as
argument, and causes this file to be the default for future @code{run}
commands. It also resets the controlling terminal for the child
@@ -2483,14 +2479,17 @@ directs that processes started with subsequent @code{run} commands
default to do input and output on the terminal @file{/dev/ttyb} and have
that as their controlling terminal.
-An explicit redirection in @code{run} overrides the @code{tty} command's
-effect on the input/output device, but not its effect on the controlling
-terminal.
+An explicit redirection using either
+@code{stdin}/@code{stdout}/@code{stderr} or @code{run} overrides the
+@code{tty} command's effect on the input/output device, but not its
+effect on the controlling terminal.
-When you use the @code{tty} command or redirect input in the @code{run}
-command, only the input @emph{for your program} is affected. The input
-for @value{GDBN} still comes from your terminal. @code{tty} is an alias
-for @code{set inferior-tty}.
+When you use the @code{tty} command or redirect input using either
+@code{stdin}/@code{stdout}/@code{stderr} or the @code{run} command,
+only the input @emph{for your program} is affected. The input for
+@value{GDBN} still comes from your terminal and from the original
+standard I/O channels. @code{tty} is an alias for @code{set
+inferior-tty}.
@cindex inferior tty
@cindex set inferior controlling terminal
@@ -2508,6 +2507,68 @@ Set the tty for the program being debugged to /dev/ttyb.
Show the current tty for the program being debugged.
@end table
+@cindex inferior standard i/o
+@cindex set inferior standard i/o
+As mentioned before, you can also redirect your program's standard
+input, output and error individually with the @code{stdin},
+@code{stdout} and @code{stderr} commands. For example,
+
+@smallexample
+stdin /tmp/answers
+stdout /tmp/output
+stderr /dev/null
+@end smallexample
+
+@noindent
+will set your program's standard input (file descriptor number 0) to
+the @file{/tmp/answers}, the standard output (file description number
+1) to the @file{/tmp/output} and will silence the standard error (file
+descriptor number 2) by redirecting it to @file{/dev/null}.
+
+The @code{stdin}, @code{stdout} and @code{stderr} are actually aliases
+to the commands @code{set inferior-stdin}, @code{set inferior-stdout}
+and @code{set inferior-stderr}.
+
+@table @code
+@item set inferior-stdin /tmp/answers
+@kindex set inferior-stdin
+@kindex stdin
+Set the standard input for the program being debugged to /tmp/answers.
+
+@item show inferior-stdin
+@kindex show inferior-stdin
+Show the current standard input redirection for the program being debugged.
+
+@item set inferior-stdout /tmp/output
+@kindex set inferior-stdout
+@kindex stdout
+Set the standard output for the program being debugged to /tmp/output.
+
+@item show inferior-stdout
+@kindex show inferior-stdout
+Show the current standard output redirection for the program being debugged.
+
+@item set inferior-stderr /dev/null
+@kindex set inferior-stderr
+@kindex stderr
+Set the standard error for the program being debugged to /dev/null
+
+@item show inferior-error
+@kindex show inferior-error
+Show the current standard error redirection for the program being debugged.
+@end table
+
+@cindex inferior i/o shell based redirection
+Yet another way of doing redirection is by using the shell
+capabilities with the @code{run} command. For example,
+
+@smallexample
+run > outfile
+@end smallexample
+
+@noindent
+starts your program, diverting its output to the file @file{outfile}.
+
@node Attach
@section Debugging an Already-running Process
@kindex attach
@@ -108,6 +108,64 @@ escape_bang_in_quoted_argument (const char *shell_file)
return 0;
}
+/* Helper function that attempts to open a file and if successful
+ redirects another file descriptor to the one just opened. If
+ file_name is not given, this returns -1 as a simple way to flag
+ a skip (user has not asked for a redirection). Seems OK since
+ this is a helper function. */
+
+static int
+set_std_io_helper (const char *file_name, int std_io_fd, int flags, mode_t mode)
+{
+ int fd;
+
+ if (file_name == NULL)
+ return -1;
+
+ fd = open (file_name, flags, mode);
+ if (fd < 0)
+ return 0;
+
+ if (dup2 (fd, std_io_fd) == -1) {
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+ return 1;
+}
+
+/* Attempts to redirect stdin, stdout and stderr. If redirection was
+ not requested by the user, it will be skipped in the helper function.
+ In case of errors, each requested and failed redirection error will
+ be passed on for individual error reporting (no details such as
+ errno/perror though). */
+
+#define SET_STDIO_ERROR_STDIN 0x01
+#define SET_STDIO_ERROR_STDOUT 0x02
+#define SET_STDIO_ERROR_STDERR 0x04
+
+static int
+set_std_io (void)
+{
+ int result = 0;
+ char *file_name = NULL;
+
+ if (set_std_io_helper (get_inferior_io_stdin(), 0,
+ O_RDONLY, S_IRUSR | S_IWUSR) == 0)
+ result |= SET_STDIO_ERROR_STDIN;
+
+ if (set_std_io_helper (get_inferior_io_stdout(), 1,
+ O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR) == 0)
+ result |= SET_STDIO_ERROR_STDOUT;
+
+ if (set_std_io_helper (get_inferior_io_stderr(), 2,
+ O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR) == 0)
+ result |= SET_STDIO_ERROR_STDERR;
+
+ return result;
+}
+
/* Start an inferior Unix child process and sets inferior_ptid to its
pid. EXEC_FILE is the file to run. ALLARGS is a string containing
the arguments to the program. ENV is the environment vector to
@@ -141,6 +199,7 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
struct inferior *inf;
int i;
int save_errno;
+ int io_redir_errors = 0;
/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
@@ -358,6 +417,28 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
path to find $SHELL. Rich Pixley says so, and I agree. */
environ = env;
+ /* Sets the inferior process standard I/O (input, output, error)
+ redirection if set with the "set inferior std{in,out,err}"
+ commands. */
+ gdb_flush (gdb_stdout);
+ gdb_flush (gdb_stderr);
+ io_redir_errors = set_std_io();
+ if (io_redir_errors & SET_STDIO_ERROR_STDIN)
+ fprintf_unfiltered (gdb_stderr,
+ "Could not set %s as stdin for %s\n",
+ get_inferior_io_stdin(),
+ exec_file);
+ if (io_redir_errors & SET_STDIO_ERROR_STDOUT)
+ fprintf_unfiltered (gdb_stderr,
+ "Could not set %s as stdout for %s\n",
+ get_inferior_io_stdout(),
+ exec_file);
+ if (io_redir_errors & SET_STDIO_ERROR_STDERR)
+ fprintf_unfiltered (gdb_stderr,
+ "Could not set %s as stderr for %s\n",
+ get_inferior_io_stderr(),
+ exec_file);
+
if (exec_fun != NULL)
(*exec_fun) (argv[0], argv, env);
else
@@ -115,6 +115,11 @@ static char *inferior_args_scratch;
static char *inferior_io_terminal_scratch;
+/* Scratch area where 'set inferior-{stdin,stdout,stderr}' will store
+ user provided value. */
+
+static char *inferior_io_std_scratch[3] = { NULL, NULL, NULL };
+
/* Pid of our debugged inferior, or 0 if no inferior now.
Since various parts of infrun.c test this to see whether there is a program
being debugged it should be nonzero (currently 3 is used) for remote
@@ -182,6 +187,117 @@ show_inferior_tty_command (struct ui_file *file, int from_tty,
"is \"%s\".\n"), inferior_io_terminal);
}
+static void
+set_inferior_io_helper (const char *file_name, int stdfd)
+{
+ gdb_assert (0 <= stdfd && stdfd <= 2);
+ xfree (current_inferior ()->standard_io[stdfd]);
+ current_inferior ()->standard_io[stdfd] =
+ file_name != NULL ? xstrdup (file_name) : NULL;
+}
+
+void
+set_inferior_io_stdin (const char *file_name)
+{
+ set_inferior_io_helper(file_name, 0);
+}
+
+const char *
+get_inferior_io_stdin (void)
+{
+ return current_inferior ()->standard_io[0];
+}
+
+static void
+set_inferior_stdin_command (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_inferior_io_stdin (inferior_io_std_scratch[0]);
+}
+
+static void
+show_inferior_stdin_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ /* Note that we ignore the passed-in value in favor of computing it
+ directly. */
+ const char *inferior_io_stdin = get_inferior_io_stdin ();
+
+ if (inferior_io_stdin == NULL)
+ inferior_io_stdin = "";
+ fprintf_filtered (gdb_stdout,
+ _("Standard input for future runs of program being "
+ "debugged is \"%s\".\n"), inferior_io_stdin);
+}
+
+void
+set_inferior_io_stdout (const char *file_name)
+{
+ set_inferior_io_helper(file_name, 1);
+}
+
+const char *
+get_inferior_io_stdout (void)
+{
+ return current_inferior ()->standard_io[1];
+}
+
+static void
+set_inferior_stdout_command (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_inferior_io_stdout (inferior_io_std_scratch[1]);
+}
+
+static void
+show_inferior_stdout_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ /* Note that we ignore the passed-in value in favor of computing it
+ directly. */
+ const char *inferior_io_stdout = get_inferior_io_stdout ();
+
+ if (inferior_io_stdout == NULL)
+ inferior_io_stdout = "";
+ fprintf_filtered (gdb_stdout,
+ _("Standard output for future runs of program being "
+ "debugged is \"%s\".\n"), inferior_io_stdout);
+}
+
+void
+set_inferior_io_stderr (const char *file_name)
+{
+ set_inferior_io_helper(file_name, 2);
+}
+
+const char *
+get_inferior_io_stderr (void)
+{
+ return current_inferior ()->standard_io[2];
+}
+
+static void
+set_inferior_stderr_command (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_inferior_io_stderr (inferior_io_std_scratch[2]);
+}
+
+static void
+show_inferior_stderr_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ /* Note that we ignore the passed-in value in favor of computing it
+ directly. */
+ const char *inferior_io_stderr = get_inferior_io_stderr ();
+
+ if (inferior_io_stderr == NULL)
+ inferior_io_stderr = "";
+ fprintf_filtered (gdb_stderr,
+ _("Standard error for future runs of program being "
+ "debugged is \"%s\".\n"), inferior_io_stderr);
+}
+
char *
get_inferior_args (void)
{
@@ -3132,6 +3248,36 @@ Usage: set inferior-tty /dev/pts/1"),
&setlist, &showlist);
add_com_alias ("tty", "set inferior-tty", class_alias, 0);
+ add_setshow_filename_cmd ("inferior-stdin", class_run,
+ &inferior_io_std_scratch[0], _("\
+Set standard input for future runs of program being debugged."), _("\
+Show standard input for future runs of program being debugged."), _("\
+Usage: set inferior-input /tmp/redirected.stdin"),
+ set_inferior_stdin_command,
+ show_inferior_stdin_command,
+ &setlist, &showlist);
+ add_com_alias ("stdin", "set inferior-stdin", class_alias, 0);
+
+ add_setshow_filename_cmd ("inferior-stdout", class_run,
+ &inferior_io_std_scratch[1], _("\
+Set standard output for future runs of program being debugged."), _("\
+Show standard output for future runs of program being debugged."), _("\
+Usage: set inferior-stdout /tmp/redirected.stdout"),
+ set_inferior_stdout_command,
+ show_inferior_stdout_command,
+ &setlist, &showlist);
+ add_com_alias ("stdout", "set inferior-stdout", class_alias, 0);
+
+ add_setshow_filename_cmd ("inferior-stderr", class_run,
+ &inferior_io_std_scratch[2], _("\
+Set standard error for future runs of program being debugged."), _("\
+Show standard error for future runs of program being debugged."), _("\
+Usage: set inferior-stderr /tmp/redirected.stderr"),
+ set_inferior_stderr_command,
+ show_inferior_stderr_command,
+ &setlist, &showlist);
+ add_com_alias ("stderr", "set inferior-stderr", class_alias, 0);
+
cmd_name = "args";
add_setshow_string_noescape_cmd (cmd_name, class_run,
&inferior_args_scratch, _("\
@@ -99,6 +99,9 @@ free_inferior (struct inferior *inf)
inferior_free_data (inf);
xfree (inf->args);
xfree (inf->terminal);
+ xfree (inf->standard_io[0]);
+ xfree (inf->standard_io[1]);
+ xfree (inf->standard_io[2]);
free_environ (inf->environment);
target_desc_info_free (inf->tdesc_info);
xfree (inf->priv);
@@ -77,6 +77,14 @@ extern void clear_sigint_trap (void);
extern void set_inferior_io_terminal (const char *terminal_name);
extern const char *get_inferior_io_terminal (void);
+/* Set/get file name for standard input/output/error. */
+extern void set_inferior_io_stdin (const char *file_name);
+extern const char *get_inferior_io_stdin (void);
+extern void set_inferior_io_stdout (const char *file_name);
+extern const char *get_inferior_io_stdout (void);
+extern void set_inferior_io_stderr (const char *file_name);
+extern const char *get_inferior_io_stderr (void);
+
/* Collected pid, tid, etc. of the debugged inferior. When there's
no inferior, ptid_get_pid (inferior_ptid) will be 0. */
@@ -329,6 +337,9 @@ struct inferior
/* The name of terminal device to use for I/O. */
char *terminal;
+ /* The names of files to use as standard input/output/error */
+ char *standard_io[3];
+
/* Environment to use for running inferior,
in format described in environ.h. */
struct gdb_environ *environment;
@@ -798,6 +798,12 @@ gdb_test "thread find" "Command requires an argument." "thread find"
gdb_test "thread name" "No thread selected" "thread name"
#test tty
gdb_test "tty" "Argument required .filename to set it to\..*" "tty"
+#test stdin
+gdb_test "stdin" "Argument required .filename to set it to\..*" "stdin"
+#test stdout
+gdb_test "stdout" "Argument required .filename to set it to\..*" "stdout"
+#test stderr
+gdb_test "stderr" "Argument required .filename to set it to\..*" "stderr"
#test until "u" abbreviation
gdb_test "u" "The program is not being run." "until \"u\" abbreviation"
#test until