This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: CYGWIN file input redirection


Ping!  Is this OK to push to master, please?

> Date: Sat, 15 Oct 2016 15:39:42 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> CC: samsurfer117@gmail.com
> 
> > Date: Sat, 15 Oct 2016 14:33:13 +0300
> > From: Eli Zaretskii <eliz@gnu.org>
> > CC: samsurfer117@gmail.com
> > 
> > > Date: Fri, 30 Sep 2016 12:22:13 +0300
> > > From: Eli Zaretskii <eliz@gnu.org>
> > > CC: gdb-patches@sourceware.org
> > > 
> > > > How can we fix this bug?
> > > 
> > > Someone needs to write and submit the code to (a) parse the command
> > > line, like "run < foo >> bar 2> baz" and glean the redirections from
> > > it; and (b) actually implement the redirection in the CreateProcess
> > > call.
> > 
> > Guess what? someone just did.
> > 
> > The patches below implement redirection support for native debugging
> > of MinGW programs.  (I reused some of the code I wrote years ago for
> > the DJGPP project.)
> > 
> > OK to push to master?
> 
> Sorry, forgot to attach the ChangeLog entries.  Here's the patch again
> with the logs:
> 
> 2016-10-15  Eli Zaretskii  <eliz@gnu.org>
> 
> 	Support command-line redirection for Windows native debugging
> 
> 	* windows-nat.c (redir_open, redir_set_redirection)
> 	(redirect_inferior_handles) [!__CYGWIN__]: New functions for
> 	redirecting standard handles of the inferior.
> 	(windows_create_inferior) [!__CYGWIN__]: Use them to redirect
> 	standard handles of the inferior based on redirection symbols on
> 	the command line.
> 
> --- gdb/windows-nat.c~1	2016-10-09 12:37:04.538125000 +0300
> +++ gdb/windows-nat.c	2016-10-15 14:27:51.966125000 +0300
> @@ -2054,6 +2054,166 @@ clear_win32_environment (char **env)
>  }
>  #endif
>  
> +#ifndef __CYGWIN__
> +
> +/* Support routines for redirecting standard handles of the inferior.  */
> +
> +static int
> +redir_open (const char *redir_string, HANDLE *inp, HANDLE *out, HANDLE *err)
> +{
> +  HANDLE *hdl;
> +  int mode, fd;
> +  const char *fname = redir_string + 1;;
> +
> +  switch (*redir_string)
> +    {
> +    case '<':
> +      hdl = inp;
> +      mode = O_RDONLY;
> +      break;
> +    case '1': case '2':
> +      fname++;
> +      /* FALLTHROUGH */
> +    case '>':
> +      hdl = (*redir_string == '2') ? err : out;
> +      mode = O_WRONLY | O_CREAT;
> +      if (*fname == '>')
> +	{
> +	  fname++;
> +	  mode |= O_APPEND;
> +	}
> +      else
> +	mode |= O_TRUNC;
> +      break;
> +    default:
> +      return -1;
> +    }
> +  fname++;	/* skip the separator space */
> +  fd = _open (fname, mode, _S_IREAD | _S_IWRITE);
> +  if (fd < 0)
> +    return -1;
> +  /* _open just sets a flag for O_APPEND, which won't be passed to the
> +     inferior, so we need to actually move the file pointer.  */
> +  if ((mode & O_APPEND) != 0)
> +    _lseek (fd, 0L, SEEK_END);
> +  *hdl = (HANDLE)_get_osfhandle (fd);
> +  return 0;
> +}
> +
> +static int
> +redir_set_redirection (const char *s, HANDLE *inp, HANDLE *out, HANDLE *err)
> +{
> +  char buf[__PMAX + 5];	/* extra space for redirection string */
> +  char *d = buf;
> +  const char *start = s;
> +  int quote = 0;
> +
> +  *d++ = *s++;	/* copy the 1st character, < or > or a digit */
> +  if ((*start == '>' || *start == '1' || *start == '2')
> +      && *s == '>')
> +    {
> +      *d++ = *s++;
> +      if (*s == '>' && *start != '>')
> +	*d++ = *s++;
> +    }
> +  while (isspace (*s))	/* skip whitespace before file name */
> +    s++;
> +  *d++ = ' ';		/* separate file name with a single space */
> +
> +  /* Copy the file name.  */
> +  while (*s)
> +    {
> +      /* Remove quoting characters from the file name in buf[].  */
> +      if (*s == '"')	/* could support '..' quoting here */
> +	{
> +	  if (!quote)
> +	    quote = *s++;
> +	  else if (*s == quote)
> +	    {
> +	      quote = 0;
> +	      s++;
> +	    }
> +	  else
> +	    *d++ = *s++;
> +	}
> +      else if (*s == '\\')
> +	{
> +	  if (s[1] == '"')	/* could support '..' here */
> +	    s++;
> +	  *d++ = *s++;
> +	}
> +      else if (isspace (*s) && !quote)
> +	break;
> +      else
> +	*d++ = *s++;
> +      if (d - buf >= sizeof (buf) - 1)
> +	{
> +	  errno = ENAMETOOLONG;
> +	  return 0;
> +	}
> +    }
> +  *d = '\0';
> +
> +  /* Windows doesn't allow redirection characters in file names, so we
> +     can bail out early if they use them, or if there's no target file
> +     name after the redirection symbol.  */
> +  if (d[-1] == '>' || d[-1] == '<')
> +    {
> +      errno = ENOENT;
> +      return 0;
> +    }
> +  if (redir_open (buf, inp, out, err) == 0)
> +    return s - start;
> +  return 0;
> +}
> +
> +static bool
> +redirect_inferior_handles (const char *cmd_orig, char *cmd,
> +			   HANDLE *inp, HANDLE *out, HANDLE *err)
> +{
> +  const char *s = cmd_orig;
> +  char *d = cmd;
> +  int quote = 0;
> +  bool retval = false;
> +
> +  while (isspace (*s))
> +    *d++ = *s++;
> +
> +  while (*s)
> +    {
> +      if (*s == '"')	/* could also support '..' quoting here */
> +	{
> +	  if (!quote)
> +	    quote = *s;
> +	  else if (*s == quote)
> +	    quote = 0;
> +	}
> +      else if (*s == '\\')
> +	{
> +	  if (s[1] == '"')	/* escaped quote char */
> +	    s++;
> +	}
> +      else if (!quote)
> +	{
> +	  if (*s == '<' || *s == '>'
> +	      || ((*s == '1' || *s == '2') && s[1] == '>'))
> +	    {
> +	      int skip = redir_set_redirection (s, inp, out, err);
> +
> +	      if (skip <= 0)
> +		return false;
> +	      retval = true;
> +	      s += skip;
> +	    }
> +	}
> +      if (*s)
> +	*d++ = *s++;
> +    }
> +  *d = '\0';
> +  return retval;
> +}
> +#endif	/* !__CYGWIN__ */
> +
>  /* Start an inferior windows 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.
> @@ -2076,20 +2236,24 @@ windows_create_inferior (struct target_o
>    size_t len;
>    int tty;
>    int ostdin, ostdout, ostderr;
> -#else
> +#else  /* !__CYGWIN__ */
>    char real_path[__PMAX];
>    char shell[__PMAX]; /* Path to shell */
>    char *toexec;
> -  char *args;
> -  size_t args_len;
> -  HANDLE tty;
> +  char *args, *allargs_copy;
> +  size_t args_len, allargs_len;
> +  HANDLE tty = INVALID_HANDLE_VALUE;
> +  HANDLE inf_stdin = INVALID_HANDLE_VALUE;
> +  HANDLE inf_stdout = INVALID_HANDLE_VALUE;
> +  HANDLE inf_stderr = INVALID_HANDLE_VALUE;
> +  bool redirected = false;
>    char *w32env;
>    char *temp;
>    size_t envlen;
>    int i;
>    size_t envsize;
>    char **env;
> -#endif
> +#endif	/* !__CYGWIN__ */
>    PROCESS_INFORMATION pi;
>    BOOL ret;
>    DWORD flags = 0;
> @@ -2121,7 +2285,7 @@ windows_create_inferior (struct target_o
>  	error (_("Error starting executable: %d"), errno);
>        cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
>        mbstowcs (cygallargs, allargs, len);
> -#else
> +#else  /* !__USEWIDE */
>        cygallargs = allargs;
>  #endif
>      }
> @@ -2137,12 +2301,12 @@ windows_create_inferior (struct target_o
>  	    + mbstowcs (NULL, allargs, 0) + 2;
>        cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
>        swprintf (cygallargs, len, L" -c 'exec %s %s'", exec_file, allargs);
> -#else
> +#else  /* !__USEWIDE */
>        len = (sizeof (" -c 'exec  '") + strlen (exec_file)
>  	     + strlen (allargs) + 2);
>        cygallargs = (char *) alloca (len);
>        xsnprintf (cygallargs, len, " -c 'exec %s %s'", exec_file, allargs);
> -#endif
> +#endif	/* __USEWIDE */
>        toexec = shell;
>        flags |= DEBUG_PROCESS;
>      }
> @@ -2153,12 +2317,12 @@ windows_create_inferior (struct target_o
>    wcscpy (args, toexec);
>    wcscat (args, L" ");
>    wcscat (args, cygallargs);
> -#else
> +#else  /* !__USEWIDE */
>    args = (cygwin_buf_t *) alloca (strlen (toexec) + strlen (cygallargs) + 2);
>    strcpy (args, toexec);
>    strcat (args, " ");
>    strcat (args, cygallargs);
> -#endif
> +#endif	/* !__USEWIDE */
>  
>  #ifdef CW_CVT_ENV_TO_WINENV
>    /* First try to create a direct Win32 copy of the POSIX environment. */
> @@ -2167,7 +2331,7 @@ windows_create_inferior (struct target_o
>      flags |= CREATE_UNICODE_ENVIRONMENT;
>    else
>      /* If that fails, fall back to old method tweaking GDB's environment. */
> -#endif
> +#endif	/* CW_CVT_ENV_TO_WINENV */
>      {
>        /* Reset all Win32 environment variables to avoid leftover on next run. */
>        clear_win32_environment (environ);
> @@ -2232,21 +2396,26 @@ windows_create_inferior (struct target_o
>        close (ostdout);
>        close (ostderr);
>      }
> -#else
> -  toexec = exec_file;
> -  /* Build the command line, a space-separated list of tokens where
> -     the first token is the name of the module to be executed.
> -     To avoid ambiguities introduced by spaces in the module name,
> -     we quote it.  */
> -  args_len = strlen (toexec) + 2 /* quotes */ + strlen (allargs) + 2;
> -  args = (char *) alloca (args_len);
> -  xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs);
> -
> -  flags |= DEBUG_ONLY_THIS_PROCESS;
> -
> -  if (!inferior_io_terminal)
> -    tty = INVALID_HANDLE_VALUE;
> -  else
> +#else  /* !__CYGWIN__ */
> +  allargs_len = strlen (allargs);
> +  allargs_copy = strcpy ((char *)alloca (allargs_len + 1), allargs);
> +  if (strpbrk (allargs_copy, "<>"))
> +    {
> +      int e = errno;
> +      errno = 0;
> +      redirected =
> +	redirect_inferior_handles (allargs, allargs_copy,
> +				   &inf_stdin, &inf_stdout, &inf_stderr);
> +      if (errno)
> +	warning (_("Error in redirection: %s."), strerror (errno));
> +      else
> +	errno = e;
> +      allargs_len = strlen (allargs_copy);
> +    }
> +  if (inferior_io_terminal
> +      && !(inf_stdin != INVALID_HANDLE_VALUE
> +	   && inf_stdout != INVALID_HANDLE_VALUE
> +	   && inf_stderr != INVALID_HANDLE_VALUE))
>      {
>        SECURITY_ATTRIBUTES sa;
>        sa.nLength = sizeof(sa);
> @@ -2257,15 +2426,32 @@ windows_create_inferior (struct target_o
>        if (tty == INVALID_HANDLE_VALUE)
>  	warning (_("Warning: Failed to open TTY %s, error %#x."),
>  		 inferior_io_terminal, (unsigned) GetLastError ());
> -      else
> -	{
> -	  si.hStdInput = tty;
> -	  si.hStdOutput = tty;
> -	  si.hStdError = tty;
> -	  si.dwFlags |= STARTF_USESTDHANDLES;
> -	}
> +    }
> +  if (redirected || tty != INVALID_HANDLE_VALUE)
> +    {
> +      si.hStdInput = inf_stdin == INVALID_HANDLE_VALUE ? tty : inf_stdin;
> +      if (si.hStdInput == INVALID_HANDLE_VALUE)
> +	si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
> +      si.hStdOutput = inf_stdout == INVALID_HANDLE_VALUE ? tty : inf_stdout;
> +      if (si.hStdOutput == INVALID_HANDLE_VALUE)
> +	si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
> +      si.hStdError = inf_stderr == INVALID_HANDLE_VALUE ? tty : inf_stderr;
> +      if (si.hStdError == INVALID_HANDLE_VALUE)
> +	si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
> +      si.dwFlags |= STARTF_USESTDHANDLES;
>      }
>  
> +  toexec = exec_file;
> +  /* Build the command line, a space-separated list of tokens where
> +     the first token is the name of the module to be executed.
> +     To avoid ambiguities introduced by spaces in the module name,
> +     we quote it.  */
> +  args_len = strlen (toexec) + 2 /* quotes */ + allargs_len + 2;
> +  args = (char *) alloca (args_len);
> +  xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs_copy);
> +
> +  flags |= DEBUG_ONLY_THIS_PROCESS;
> +
>    /* CreateProcess takes the environment list as a null terminated set of
>       strings (i.e. two nulls terminate the list).  */
>  
> @@ -2304,7 +2490,13 @@ windows_create_inferior (struct target_o
>  			&pi);
>    if (tty != INVALID_HANDLE_VALUE)
>      CloseHandle (tty);
> -#endif
> +  if (inf_stdin != INVALID_HANDLE_VALUE)
> +    CloseHandle (inf_stdin);
> +  if (inf_stdout != INVALID_HANDLE_VALUE)
> +    CloseHandle (inf_stdout);
> +  if (inf_stderr != INVALID_HANDLE_VALUE)
> +    CloseHandle (inf_stderr);
> +#endif	/* !__CYGWIN__ */
>  
>    if (!ret)
>      error (_("Error creating process %s, (error %u)."),
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]