summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Prus <vladimir@codesourcery.com>2007-04-08 15:20:07 +0000
committerVladimir Prus <vladimir@codesourcery.com>2007-04-08 15:20:07 +0000
commit2f3f3b34c5e70ea4b0cbea2e6703cfc5542e730b (patch)
treeb53223b419839c69163c9d8a6f8533377d8775c9
parente2787b9f05b2a5d81ddf9449ff214e0ab12c49bc (diff)
downloadgdb-2f3f3b34c5e70ea4b0cbea2e6703cfc5542e730b.tar.gz
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.
-rw-r--r--gdb/ChangeLog17
-rw-r--r--gdb/ser-base.c42
-rw-r--r--gdb/ser-mingw.c23
-rw-r--r--gdb/ser-pipe.c20
-rw-r--r--gdb/serial.c1
-rw-r--r--gdb/serial.h10
6 files changed, 111 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 270d2f0dae7..3c449a954e9 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2007-04-08 Vladimir Prus <vladimir@codesourcery.com>
+
+ 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 <pedro_alves@portugalmail.pt>
* dbxread.c (read_ofile_symtab): Move current_objfile
diff --git a/gdb/ser-base.c b/gdb/ser-base.c
index a051157b316..fe5a83394db 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 fcbef3ab2ba..074687df618 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 6b1cb52aca7..f4b11b939bf 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 de1f891edd4..2025527920e 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 1f0accd4a7c..49ad4d11ad0 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