From 65cc4390f1aea99f342f461aa6cbd7236d09552b Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sun, 8 Apr 2007 15:20:07 +0000 Subject: Pass stderr of program run with "target remote |" via gdb_stderr. * serial.c (serial_open): Set error_fd to -1. * serial.h (struct serial): New field error_fd. (struct serial_opts): New field avail. * ser-pipe.c (pipe_open): Create another pair of sockets. Pass stderr to gdb. * ser-mingw.c (pipe_windows_open): Pass PEX_STDERR_TO_PIPE to pex_run. Initialize sd->error_fd. (pipe_avail): New. (_initialize_ser_windows): Hook pipe_avail. * ser-base.c (generic_readchar): Check if there's anything in stderr channel and route that to gdb_stderr. --- gdb/ChangeLog | 17 +++++++++++++++++ gdb/ser-base.c | 42 ++++++++++++++++++++++++++++++++++++++++++ gdb/ser-mingw.c | 23 +++++++++++++++++++++-- gdb/ser-pipe.c | 20 ++++++++++++++++++++ gdb/serial.c | 1 + gdb/serial.h | 10 ++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 270d2f0..3c449a9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +2007-04-08 Vladimir Prus + + Pass stderr of program run with "target remote |" + via gdb_stderr. + * serial.c (serial_open): Set error_fd to -1. + * serial.h (struct serial): New field error_fd. + (struct serial_opts): New field avail. + * ser-pipe.c (pipe_open): Create another pair + of sockets. Pass stderr to gdb. + * ser-mingw.c (pipe_windows_open): Pass + PEX_STDERR_TO_PIPE to pex_run. Initialize + sd->error_fd. + (pipe_avail): New. + (_initialize_ser_windows): Hook pipe_avail. + * ser-base.c (generic_readchar): Check if there's + anything in stderr channel and route that to gdb_stderr. + 2007-04-03 Pedro Alves * dbxread.c (read_ofile_symtab): Move current_objfile diff --git a/gdb/ser-base.c b/gdb/ser-base.c index a051157..fe5a833 100644 --- a/gdb/ser-base.c +++ b/gdb/ser-base.c @@ -343,6 +343,48 @@ generic_readchar (struct serial *scb, int timeout, } } } + /* Read any error output we might have. */ + if (scb->error_fd != -1) + { + ssize_t s; + char buf[81]; + + for (;;) + { + char *current; + char *newline; + int to_read = 80; + + int num_bytes = -1; + if (scb->ops->avail) + num_bytes = (scb->ops->avail)(scb, scb->error_fd); + if (num_bytes != -1) + to_read = (num_bytes < to_read) ? num_bytes : to_read; + + if (to_read == 0) + break; + + s = read (scb->error_fd, &buf, to_read); + if (s == -1) + break; + + /* In theory, embedded newlines are not a problem. + But for MI, we want each output line to have just + one newline for legibility. So output things + in newline chunks. */ + buf[s] = '\0'; + current = buf; + while ((newline = strstr (current, "\n")) != NULL) + { + *newline = '\0'; + fputs_unfiltered (current, gdb_stderr); + fputs_unfiltered ("\n", gdb_stderr); + current = newline + 1; + } + fputs_unfiltered (current, gdb_stderr); + } + } + reschedule (scb); return ch; } diff --git a/gdb/ser-mingw.c b/gdb/ser-mingw.c index fcbef3a..074687d 100644 --- a/gdb/ser-mingw.c +++ b/gdb/ser-mingw.c @@ -697,6 +697,7 @@ static int pipe_windows_open (struct serial *scb, const char *name) { struct pipe_state *ps; + FILE *pex_stderr; char **argv = buildargv (name); struct cleanup *back_to = make_cleanup_freeargv (argv); @@ -717,7 +718,8 @@ pipe_windows_open (struct serial *scb, const char *name) { int err; const char *err_msg - = pex_run (ps->pex, PEX_SEARCH | PEX_BINARY_INPUT | PEX_BINARY_OUTPUT, + = pex_run (ps->pex, PEX_SEARCH | PEX_BINARY_INPUT | PEX_BINARY_OUTPUT + | PEX_STDERR_TO_PIPE, argv[0], argv, NULL, NULL, &err); @@ -739,8 +741,13 @@ pipe_windows_open (struct serial *scb, const char *name) ps->output = pex_read_output (ps->pex, 1); if (! ps->output) goto fail; - scb->fd = fileno (ps->output); + + pex_stderr = pex_read_err (ps->pex, 1); + if (! pex_stderr) + goto fail; + scb->error_fd = fileno (pex_stderr); + scb->state = (void *) ps; discard_cleanups (back_to); @@ -865,6 +872,17 @@ pipe_done_wait_handle (struct serial *scb) WaitForSingleObject (ps->wait.have_stopped, INFINITE); } +static int +pipe_avail (struct serial *scb, int fd) +{ + HANDLE h = (HANDLE) _get_osfhandle (fd); + DWORD numBytes; + BOOL r = PeekNamedPipe (h, NULL, 0, NULL, &numBytes, NULL); + if (r == FALSE) + numBytes = 0; + return numBytes; +} + struct net_windows_state { HANDLE read_event; @@ -1164,6 +1182,7 @@ _initialize_ser_windows (void) ops->write_prim = pipe_windows_write; ops->wait_handle = pipe_wait_handle; ops->done_wait_handle = pipe_done_wait_handle; + ops->avail = pipe_avail; serial_add_interface (ops); diff --git a/gdb/ser-pipe.c b/gdb/ser-pipe.c index 6b1cb52..f4b11b9 100644 --- a/gdb/ser-pipe.c +++ b/gdb/ser-pipe.c @@ -62,9 +62,12 @@ pipe_open (struct serial *scb, const char *name) * published in UNIX Review, Vol. 6, No. 8. */ int pdes[2]; + int err_pdes[2]; int pid; if (socketpair (AF_UNIX, SOCK_STREAM, 0, pdes) < 0) return -1; + if (socketpair (AF_UNIX, SOCK_STREAM, 0, err_pdes) < 0) + return -1; /* Create the child process to run the command in. Note that the apparent call to vfork() below *might* actually be a call to @@ -77,9 +80,18 @@ pipe_open (struct serial *scb, const char *name) { close (pdes[0]); close (pdes[1]); + close (err_pdes[0]); + close (err_pdes[1]); return -1; } + if (fcntl (err_pdes[0], F_SETFL, O_NONBLOCK) == -1) + { + close (err_pdes[0]); + close (err_pdes[1]); + err_pdes[0] = err_pdes[1] = -1; + } + /* Child. */ if (pid == 0) { @@ -91,6 +103,13 @@ pipe_open (struct serial *scb, const char *name) close (pdes[1]); } dup2 (STDOUT_FILENO, STDIN_FILENO); + + if (err_pdes[0] != -1) + { + close (err_pdes[0]); + dup2 (err_pdes[1], STDERR_FILENO); + close (err_pdes[1]); + } #if 0 /* close any stray FD's - FIXME - how? */ /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams @@ -109,6 +128,7 @@ pipe_open (struct serial *scb, const char *name) state = XMALLOC (struct pipe_state); state->pid = pid; scb->fd = pdes[0]; + scb->error_fd = err_pdes[0]; scb->state = state; /* If we don't do this, GDB simply exits when the remote side dies. */ diff --git a/gdb/serial.c b/gdb/serial.c index de1f891..2025527 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -211,6 +211,7 @@ serial_open (const char *name) scb->bufcnt = 0; scb->bufp = scb->buf; + scb->error_fd = -1; if (scb->ops->open (scb, open_name)) { diff --git a/gdb/serial.h b/gdb/serial.h index 1f0accd..49ad4d1 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -191,6 +191,11 @@ extern int serial_debug_p (struct serial *scb); struct serial { int fd; /* File descriptor */ + /* File descriptor for a separate error stream that should be + immediately forwarded to gdb_stderr. This may be -1. + If != -1, this descriptor should be non-blocking or + ops->avail should be non-NULL. */ + int error_fd; struct serial_ops *ops; /* Function vector */ void *state; /* Local context info for open FD */ serial_ttystate ttystate; /* Not used (yet) */ @@ -246,6 +251,11 @@ struct serial_ops /* Perform a low-level write operation, writing (at most) COUNT bytes from BUF. */ int (*write_prim)(struct serial *scb, const void *buf, size_t count); + /* Return that number of bytes that can be read from FD + without blocking. Return value of -1 means that the + the read will not block even if less that requested bytes + are available. */ + int (*avail)(struct serial *scb, int fd); #ifdef USE_WIN32API /* Return a handle to wait on, indicating available data from SCB -- cgit v1.1