Pass stderr of program run with "target remote |"
authorVladimir Prus <vladimir@codesourcery.com>
Sun, 8 Apr 2007 15:20:07 +0000 (15:20 +0000)
committerVladimir Prus <vladimir@codesourcery.com>
Sun, 8 Apr 2007 15:20:07 +0000 (15:20 +0000)
        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
gdb/ser-base.c
gdb/ser-mingw.c
gdb/ser-pipe.c
gdb/serial.c
gdb/serial.h

index 270d2f0dae73f92f4e2b0f27d6db250c74eab69d..3c449a954e97cf2395c04d87a824ceaf96a18127 100644 (file)
@@ -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
index a051157b31650769beaf1faf2dd7c90c5b3c22bd..fe5a83394dbc21e2048be45270c3cb75774f4352 100644 (file)
@@ -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;
 }
index fcbef3ab2ba7097d8a9e0381689e1d442b07084d..074687df618c6a6187b10889aef2d42ee12bf7c0 100644 (file)
@@ -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);
 
index 6b1cb52aca78202195042619006dfa7b8b542fcc..f4b11b939bfd079b294cefc7e232da6f677fe2b2 100644 (file)
@@ -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.  */
index de1f891edd4c9d06bc7b052038ae1c072855128f..2025527920ed712c14f8c3fa2478a672e99768f1 100644 (file)
@@ -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))
     {
index 1f0accd4a7ce59fc6244538f80ffc65202eff564..49ad4d11ad0b4d72c18931acf8dc99c9864e3932 100644 (file)
@@ -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