Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFA]: File-I/O patch
@ 2002-11-21  1:03 Corinna Vinschen
  2002-11-21 11:05 ` Andrew Cagney
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Corinna Vinschen @ 2002-11-21  1:03 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 3237 bytes --]

Hi,

the following patch is the implementation of File-I/O as proposed in
http://sources.redhat.com/ml/gdb/2002-11/msg00107.html

This implementation doesn't include the changes to gdbtk which are
required to get Console I/O working in the GUI.  These will follow
at a later time.

Note that this patch requires also the patch send in the message
http://sources.redhat.com/ml/gdb-patches/2002-11/msg00351.html 

Corinna

2002-11-21  Corinna Vinschen  <vinschen@redhat.com>

        * remote.c (remote_fileio_sig_init, remote_fileio_sig_set,
        remote_fileio_sig_exit, remote_fileio_write_bytes,
        remote_fileio_to_fio_timeval, remote_fileio_func_gettimeofday,
        remote_fileio_mode_to_target, remote_fileio_ctrl_c_signal_handler,
        remote_fileio_init_fd_map, remote_fileio_resize_fd_map,
        remote_fileio_next_free_fd, remote_fileio_fd_to_targetfd,
        remote_fileio_map_fd, remote_fileio_close_target_fd,
        remote_fileio_is_stdio, remote_fileio_oflags_to_host,
        remote_fileio_mode_to_host, remote_fileio_errno_to_target,
        remote_fileio_seek_flag_to_host, remote_fileio_extract_long,
        remote_fileio_extract_int, remote_fileio_extract_ptr_w_len,
        remote_fileio_to_be, remote_fileio_to_fio_int,
        remote_fileio_to_fio_uint, remote_fileio_to_fio_mode,
        remote_fileio_to_fio_time, remote_fileio_to_fio_long,
        remote_fileio_to_fio_ulong, remote_fileio_to_fio_stat,
        remote_fileio_reply, remote_fileio_ioerror, remote_fileio_badfd,
        remote_fileio_return_errno, remote_fileio_return_success,
        remote_fileio_func_open, remote_fileio_func_close,
        remote_fileio_func_read, remote_fileio_func_write,
        remote_fileio_func_lseek, remote_fileio_func_rename,
        remote_fileio_func_unlink, remote_fileio_func_stat,
        remote_fileio_func_fstat, remote_fileio_request,
        remote_fileio_func_system, set_system_call_allowed,
        do_remote_fileio_request, show_system_call_allowed): New functions.
        (remote_wait, remote_async_wait): Call remote_fileio_request() on
        'F' packet.
        (_initialize_remote): Add "set remote system-call-allowed" and
	"show remote system-call-allowed" commands to the UI.

2002-11-21  Martin M. Hunt  <hunt@redhat.com>

        * defs.h: Declare gdb_stdin, gdb_stdtargerr and gdb_stdtargin.
        * main.c: New ui_file gdb_stdin, gdb_stdtargerr and gdb_stdtargin.
        (captured_main): Initialize new ui_files.
        * ui-file.c: Add read and fgets input functions.
        (ui_file_new): set ui_file_fputs and ui_file_read to null functions.
        (null_file_read): New function.
        (null_file_fgets): New function.
        (ui_file_read): New function.
        (ui_file_fgets): New function.
        (set_ui_file_read): New function.
        (set_ui_file_fgets): New function.
        (stdio_file_read): New function.
        (stdio_file_fgets): New function.
        * ui-file.h: New types ui_file_read_ftype and ui_file_fgets_ftype.
        (set_ui_file_read): Declare.
        (set_ui_file_fgets): Declare.
        (ui_file_read): Declare.
        (ui_file_fgets): Declare.

-- 
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
mailto:vinschen@redhat.com

[-- Attachment #2: fileio.patch --]
[-- Type: text/plain, Size: 51357 bytes --]

Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.102
diff -u -p -r1.102 defs.h
--- defs.h	15 Oct 2002 02:16:51 -0000	1.102
+++ defs.h	21 Nov 2002 08:41:49 -0000
@@ -405,6 +405,8 @@ extern void reinitialize_more_filter (vo
 
 /* Normal results */
 extern struct ui_file *gdb_stdout;
+/* Input stream */
+extern struct ui_file *gdb_stdin;
 /* Serious error notifications */
 extern struct ui_file *gdb_stderr;
 /* Log/debug/trace messages that should bypass normal stdout/stderr
@@ -417,6 +419,8 @@ extern struct ui_file *gdb_stdlog;
    very near future that restriction shall be removed - either call
    shall be unfiltered. (cagney 1999-07-02). */
 extern struct ui_file *gdb_stdtarg;
+extern struct ui_file *gdb_stdtargerr;
+extern struct ui_file *gdb_stdtargin;
 
 #if defined(TUI)
 #include "tui.h"
Index: main.c
===================================================================
RCS file: /cvs/src/src/gdb/main.c,v
retrieving revision 1.20
diff -u -p -r1.20 main.c
--- main.c	26 Sep 2002 17:46:04 -0000	1.20
+++ main.c	21 Nov 2002 08:41:49 -0000
@@ -69,6 +69,10 @@ struct ui_file *gdb_stdout;
 struct ui_file *gdb_stderr;
 struct ui_file *gdb_stdlog;
 struct ui_file *gdb_stdtarg;
+struct ui_file *gdb_stdin;
+/* target IO streams */
+struct ui_file *gdb_stdtargin;
+struct ui_file *gdb_stdtargerr;
 
 /* Used to initialize error() - defined in utils.c */
 
@@ -197,6 +201,9 @@ captured_main (void *data)
   gdb_stderr = stdio_fileopen (stderr);
   gdb_stdlog = gdb_stderr;	/* for moment */
   gdb_stdtarg = gdb_stderr;	/* for moment */
+  gdb_stdin = stdio_fileopen (stdin);
+  gdb_stdtargerr = gdb_stderr;	/* for moment */
+  gdb_stdtargin = gdb_stdin;	/* for moment */
 
   /* initialize error() */
   error_init ();
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.94
diff -u -p -r1.94 remote.c
--- remote.c	14 Nov 2002 00:25:03 -0000	1.94
+++ remote.c	21 Nov 2002 08:41:53 -0000
@@ -45,6 +45,12 @@
 #ifdef USG
 #include <sys/types.h>
 #endif
+#include <sys/stat.h>
+#include <sys/wait.h>
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif
+#include <setjmp.h>
 
 #include "event-loop.h"
 #include "event-top.h"
@@ -55,6 +61,8 @@
 
 #include "gdbcore.h" /* for exec_bfd */
 
+#include "gdb-fileio.h"
+
 /* Prototypes for local functions */
 static void cleanup_sigint_signal_handler (void *dummy);
 static void initialize_sigint_signal_handler (void);
@@ -2729,184 +2737,1481 @@ handle_remote_sigint (int sig)
   mark_async_signal_handler_wrapper (sigint_remote_token);
 }
 
-/* Signal handler for SIGINT, installed after SIGINT has already been
-   sent once.  It will take effect the second time that the user sends
-   a ^C. */
+/* Signal handler for SIGINT, installed after SIGINT has already been
+   sent once.  It will take effect the second time that the user sends
+   a ^C. */
+static void
+handle_remote_sigint_twice (int sig)
+{
+  signal (sig, handle_sigint);
+  sigint_remote_twice_token =
+    create_async_signal_handler (inferior_event_handler_wrapper, NULL);
+  mark_async_signal_handler_wrapper (sigint_remote_twice_token);
+}
+
+/* Perform the real interruption of the target execution, in response
+   to a ^C. */
+static void
+async_remote_interrupt (gdb_client_data arg)
+{
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+  target_stop ();
+}
+
+/* Perform interrupt, if the first attempt did not succeed. Just give
+   up on the target alltogether. */
+void
+async_remote_interrupt_twice (gdb_client_data arg)
+{
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "remote_interrupt_twice called\n");
+  /* Do something only if the target was not killed by the previous
+     cntl-C. */
+  if (target_executing)
+    {
+      interrupt_query ();
+      signal (SIGINT, handle_remote_sigint);
+    }
+}
+
+/* Reinstall the usual SIGINT handlers, after the target has
+   stopped. */
+static void
+cleanup_sigint_signal_handler (void *dummy)
+{
+  signal (SIGINT, handle_sigint);
+  if (sigint_remote_twice_token)
+    delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_twice_token);
+  if (sigint_remote_token)
+    delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_token);
+}
+
+/* Send ^C to target to halt it.  Target will respond, and send us a
+   packet.  */
+static void (*ofunc) (int);
+
+/* The command line interface's stop routine. This function is installed
+   as a signal handler for SIGINT. The first time a user requests a
+   stop, we call remote_stop to send a break or ^C. If there is no
+   response from the target (it didn't stop when the user requested it),
+   we ask the user if he'd like to detach from the target. */
+static void
+remote_interrupt (int signo)
+{
+  /* If this doesn't work, try more severe steps. */
+  signal (signo, remote_interrupt_twice);
+
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+  target_stop ();
+}
+
+/* The user typed ^C twice.  */
+
+static void
+remote_interrupt_twice (int signo)
+{
+  signal (signo, ofunc);
+  interrupt_query ();
+  signal (signo, remote_interrupt);
+}
+
+/* This is the generic stop called via the target vector. When a target
+   interrupt is requested, either by the command line or the GUI, we
+   will eventually end up here. */
+static void
+remote_stop (void)
+{
+  /* Send a break or a ^C, depending on user preference.  */
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "remote_stop called\n");
+
+  if (remote_break)
+    serial_send_break (remote_desc);
+  else
+    serial_write (remote_desc, "\003", 1);
+}
+
+/* Ask the user what to do when an interrupt is received.  */
+
+static void
+interrupt_query (void)
+{
+  target_terminal_ours ();
+
+  if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+    {
+      target_mourn_inferior ();
+      throw_exception (RETURN_QUIT);
+    }
+
+  target_terminal_inferior ();
+}
+
+/* Enable/disable target terminal ownership.  Most targets can use
+   terminal groups to control terminal ownership.  Remote targets are
+   different in that explicit transfer of ownership to/from GDB/target
+   is required. */
+
+static void
+remote_async_terminal_inferior (void)
+{
+  /* FIXME: cagney/1999-09-27: Shouldn't need to test for
+     sync_execution here.  This function should only be called when
+     GDB is resuming the inferior in the forground.  A background
+     resume (``run&'') should leave GDB in control of the terminal and
+     consequently should not call this code. */
+  if (!sync_execution)
+    return;
+  /* FIXME: cagney/1999-09-27: Closely related to the above.  Make
+     calls target_terminal_*() idenpotent. The event-loop GDB talking
+     to an asynchronous target with a synchronous command calls this
+     function from both event-top.c and infrun.c/infcmd.c.  Once GDB
+     stops trying to transfer the terminal to the target when it
+     shouldn't this guard can go away.  */
+  if (!remote_async_terminal_ours_p)
+    return;
+  delete_file_handler (input_fd);
+  remote_async_terminal_ours_p = 0;
+  initialize_sigint_signal_handler ();
+  /* NOTE: At this point we could also register our selves as the
+     recipient of all input.  Any characters typed could then be
+     passed on down to the target. */
+}
+
+static void
+remote_async_terminal_ours (void)
+{
+  /* See FIXME in remote_async_terminal_inferior. */
+  if (!sync_execution)
+    return;
+  /* See FIXME in remote_async_terminal_inferior. */
+  if (remote_async_terminal_ours_p)
+    return;
+  cleanup_sigint_signal_handler (NULL);
+  add_file_handler (input_fd, stdin_event_handler, 0);
+  remote_async_terminal_ours_p = 1;
+}
+
+/* If nonzero, ignore the next kill.  */
+
+int kill_kludge;
+
+void
+remote_console_output (char *msg)
+{
+  char *p;
+
+  for (p = msg; p[0] && p[1]; p += 2)
+    {
+      char tb[2];
+      char c = fromhex (p[0]) * 16 + fromhex (p[1]);
+      tb[0] = c;
+      tb[1] = 0;
+      fputs_unfiltered (tb, gdb_stdtarg);
+    }
+  gdb_flush (gdb_stdtarg);
+}
+
+static struct {
+  int *fd_map;
+  int fd_map_size;
+} remote_fio_data;
+
+#define FIO_FD_INVALID		-1
+#define FIO_FD_CONSOLE_IN	-2
+#define FIO_FD_CONSOLE_OUT	-3
+
+static int remote_fio_system_call_allowed = 0;
+
+static int
+remote_fileio_init_fd_map ()
+{
+  int i;
+
+  if (!remote_fio_data.fd_map)
+    {
+      remote_fio_data.fd_map = (int *) xmalloc (10 * sizeof (int));
+      remote_fio_data.fd_map_size = 10;
+      remote_fio_data.fd_map[0] = FIO_FD_CONSOLE_IN;
+      remote_fio_data.fd_map[1] = FIO_FD_CONSOLE_OUT;
+      remote_fio_data.fd_map[2] = FIO_FD_CONSOLE_OUT;
+      for (i = 3; i < 10; ++i)
+        remote_fio_data.fd_map[i] = FIO_FD_INVALID;
+    }
+  return 3;
+}
+
+static int
+remote_fileio_resize_fd_map ()
+{
+  if (!remote_fio_data.fd_map)
+    return remote_fileio_init_fd_map ();
+  remote_fio_data.fd_map_size += 10;
+  remote_fio_data.fd_map =
+    (int *) xrealloc (remote_fio_data.fd_map,
+		      remote_fio_data.fd_map_size * sizeof (int));
+  return remote_fio_data.fd_map_size - 10;
+}
+
+static int
+remote_fileio_next_free_fd ()
+{
+  int i;
+
+  for (i = 0; i < remote_fio_data.fd_map_size; ++i)
+    if (remote_fio_data.fd_map[i] == FIO_FD_INVALID)
+      return i;
+  return remote_fileio_resize_fd_map ();
+}
+
+static int
+remote_fileio_fd_to_targetfd (int fd)
+{
+  int target_fd = remote_fileio_next_free_fd ();
+  remote_fio_data.fd_map[target_fd] = fd;
+  return target_fd;
+}
+
+static int
+remote_fileio_map_fd (int target_fd)
+{
+  remote_fileio_init_fd_map ();
+  if (target_fd < 0 || target_fd >= remote_fio_data.fd_map_size)
+    return FIO_FD_INVALID;
+  return remote_fio_data.fd_map[target_fd];
+}
+
+static void
+remote_fileio_close_target_fd (int target_fd)
+{
+  remote_fileio_init_fd_map ();
+  if (target_fd >= 0 && target_fd < remote_fio_data.fd_map_size)
+    remote_fio_data.fd_map[target_fd] = FIO_FD_INVALID;
+}
+
+static int
+remote_fileio_oflags_to_host (long flags)
+{
+  int hflags = 0;
+
+  if (flags & FILEIO_O_CREAT)
+    hflags |= O_CREAT;
+  if (flags & FILEIO_O_EXCL)
+    hflags |= O_EXCL;
+  if (flags & FILEIO_O_TRUNC)
+    hflags |= O_TRUNC;
+  if (flags & FILEIO_O_APPEND)
+    hflags |= O_APPEND;
+  if (flags & FILEIO_O_RDONLY)
+    hflags |= O_RDONLY;
+  if (flags & FILEIO_O_WRONLY)
+    hflags |= O_WRONLY;
+  if (flags & FILEIO_O_RDWR)
+    hflags |= O_RDWR;
+/* On systems supporting binary and text mode, always open files in
+   binary mode. */
+#ifdef O_BINARY
+  hflags |= O_BINARY;
+#endif
+  return hflags;
+}
+
+static mode_t
+remote_fileio_mode_to_host (long mode, int open_call)
+{
+  mode_t hmode = 0;
+
+  if (!open_call)
+    {
+      if (mode & FILEIO_S_IFREG)
+	hmode |= S_IFREG;
+      if (mode & FILEIO_S_IFDIR)
+	hmode |= S_IFDIR;
+      if (mode & FILEIO_S_IFCHR)
+	hmode |= S_IFCHR;
+    }
+  if (mode & FILEIO_S_IRUSR)
+    hmode |= S_IRUSR;
+  if (mode & FILEIO_S_IWUSR)
+    hmode |= S_IWUSR;
+  if (mode & FILEIO_S_IXUSR)
+    hmode |= S_IXUSR;
+  if (mode & FILEIO_S_IRGRP)
+    hmode |= S_IRGRP;
+  if (mode & FILEIO_S_IWGRP)
+    hmode |= S_IWGRP;
+  if (mode & FILEIO_S_IXGRP)
+    hmode |= S_IXGRP;
+  if (mode & FILEIO_S_IROTH)
+    hmode |= S_IROTH;
+  if (mode & FILEIO_S_IWOTH)
+    hmode |= S_IWOTH;
+  if (mode & FILEIO_S_IXOTH)
+    hmode |= S_IXOTH;
+  return hmode;
+}
+
+static long long
+remote_fileio_mode_to_target (mode_t mode)
+{
+  mode_t tmode = 0;
+
+  if (mode & S_IFREG)
+    tmode |= FILEIO_S_IFREG;
+  if (mode & S_IFDIR)
+    tmode |= FILEIO_S_IFDIR;
+  if (mode & S_IFCHR)
+    tmode |= FILEIO_S_IFCHR;
+  if (mode & S_IRUSR)
+    tmode |= FILEIO_S_IRUSR;
+  if (mode & S_IWUSR)
+    tmode |= FILEIO_S_IWUSR;
+  if (mode & S_IXUSR)
+    tmode |= FILEIO_S_IXUSR;
+  if (mode & S_IRGRP)
+    tmode |= FILEIO_S_IRGRP;
+  if (mode & S_IWGRP)
+    tmode |= FILEIO_S_IWGRP;
+  if (mode & S_IXGRP)
+    tmode |= FILEIO_S_IXGRP;
+  if (mode & S_IROTH)
+    tmode |= FILEIO_S_IROTH;
+  if (mode & S_IWOTH)
+    tmode |= FILEIO_S_IWOTH;
+  if (mode & S_IXOTH)
+    tmode |= FILEIO_S_IXOTH;
+  return tmode;
+}
+
+static int
+remote_fileio_errno_to_target (int error)
+{
+  switch (error)
+    {
+      case EPERM:
+        return FILEIO_EPERM;
+      case ENOENT:
+        return FILEIO_ENOENT;
+      case EINTR:
+        return FILEIO_EINTR;
+      case EIO:
+        return FILEIO_EIO;
+      case EBADF:
+        return FILEIO_EBADF;
+      case EACCES:
+        return FILEIO_EACCES;
+      case EFAULT:
+        return FILEIO_EFAULT;
+      case EBUSY:
+        return FILEIO_EBUSY;
+      case EEXIST:
+        return FILEIO_EEXIST;
+      case ENODEV:
+        return FILEIO_ENODEV;
+      case ENOTDIR:
+        return FILEIO_ENOTDIR;
+      case EISDIR:
+        return FILEIO_EISDIR;
+      case EINVAL:
+        return FILEIO_EINVAL;
+      case ENFILE:
+        return FILEIO_ENFILE;
+      case EMFILE:
+        return FILEIO_EMFILE;
+      case EFBIG:
+        return FILEIO_EFBIG;
+      case ENOSPC:
+        return FILEIO_ENOSPC;
+      case ESPIPE:
+        return FILEIO_ESPIPE;
+      case EROFS:
+        return FILEIO_EROFS;
+      case ENOSYS:
+        return FILEIO_ENOSYS;
+      case ENAMETOOLONG:
+        return FILEIO_ENAMETOOLONG;
+    }
+  return FILEIO_EUNKNOWN;
+}
+
+static int
+remote_fileio_seek_flag_to_host (long num, int *flag)
+{
+  if (!flag)
+    return 0;
+  switch (num)
+    {
+      case FILEIO_SEEK_SET:
+        *flag = SEEK_SET;
+	break;
+      case FILEIO_SEEK_CUR:
+        *flag =  SEEK_CUR;
+	break;
+      case FILEIO_SEEK_END:
+        *flag =  SEEK_END;
+	break;
+      default:
+        return -1;
+    }
+  return 0;
+}
+
+static int
+remote_fileio_extract_long (char **buf, long long *retlong)
+{
+  char *c;
+  int sign = 1;
+
+  if (!buf || !*buf || !**buf || !retlong)
+    return -1;
+  c = strchr (*buf, ',');
+  if (c)
+    *c++ = '\0';
+  else
+    c = strchr (*buf, '\0');
+  while (strchr ("+-", **buf))
+    {
+      if (**buf == '-')
+	sign = -sign;
+      ++*buf;
+    }
+  for (*retlong = 0; **buf; ++*buf)
+    {
+      *retlong <<= 4;
+      if (**buf >= '0' && **buf <= '9')
+        *retlong += **buf - '0';
+      else if (**buf >= 'a' && **buf <= 'f')
+        *retlong += **buf - 'a' + 10;
+      else if (**buf >= 'A' && **buf <= 'F')
+        *retlong += **buf - 'A' + 10;
+      else
+        return -1;
+    }
+  *retlong *= sign;
+  *buf = c;
+  return 0;
+}
+
+static int
+remote_fileio_extract_int (char **buf, long *retint)
+{
+  int ret;
+  long long retlong;
+
+  if (!retint)
+    return -1;
+  if (!(ret = remote_fileio_extract_long (buf, &retlong)))
+    *retint = (long) retlong;
+  return ret;
+}
+
+static int
+remote_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length)
+{
+  char *c;
+  long long retlong;
+
+  if (!buf || !*buf || !**buf || !ptrval || !length)
+    return -1;
+  c = strchr (*buf, '/');
+  if (!c)
+    return -1;
+  *c++ = '\0';
+  if (remote_fileio_extract_long (buf, &retlong))
+    return -1;
+  *ptrval = (CORE_ADDR) retlong;
+  *buf = c;
+  if (remote_fileio_extract_long (buf, &retlong))
+    return -1;
+  *length = (int) retlong;
+  return 0;
+}
+
+/* Convert to big endian */
+static void
+remote_fileio_to_be (long long num, char *buf, int bytes)
+{
+  int i;
+
+  for (i = 0; i < bytes; ++i)
+    buf[i] = (num >> (8 * (bytes - i - 1))) & 0xff;
+}
+
+static void
+remote_fileio_to_fio_int (long num, fio_int_t fnum)
+{
+  remote_fileio_to_be ((long long) num, (char *) fnum, 4);
+}
+
+static void
+remote_fileio_to_fio_uint (long num, fio_uint_t fnum)
+{
+  remote_fileio_to_be ((long long) num, (char *) fnum, 4);
+}
+
+static void
+remote_fileio_to_fio_mode (mode_t num, fio_mode_t fnum)
+{
+  remote_fileio_to_be (remote_fileio_mode_to_target(num), (char *) fnum, 4);
+}
+
+static void
+remote_fileio_to_fio_time (time_t num, fio_time_t fnum)
+{
+  remote_fileio_to_be ((long long) num, (char *) fnum, 4);
+}
+
+static void
+remote_fileio_to_fio_long (long long num, fio_long_t fnum)
+{
+  remote_fileio_to_be (num, (char *) fnum, 8);
+}
+
+static void
+remote_fileio_to_fio_ulong (long long num, fio_ulong_t fnum)
+{
+  remote_fileio_to_be (num, (char *) fnum, 8);
+}
+
+static void
+remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
+{
+  /* `st_dev' is set in the calling function */
+  remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);
+  remote_fileio_to_fio_mode (st->st_mode, fst->fst_mode);
+  remote_fileio_to_fio_uint ((long) st->st_nlink, fst->fst_nlink);
+  remote_fileio_to_fio_uint ((long) st->st_uid, fst->fst_uid);
+  remote_fileio_to_fio_uint ((long) st->st_gid, fst->fst_gid);
+  remote_fileio_to_fio_uint ((long) st->st_rdev, fst->fst_rdev);
+  remote_fileio_to_fio_ulong ((long long) st->st_size, fst->fst_size);
+  remote_fileio_to_fio_ulong ((long long) st->st_blksize, fst->fst_blksize);
+  remote_fileio_to_fio_ulong ((long long) st->st_blocks, fst->fst_blocks);
+  remote_fileio_to_fio_time (st->st_atime, fst->fst_atime);
+  remote_fileio_to_fio_time (st->st_mtime, fst->fst_mtime);
+  remote_fileio_to_fio_time (st->st_ctime, fst->fst_ctime);
+}
+
+static void
+remote_fileio_to_fio_timeval (struct timeval *tv, struct fio_timeval *ftv)
+{
+  remote_fileio_to_fio_time (tv->tv_sec, ftv->ftv_sec);
+  remote_fileio_to_fio_long (tv->tv_usec, ftv->ftv_usec);
+}
+
+static int remote_fio_ctrl_c_flag = 0;
+static int remote_fio_no_longjmp = 0;
+jmp_buf remote_fio_jmp_buf;
+
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+static struct sigaction remote_fio_sa;
+static struct sigaction remote_fio_osa;
+#else
+static void (*remote_fio_ofunc)(int);
+#endif
+
+static void
+remote_fileio_sig_init ()
+{
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+  remote_fio_sa.sa_handler = SIG_IGN;
+  sigemptyset (&remote_fio_sa.sa_mask);
+  remote_fio_sa.sa_flags = 0;
+  sigaction (SIGINT, &remote_fio_sa, &remote_fio_osa);
+#else
+  remote_fio_ofunc = signal (SIGINT, SIG_IGN);
+#endif
+}
+
+static void
+remote_fileio_sig_set (void (*sigint_func)(int))
+{
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+  remote_fio_sa.sa_handler = sigint_func;
+  sigemptyset (&remote_fio_sa.sa_mask);
+  remote_fio_sa.sa_flags = 0;
+  sigaction (SIGINT, &remote_fio_sa, NULL);
+#else
+  signal (SIGINT, sigint_func);
+#endif
+}
+
+static void
+remote_fileio_sig_exit ()
+{
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+  sigaction (SIGINT, &remote_fio_osa, NULL);
+#else
+  signal (SIGINT, remote_fio_ofunc);
+#endif
+}
+
+static void
+remote_fileio_ctrl_c_signal_handler (int signo)
+{
+  remote_fileio_sig_set (SIG_IGN);
+  remote_fio_ctrl_c_flag = 1;
+  if (!remote_fio_no_longjmp)
+    throw_exception (RETURN_QUIT);
+  remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
+}
+
+static void
+remote_fileio_reply (int retcode, int error)
+{
+  char buf[32];
+
+  remote_fileio_sig_set (SIG_IGN);
+  strcpy (buf, "F");
+  if (retcode < 0)
+    {
+      strcat (buf, "-");
+      retcode = -retcode;
+    }
+  sprintf (buf + strlen (buf), "%x", retcode);
+  if (error || remote_fio_ctrl_c_flag)
+    {
+      if (error && remote_fio_ctrl_c_flag)
+        error = FILEIO_EINTR;
+      if (error < 0)
+        {
+	  strcat (buf, "-");
+	  error = -error;
+	}
+      sprintf (buf + strlen (buf), ",%x", error);
+      if (remote_fio_ctrl_c_flag)
+        strcat (buf, ",C");
+    }
+  remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
+  putpkt (buf);
+}
+
+static void
+remote_fileio_ioerror ()
+{
+  remote_fileio_reply (-1, FILEIO_EIO);
+}
+
+static void
+remote_fileio_badfd ()
+{
+  remote_fileio_reply (-1, FILEIO_EBADF);
+}
+
+static void
+remote_fileio_return_errno (int retcode)
+{
+  remote_fileio_reply (retcode,
+		       retcode < 0 ? remote_fileio_errno_to_target (errno) : 0);
+}
+
+static void
+remote_fileio_return_success (int retcode)
+{
+  remote_fileio_reply (retcode, 0);
+}
+
+/* Wrapper function for remote_write_bytes() which has the disadvantage to
+   write only one packet, regardless of the requested number of bytes to
+   transfer.  This wrapper calls remote_write_bytes() as often as needed. */
+static int
+remote_fileio_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+  int ret = 0, written;
+
+  while (len > 0 && (written = remote_write_bytes (memaddr, myaddr, len)) > 0)
+    {
+      len -= written;
+      memaddr += written;
+      myaddr += written;
+      ret += written;
+    }
+  return ret;
+}
+
+static void
+remote_fileio_func_open (char *buf)
+{
+  CORE_ADDR ptrval;
+  int length, retlength;
+  long num;
+  int flags, fd;
+  mode_t mode;
+  char *pathname;
+  struct stat st;
+
+  /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
+  if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* 2. Parameter: open flags */
+  if (remote_fileio_extract_int (&buf, &num))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  flags = remote_fileio_oflags_to_host (num);
+  /* 3. Parameter: open mode */
+  if (remote_fileio_extract_int (&buf, &num))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  mode = remote_fileio_mode_to_host (num, 1);
+
+  /* Request pathname using 'm' packet */
+  pathname = alloca (length);
+  retlength = remote_read_bytes (ptrval, pathname, length);
+  if (retlength != length)
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+
+  /* Check if pathname exists and is not a regular file or directory.  If so,
+     return an appropriate error code.  Same for trying to open directories
+     for writing. */
+  if (!stat (pathname, &st))
+    {
+      if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+	{
+	  remote_fileio_reply (-1, FILEIO_ENODEV);
+	  return;
+	}
+      if (S_ISDIR (st.st_mode)
+	  && ((flags & O_WRONLY) == O_WRONLY || (flags & O_RDWR) == O_RDWR))
+	{
+	  remote_fileio_reply (-1, FILEIO_EISDIR);
+	  return;
+	}
+    }
+
+  remote_fio_no_longjmp = 1;
+  fd = open (pathname, flags, mode);
+  if (fd < 0)
+    {
+      remote_fileio_return_errno (-1);
+      return;
+    }
+
+  fd = remote_fileio_fd_to_targetfd (fd);
+  remote_fileio_return_success (fd);
+}
+
+static void
+remote_fileio_func_close (char *buf)
+{
+  long num;
+  int fd;
+
+  /* Parameter: file descriptor */
+  if (remote_fileio_extract_int (&buf, &num))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  if ((fd = remote_fileio_map_fd ((int) num)) == FIO_FD_INVALID)
+    {
+      remote_fileio_badfd ();
+      return;
+    }
+
+  remote_fio_no_longjmp = 1;
+  if (fd != FIO_FD_CONSOLE_IN && fd != FIO_FD_CONSOLE_OUT && close (fd))
+    remote_fileio_return_errno (-1);
+  remote_fileio_close_target_fd ((int) num);
+  remote_fileio_return_success (0);
+}
+
+static void
+remote_fileio_func_read (char *buf)
+{
+  long target_fd, num;
+  long long lnum;
+  CORE_ADDR ptrval;
+  int fd, ret, retlength;
+  char *buffer;
+  size_t length;
+  off_t old_offset, new_offset;
+
+  /* 1. Parameter: file descriptor */
+  if (remote_fileio_extract_int (&buf, &target_fd))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  if ((fd = remote_fileio_map_fd ((int) target_fd)) == FIO_FD_INVALID)
+    {
+      remote_fileio_badfd ();
+      return;
+    }
+  /* 2. Parameter: buffer pointer */
+  if (remote_fileio_extract_long (&buf, &lnum))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  ptrval = (CORE_ADDR) lnum;
+  /* 3. Parameter: buffer length */
+  if (remote_fileio_extract_int (&buf, &num))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  length = (size_t) num;
+
+  switch (fd)
+    {
+      case FIO_FD_CONSOLE_OUT:
+	remote_fileio_badfd ();
+	return;
+      case FIO_FD_CONSOLE_IN:
+	{
+	  static char *remaining_buf = NULL;
+	  static int remaining_length = 0;
+
+	  buffer = (char *) xmalloc (32768);
+	  if (remaining_buf)
+	    {
+	      remote_fio_no_longjmp = 1;
+	      if (remaining_length > length)
+		{
+		  memcpy (buffer, remaining_buf, length);
+		  memmove (remaining_buf, remaining_buf + length,
+			   remaining_length - length);
+		  remaining_length -= length;
+		  ret = length;
+		}
+	      else
+		{
+		  memcpy (buffer, remaining_buf, remaining_length);
+		  xfree (remaining_buf);
+		  remaining_buf = NULL;
+		  ret = remaining_length;
+		}
+	    }
+	  else
+	    {
+	      ret = ui_file_read (gdb_stdtargin, buffer, 32767);
+	      remote_fio_no_longjmp = 1;
+	      if (ret > 0 && (size_t)ret > length)
+		{
+		  remaining_buf = (char *) xmalloc (ret - length);
+		  remaining_length = ret - length;
+		  memcpy (remaining_buf, buffer + length, remaining_length);
+		  ret = length;
+		}
+	    }
+	}
+	break;
+      default:
+	buffer = (char *) xmalloc (length);
+	/* POSIX defines EINTR behaviour of read in a weird way.  It's allowed
+	   for read() to return -1 even if "some" bytes have been read.  It
+	   has been corrected in SUSv2 but that doesn't help us much...
+	   Therefore a complete solution must check how many bytes have been
+	   read on EINTR to return a more reliable value to the target */
+	old_offset = lseek (fd, 0, SEEK_CUR);
+	remote_fio_no_longjmp = 1;
+	ret = read (fd, buffer, length);
+	if (ret < 0 && errno == EINTR)
+	  {
+	    new_offset = lseek (fd, 0, SEEK_CUR);
+	    /* If some data has been read, return the number of bytes read.
+	       The Ctrl-C flag is set in remote_fileio_reply() anyway */
+	    if (old_offset != new_offset)
+	      ret = new_offset - old_offset;
+	  }
+	break;
+    }
+
+  if (ret > 0)
+    {
+      retlength = remote_fileio_write_bytes (ptrval, buffer, ret);
+      if (retlength != ret)
+	ret = -1; /* errno has been set to EIO in remote_fileio_write_bytes() */
+    }
+
+  if (ret < 0)
+    remote_fileio_return_errno (-1);
+  else
+    remote_fileio_return_success (ret);
+
+  xfree (buffer);
+}
+
+static void
+remote_fileio_func_write (char *buf)
+{
+  long target_fd, num;
+  long long lnum;
+  CORE_ADDR ptrval;
+  int fd, ret, retlength;
+  char *buffer;
+  size_t length;
+
+  /* 1. Parameter: file descriptor */
+  if (remote_fileio_extract_int (&buf, &target_fd))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  if ((fd = remote_fileio_map_fd ((int) target_fd)) == FIO_FD_INVALID)
+    {
+      remote_fileio_badfd ();
+      return;
+    }
+  /* 2. Parameter: buffer pointer */
+  if (remote_fileio_extract_long (&buf, &lnum))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  ptrval = (CORE_ADDR) lnum;
+  /* 3. Parameter: buffer length */
+  if (remote_fileio_extract_int (&buf, &num))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  length = (size_t) num;
+    
+  buffer = (char *) xmalloc (length);
+  retlength = remote_read_bytes (ptrval, buffer, length);
+  if (retlength != length)
+    {
+      xfree (buffer);
+      remote_fileio_ioerror ();
+      return;
+    }
+
+  remote_fio_no_longjmp = 1;
+  switch (fd)
+    {
+      case FIO_FD_CONSOLE_IN:
+	remote_fileio_badfd ();
+	return;
+      case FIO_FD_CONSOLE_OUT:
+	ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr, buffer,
+		       length);
+	gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr);
+	ret = length;
+	break;
+      default:
+	ret = write (fd, buffer, length);
+	if (ret < 0 && errno == EACCES)
+	  errno = EBADF; /* Cygwin returns EACCESS when writing to a R/O file.*/
+	break;
+    }
+
+  if (ret < 0)
+    remote_fileio_return_errno (-1);
+  else
+    remote_fileio_return_success (ret);
+
+  xfree (buffer);
+}
+
+static void
+remote_fileio_func_lseek (char *buf)
+{
+  long num;
+  long long lnum;
+  int fd, flag;
+  off_t offset, ret;
+
+  /* 1. Parameter: file descriptor */
+  if (remote_fileio_extract_int (&buf, &num))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  if ((fd = remote_fileio_map_fd ((int) num)) == FIO_FD_INVALID)
+    {
+      remote_fileio_badfd ();
+      return;
+    }
+  else if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
+    {
+      remote_fileio_reply (-1, FILEIO_ESPIPE);
+      return;
+    }
+
+  /* 2. Parameter: offset */
+  if (remote_fileio_extract_long (&buf, &lnum))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  offset = (off_t) lnum;
+  /* 3. Parameter: flag */
+  if (remote_fileio_extract_int (&buf, &num))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  if (remote_fileio_seek_flag_to_host (num, &flag))
+    {
+      remote_fileio_reply (-1, FILEIO_EINVAL);
+      return;
+    }
+  
+  remote_fio_no_longjmp = 1;
+  ret = lseek (fd, offset, flag);
+
+  if (ret == (off_t) -1)
+    remote_fileio_return_errno (-1);
+  else
+    remote_fileio_return_success (ret);
+}
+
+static void
+remote_fileio_func_rename (char *buf)
+{
+  CORE_ADDR ptrval;
+  int length, retlength;
+  char *oldpath, *newpath;
+  int ret, of, nf;
+  struct stat ost, nst;
+
+  /* 1. Parameter: Ptr to oldpath / length incl. trailing zero */
+  if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* Request oldpath using 'm' packet */
+  oldpath = alloca (length);
+  retlength = remote_read_bytes (ptrval, oldpath, length);
+  if (retlength != length)
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* 2. Parameter: Ptr to newpath / length incl. trailing zero */
+  if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* Request newpath using 'm' packet */
+  newpath = alloca (length);
+  retlength = remote_read_bytes (ptrval, newpath, length);
+  if (retlength != length)
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  
+  /* Only operate on regular files and directories */
+  if ((!(of = stat (oldpath, &ost))
+       && !S_ISREG (ost.st_mode) && !S_ISDIR (ost.st_mode))
+      || (!(nf = stat (newpath, &nst))
+          && !S_ISREG (nst.st_mode) && !S_ISDIR (nst.st_mode)))
+    {
+      remote_fileio_reply (-1, FILEIO_EACCES);
+      return;
+    }
+
+  remote_fio_no_longjmp = 1;
+  ret = rename (oldpath, newpath);
+
+  if (ret == -1)
+    {
+      /* Special case: newpath is a non-empty directory.  Some systems
+         return ENOTEMPTY, some return EEXIST.  We coerce that to be
+	 always EEXIST. */
+      if (errno == ENOTEMPTY)
+        errno = EEXIST;
+#ifdef __CYGWIN__
+      /* Workaround some Cygwin problems with correct errnos. */
+      if (errno == EACCES)
+        {
+	  if (!of && !nf && S_ISDIR (nst.st_mode))
+	    {
+	      if (S_ISREG (ost.st_mode))
+		errno = EISDIR;
+	      else
+		{
+		  char oldfullpath[PATH_MAX + 1];
+		  char newfullpath[PATH_MAX + 1];
+		  int len;
+
+		  cygwin_conv_to_full_posix_path (oldpath, oldfullpath);
+		  cygwin_conv_to_full_posix_path (newpath, newfullpath);
+		  len = strlen (oldfullpath);
+		  if (newfullpath[len] == '/'
+		      && !strncmp (oldfullpath, newfullpath, len))
+		    errno = EINVAL;
+		  else
+		    errno = EEXIST;
+		}
+	    }
+	}
+#endif
+
+      remote_fileio_return_errno (-1);
+    }
+  else
+    remote_fileio_return_success (ret);
+}
+
 static void
-handle_remote_sigint_twice (int sig)
+remote_fileio_func_unlink (char *buf)
 {
-  signal (sig, handle_sigint);
-  sigint_remote_twice_token =
-    create_async_signal_handler (inferior_event_handler_wrapper, NULL);
-  mark_async_signal_handler_wrapper (sigint_remote_twice_token);
+  CORE_ADDR ptrval;
+  int length, retlength;
+  char *pathname;
+  int ret;
+  struct stat st;
+
+  /* Parameter: Ptr to pathname / length incl. trailing zero */
+  if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* Request pathname using 'm' packet */
+  pathname = alloca (length);
+  retlength = remote_read_bytes (ptrval, pathname, length);
+  if (retlength != length)
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+
+  /* Only operate on regular files (and directories, which allows to return
+     the correct return code) */
+  if (!stat (pathname, &st) && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+    {
+      remote_fileio_reply (-1, FILEIO_ENODEV);
+      return;
+    }
+
+  remote_fio_no_longjmp = 1;
+  ret = unlink (pathname);
+
+  if (ret == -1)
+    remote_fileio_return_errno (-1);
+  else
+    remote_fileio_return_success (ret);
 }
 
-/* Perform the real interruption of the target execution, in response
-   to a ^C. */
 static void
-async_remote_interrupt (gdb_client_data arg)
+remote_fileio_func_stat (char *buf)
 {
-  if (remote_debug)
-    fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+  CORE_ADDR ptrval;
+  int ret, length, retlength;
+  char *pathname;
+  long long lnum;
+  struct stat st;
+  struct fio_stat fst;
 
-  target_stop ();
-}
+  /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
+  if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* Request pathname using 'm' packet */
+  pathname = alloca (length);
+  retlength = remote_read_bytes (ptrval, pathname, length);
+  if (retlength != length)
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
 
-/* Perform interrupt, if the first attempt did not succeed. Just give
-   up on the target alltogether. */
-void
-async_remote_interrupt_twice (gdb_client_data arg)
-{
-  if (remote_debug)
-    fprintf_unfiltered (gdb_stdlog, "remote_interrupt_twice called\n");
-  /* Do something only if the target was not killed by the previous
-     cntl-C. */
-  if (target_executing)
+  /* 2. Parameter: Ptr to struct stat */
+  if (remote_fileio_extract_long (&buf, &lnum))
     {
-      interrupt_query ();
-      signal (SIGINT, handle_remote_sigint);
+      remote_fileio_ioerror ();
+      return;
+    }
+  ptrval = (CORE_ADDR) lnum;
+
+  remote_fio_no_longjmp = 1;
+  ret = stat (pathname, &st);
+
+  if (ret == -1)
+    {
+      remote_fileio_return_errno (-1);
+      return;
+    }
+  /* Only operate on regular files and directories */
+  if (!ret && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+    {
+      remote_fileio_reply (-1, FILEIO_EACCES);
+      return;
+    }
+  if (ptrval)
+    {
+      remote_fileio_to_fio_stat (&st, &fst);
+      remote_fileio_to_fio_uint (0, fst.fst_dev);
+      
+      retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst);
+      if (retlength != sizeof fst)
+	{
+	  remote_fileio_return_errno (-1);
+	  return;
+	}
     }
+  remote_fileio_return_success (ret);
 }
 
-/* Reinstall the usual SIGINT handlers, after the target has
-   stopped. */
 static void
-cleanup_sigint_signal_handler (void *dummy)
+remote_fileio_func_fstat (char *buf)
 {
-  signal (SIGINT, handle_sigint);
-  if (sigint_remote_twice_token)
-    delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_twice_token);
-  if (sigint_remote_token)
-    delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_token);
-}
+  CORE_ADDR ptrval;
+  int fd, ret, retlength;
+  long target_fd;
+  long long lnum;
+  struct stat st;
+  struct fio_stat fst;
+  struct timeval tv;
 
-/* Send ^C to target to halt it.  Target will respond, and send us a
-   packet.  */
-static void (*ofunc) (int);
+  /* 1. Parameter: file descriptor */
+  if (remote_fileio_extract_int (&buf, &target_fd))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  if ((fd = remote_fileio_map_fd ((int) target_fd)) == FIO_FD_INVALID)
+    {
+      remote_fileio_badfd ();
+      return;
+    }
+  /* 2. Parameter: Ptr to struct stat */
+  if (remote_fileio_extract_long (&buf, &lnum))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  ptrval = (CORE_ADDR) lnum;
 
-/* The command line interface's stop routine. This function is installed
-   as a signal handler for SIGINT. The first time a user requests a
-   stop, we call remote_stop to send a break or ^C. If there is no
-   response from the target (it didn't stop when the user requested it),
-   we ask the user if he'd like to detach from the target. */
-static void
-remote_interrupt (int signo)
-{
-  /* If this doesn't work, try more severe steps. */
-  signal (signo, remote_interrupt_twice);
+  remote_fio_no_longjmp = 1;
+  if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
+    {
+      remote_fileio_to_fio_uint (1, fst.fst_dev);
+      st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR);
+      st.st_nlink = 1;
+      st.st_uid = getuid ();
+      st.st_gid = getgid ();
+      st.st_rdev = 0;
+      st.st_size = 0;
+      st.st_blksize = 512;
+      st.st_blocks = 0;
+      if (!gettimeofday (&tv, NULL))
+	st.st_atime = st.st_mtime = st.st_ctime = tv.tv_sec;
+      else
+        st.st_atime = st.st_mtime = st.st_ctime = (time_t) 0;
+      ret = 0;
+    }
+  else
+    ret = fstat (fd, &st);
 
-  if (remote_debug)
-    fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+  if (ret == -1)
+    {
+      remote_fileio_return_errno (-1);
+      return;
+    }
+  if (ptrval)
+    {
+      remote_fileio_to_fio_stat (&st, &fst);
 
-  target_stop ();
+      retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst);
+      if (retlength != sizeof fst)
+	{
+	  remote_fileio_return_errno (-1);
+	  return;
+	}
+    }
+  remote_fileio_return_success (ret);
 }
 
-/* The user typed ^C twice.  */
-
 static void
-remote_interrupt_twice (int signo)
+remote_fileio_func_gettimeofday (char *buf)
 {
-  signal (signo, ofunc);
-  interrupt_query ();
-  signal (signo, remote_interrupt);
+  long long lnum;
+  CORE_ADDR ptrval;
+  int ret, retlength;
+  struct timeval tv;
+  struct fio_timeval ftv;
+
+  /* 1. Parameter: struct timeval pointer */
+  if (remote_fileio_extract_long (&buf, &lnum))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  ptrval = (CORE_ADDR) lnum;
+  /* 2. Parameter: some pointer value... */
+  if (remote_fileio_extract_long (&buf, &lnum))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* ...which has to be NULL */
+  if (lnum)
+    {
+      remote_fileio_reply (-1, FILEIO_EINVAL);
+      return;
+    }
+
+  remote_fio_no_longjmp = 1;
+  ret = gettimeofday (&tv, NULL);
+
+  if (ret == -1)
+    {
+      remote_fileio_return_errno (-1);
+      return;
+    }
+
+  if (ptrval)
+    {
+      remote_fileio_to_fio_timeval (&tv, &ftv);
+
+      retlength = remote_fileio_write_bytes (ptrval, (char *) &ftv, sizeof ftv);
+      if (retlength != sizeof ftv)
+	{
+	  remote_fileio_return_errno (-1);
+	  return;
+	}
+    }
+  remote_fileio_return_success (ret);
 }
 
-/* This is the generic stop called via the target vector. When a target
-   interrupt is requested, either by the command line or the GUI, we
-   will eventually end up here. */
 static void
-remote_stop (void)
+remote_fileio_func_isatty (char *buf)
 {
-  /* Send a break or a ^C, depending on user preference.  */
-  if (remote_debug)
-    fprintf_unfiltered (gdb_stdlog, "remote_stop called\n");
+  long target_fd;
+  int fd;
 
-  if (remote_break)
-    serial_send_break (remote_desc);
-  else
-    serial_write (remote_desc, "\003", 1);
+  /* Parameter: file descriptor */
+  if (remote_fileio_extract_int (&buf, &target_fd))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  remote_fio_no_longjmp = 1;
+  fd = remote_fileio_map_fd ((int) target_fd);
+  remote_fileio_return_success (fd == FIO_FD_CONSOLE_IN ||
+  				fd == FIO_FD_CONSOLE_OUT ? 1 : 0);
 }
 
-/* Ask the user what to do when an interrupt is received.  */
-
 static void
-interrupt_query (void)
+remote_fileio_func_system (char *buf)
 {
-  target_terminal_ours ();
+  CORE_ADDR ptrval;
+  int ret, length, retlength;
+  char *cmdline;
 
-  if (query ("Interrupted while waiting for the program.\n\
-Give up (and stop debugging it)? "))
+  /* Check if system(3) has been explicitely allowed using the
+     `set remote system-call-allowed 1' command.  If not, return
+     EPERM */
+  if (!remote_fio_system_call_allowed)
     {
-      target_mourn_inferior ();
-      throw_exception (RETURN_QUIT);
+      remote_fileio_reply (-1, FILEIO_EPERM);
+      return;
     }
 
-  target_terminal_inferior ();
+  /* Parameter: Ptr to commandline / length incl. trailing zero */
+  if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+  /* Request commandline using 'm' packet */
+  cmdline = alloca (length);
+  retlength = remote_read_bytes (ptrval, cmdline, length);
+  if (retlength != length)
+    {
+      remote_fileio_ioerror ();
+      return;
+    }
+
+  remote_fio_no_longjmp = 1;
+  ret = system (cmdline);
+
+  if (ret == -1)
+    remote_fileio_return_errno (-1);
+  else
+    remote_fileio_return_success (WEXITSTATUS (ret));
 }
 
-/* Enable/disable target terminal ownership.  Most targets can use
-   terminal groups to control terminal ownership.  Remote targets are
-   different in that explicit transfer of ownership to/from GDB/target
-   is required. */
+static struct {
+  char *name;
+  void (*func)(char *);
+} remote_fio_func_map[] = {
+  "open", remote_fileio_func_open,
+  "close", remote_fileio_func_close,
+  "read", remote_fileio_func_read,
+  "write", remote_fileio_func_write,
+  "lseek", remote_fileio_func_lseek,
+  "rename", remote_fileio_func_rename,
+  "unlink", remote_fileio_func_unlink,
+  "stat", remote_fileio_func_stat,
+  "fstat", remote_fileio_func_fstat,
+  "gettimeofday", remote_fileio_func_gettimeofday,
+  "isatty", remote_fileio_func_isatty,
+  "system", remote_fileio_func_system,
+  NULL, NULL
+};
 
-static void
-remote_async_terminal_inferior (void)
+static int
+do_remote_fileio_request (struct ui_out *uiout, void *buf_arg)
 {
-  /* FIXME: cagney/1999-09-27: Shouldn't need to test for
-     sync_execution here.  This function should only be called when
-     GDB is resuming the inferior in the forground.  A background
-     resume (``run&'') should leave GDB in control of the terminal and
-     consequently should not call this code. */
-  if (!sync_execution)
-    return;
-  /* FIXME: cagney/1999-09-27: Closely related to the above.  Make
-     calls target_terminal_*() idenpotent. The event-loop GDB talking
-     to an asynchronous target with a synchronous command calls this
-     function from both event-top.c and infrun.c/infcmd.c.  Once GDB
-     stops trying to transfer the terminal to the target when it
-     shouldn't this guard can go away.  */
-  if (!remote_async_terminal_ours_p)
-    return;
-  delete_file_handler (input_fd);
-  remote_async_terminal_ours_p = 0;
-  initialize_sigint_signal_handler ();
-  /* NOTE: At this point we could also register our selves as the
-     recipient of all input.  Any characters typed could then be
-     passed on down to the target. */
+  char *buf = buf_arg;
+  char *c;
+  int idx;
+
+  remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
+
+  c = strchr (++buf, ',');
+  if (c)
+    *c++ = '\0';
+  else
+    c = strchr (buf, '\0');
+  for (idx = 0; remote_fio_func_map[idx].name; ++idx)
+    if (!strcmp (remote_fio_func_map[idx].name, buf))
+      break;
+  if (!remote_fio_func_map[idx].name)	/* ERROR: No such function. */
+    return RETURN_ERROR;
+  remote_fio_func_map[idx].func (c);
+  return 0;
 }
 
 static void
-remote_async_terminal_ours (void)
+remote_fileio_request (char *buf)
 {
-  /* See FIXME in remote_async_terminal_inferior. */
-  if (!sync_execution)
-    return;
-  /* See FIXME in remote_async_terminal_inferior. */
-  if (remote_async_terminal_ours_p)
-    return;
-  cleanup_sigint_signal_handler (NULL);
-  add_file_handler (input_fd, stdin_event_handler, 0);
-  remote_async_terminal_ours_p = 1;
-}
-
-/* If nonzero, ignore the next kill.  */
+  int ex;
 
-int kill_kludge;
+  remote_fileio_sig_init ();
 
-void
-remote_console_output (char *msg)
-{
-  char *p;
+  remote_fio_ctrl_c_flag = 0;
+  remote_fio_no_longjmp = 0;
 
-  for (p = msg; p[0] && p[1]; p += 2)
-    {
-      char tb[2];
-      char c = fromhex (p[0]) * 16 + fromhex (p[1]);
-      tb[0] = c;
-      tb[1] = 0;
-      fputs_unfiltered (tb, gdb_stdtarg);
+  ex = catch_exceptions (uiout, do_remote_fileio_request, (void *)buf,
+			 NULL, RETURN_MASK_ALL);
+  switch (ex)
+    {
+      case RETURN_ERROR:
+	remote_fileio_reply (-1, FILEIO_ENOSYS);
+        break;
+      case RETURN_QUIT:
+        remote_fileio_reply (-1, FILEIO_EINTR);
+	break;
+      default:
+        break;
     }
-  gdb_flush (gdb_stdtarg);
+
+  remote_fileio_sig_exit ();
 }
 
 /* Wait until the remote machine stops, then return,
@@ -2945,6 +4250,9 @@ remote_wait (ptid_t ptid, struct target_
 	case 'E':		/* Error of some sort */
 	  warning ("Remote failure reply: %s", buf);
 	  continue;
+	case 'F':		/* File-I/O request */
+	  remote_fileio_request (buf);
+	  continue;
 	case 'T':		/* Status with PC, SP, FP, ... */
 	  {
 	    int i;
@@ -3196,6 +4504,9 @@ remote_async_wait (ptid_t ptid, struct t
 	case 'E':		/* Error of some sort */
 	  warning ("Remote failure reply: %s", buf);
 	  continue;
+	case 'F':		/* File-I/O request */
+	  remote_fileio_request (buf);
+	  continue;
 	case 'T':		/* Status with PC, SP, FP, ... */
 	  {
 	    int i;
@@ -4750,6 +6061,31 @@ remote_remove_breakpoint (CORE_ADDR addr
 #endif /* REMOTE_BREAKPOINT */
 }
 
+static void
+set_system_call_allowed (char *args, int from_tty)
+{
+  if (args)
+    {
+      char *arg_end;
+      int val = strtoul (args, &arg_end, 10);
+      if (*args && *arg_end == '\0')
+        {
+	  remote_fio_system_call_allowed = !!val;
+	  return;
+	}
+    }
+  error ("Illegal argument for \"set remote system-call-allowed\" command");
+}
+
+static void
+show_system_call_allowed (char *args, int from_tty)
+{
+  if (args)
+    error ("Garbage after \"show remote system-call-allowed\" command: `%s'", args);
+  printf_unfiltered ("Calling host system(3) call from target is %sallowed\n",
+		     remote_fio_system_call_allowed ? "" : "not ");
+}
+
 static int
 watchpoint_to_Z_packet (int type)
 {
@@ -6167,6 +7503,15 @@ in a memory packet.\n",
 		  "Set binary downloads.\n", &setlist),
      &showlist);
 #endif
+
+  add_cmd ("system-call-allowed", no_class,
+	   set_system_call_allowed,
+	   "Set if the host system(3) call is allowed for the target.\n",
+	   &remote_set_cmdlist);
+  add_cmd ("system-call-allowed", no_class,
+	   show_system_call_allowed,
+	   "Show if the host system(3) call is allowed for the target.\n",
+	   &remote_show_cmdlist);
 
   add_info ("remote-process", remote_info_process,
 	    "Query the remote system for process info.");
Index: ui-file.c
===================================================================
RCS file: /cvs/src/src/gdb/ui-file.c,v
retrieving revision 1.9
diff -u -p -r1.9 ui-file.c
--- ui-file.c	25 Jul 2002 03:14:28 -0000	1.9
+++ ui-file.c	21 Nov 2002 08:41:53 -0000
@@ -25,9 +25,12 @@
 #include "ui-file.h"
 #include "gdb_string.h"
 
+#include <errno.h>
+
 static ui_file_isatty_ftype null_file_isatty;
 static ui_file_write_ftype null_file_write;
 static ui_file_fputs_ftype null_file_fputs;
+static ui_file_read_ftype null_file_read;
 static ui_file_flush_ftype null_file_flush;
 static ui_file_delete_ftype null_file_delete;
 static ui_file_rewind_ftype null_file_rewind;
@@ -39,6 +42,7 @@ struct ui_file
     ui_file_flush_ftype *to_flush;
     ui_file_write_ftype *to_write;
     ui_file_fputs_ftype *to_fputs;
+    ui_file_read_ftype *to_read;
     ui_file_delete_ftype *to_delete;
     ui_file_isatty_ftype *to_isatty;
     ui_file_rewind_ftype *to_rewind;
@@ -56,6 +60,7 @@ ui_file_new (void)
   set_ui_file_flush (file, null_file_flush);
   set_ui_file_write (file, null_file_write);
   set_ui_file_fputs (file, null_file_fputs);
+  set_ui_file_read (file, null_file_read);
   set_ui_file_isatty (file, null_file_isatty);
   set_ui_file_rewind (file, null_file_rewind);
   set_ui_file_put (file, null_file_put);
@@ -123,6 +128,15 @@ null_file_write (struct ui_file *file,
     }
 }
 
+static long
+null_file_read (struct ui_file *file,
+		char *buf,
+		long sizeof_buf)
+{
+  errno = EBADF;
+  return 0;
+}
+
 static void
 null_file_fputs (const char *buf, struct ui_file *file)
 {
@@ -186,6 +200,12 @@ ui_file_write (struct ui_file *file,
   file->to_write (file, buf, length_buf);
 }
 
+long
+ui_file_read (struct ui_file *file, char *buf, long length_buf)
+{
+  return file->to_read (file, buf, length_buf); 
+}
+
 void
 fputs_unfiltered (const char *buf, struct ui_file *file)
 {
@@ -224,6 +244,12 @@ set_ui_file_write (struct ui_file *file,
 }
 
 void
+set_ui_file_read (struct ui_file *file, ui_file_read_ftype *read)
+{
+  file->to_read = read;
+}
+
+void
 set_ui_file_fputs (struct ui_file *file, ui_file_fputs_ftype *fputs)
 {
   file->to_fputs = fputs;
@@ -383,6 +409,7 @@ mem_file_write (struct ui_file *file,
 
 static ui_file_write_ftype stdio_file_write;
 static ui_file_fputs_ftype stdio_file_fputs;
+static ui_file_read_ftype stdio_file_read;
 static ui_file_isatty_ftype stdio_file_isatty;
 static ui_file_delete_ftype stdio_file_delete;
 static struct ui_file *stdio_file_new (FILE * file, int close_p);
@@ -409,6 +436,7 @@ stdio_file_new (FILE *file, int close_p)
   set_ui_file_flush (ui_file, stdio_file_flush);
   set_ui_file_write (ui_file, stdio_file_write);
   set_ui_file_fputs (ui_file, stdio_file_fputs);
+  set_ui_file_read (ui_file, stdio_file_read);
   set_ui_file_isatty (ui_file, stdio_file_isatty);
   return ui_file;
 }
@@ -435,6 +463,16 @@ stdio_file_flush (struct ui_file *file)
     internal_error (__FILE__, __LINE__,
 		    "stdio_file_flush: bad magic number");
   fflush (stdio->file);
+}
+
+static long
+stdio_file_read (struct ui_file *file, char *buf, long length_buf)
+{
+  struct stdio_file *stdio = ui_file_data (file);
+  if (stdio->magic != &stdio_file_magic)
+    internal_error (__FILE__, __LINE__,
+		    "stdio_file_read: bad magic number");
+  return read (fileno (stdio->file), buf, length_buf);
 }
 
 static void
Index: ui-file.h
===================================================================
RCS file: /cvs/src/src/gdb/ui-file.h,v
retrieving revision 1.3
diff -u -p -r1.3 ui-file.h
--- ui-file.h	25 Jul 2002 03:14:28 -0000	1.3
+++ ui-file.h	21 Nov 2002 08:41:53 -0000
@@ -41,6 +41,9 @@ extern void set_ui_file_write (struct ui
 typedef void (ui_file_fputs_ftype) (const char *, struct ui_file * stream);
 extern void set_ui_file_fputs (struct ui_file *stream, ui_file_fputs_ftype * fputs);
 
+typedef long (ui_file_read_ftype) (struct ui_file * stream, char *buf, long length_buf);
+extern void set_ui_file_read (struct ui_file *stream, ui_file_read_ftype *fread);
+
 typedef int (ui_file_isatty_ftype) (struct ui_file * stream);
 extern void set_ui_file_isatty (struct ui_file *stream, ui_file_isatty_ftype * isatty);
 
@@ -77,6 +80,8 @@ extern void ui_file_put (struct ui_file 
 extern char *ui_file_xstrdup (struct ui_file *file, long *length);
 
 
+
+extern long ui_file_read (struct ui_file *file, char *buf, long length_buf);
 
 /* Create/open a memory based file. Can be used as a scratch buffer
    for collecting output. */

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2003-06-10 15:51 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-11-21  1:03 [RFA]: File-I/O patch Corinna Vinschen
2002-11-21 11:05 ` Andrew Cagney
2002-11-21 13:04 ` Corinna Vinschen
2003-03-07 19:31 ` Andrew Cagney
2003-03-10 18:26   ` Corinna Vinschen
2003-06-03 18:31     ` Andrew Cagney
2003-06-08 18:55       ` Andrew Cagney
2003-06-10 14:44         ` Corinna Vinschen
2003-06-10 15:51           ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox