*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / remote.c
index 2d8a88b81447dbead3075fd080b7084bff58dc2c..1ea5d55d5990101bb2aaa269e0541b09956296d1 100644 (file)
@@ -1,7 +1,7 @@
 /* Remote target communications for serial-line targets in custom GDB protocol
 
    Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -58,6 +58,7 @@
 #include "gdbcore.h" /* for exec_bfd */
 
 #include "remote-fileio.h"
+#include "gdb/fileio.h"
 
 #include "memory-map.h"
 
@@ -207,6 +208,10 @@ static void show_remote_protocol_packet_cmd (struct ui_file *file,
 
 void _initialize_remote (void);
 
+/* For "remote".  */
+
+static struct cmd_list_element *remote_cmdlist;
+
 /* For "set remote" and "show remote".  */
 
 static struct cmd_list_element *remote_set_cmdlist;
@@ -901,6 +906,11 @@ enum {
   PACKET_Z2,
   PACKET_Z3,
   PACKET_Z4,
+  PACKET_vFile_open,
+  PACKET_vFile_pread,
+  PACKET_vFile_pwrite,
+  PACKET_vFile_close,
+  PACKET_vFile_unlink,
   PACKET_qXfer_auxv,
   PACKET_qXfer_features,
   PACKET_qXfer_libraries,
@@ -1343,7 +1353,7 @@ unpack_varlen_hex (char *buff,    /* packet to parse */
 static char *
 unpack_nibble (char *buf, int *val)
 {
-  ishex (*buf++, val);
+  *val = fromhex (*buf++);
   return buf;
 }
 
@@ -6276,6 +6286,631 @@ remote_read_description (struct target_ops *target)
   return NULL;
 }
 
+/* Remote file transfer support.  This is host-initiated I/O, not
+   target-initiated; for target-initiated, see remote-fileio.c.  */
+
+/* If *LEFT is at least the length of STRING, copy STRING to
+   *BUFFER, update *BUFFER to point to the new end of the buffer, and
+   decrease *LEFT.  Otherwise raise an error.  */
+
+static void
+remote_buffer_add_string (char **buffer, int *left, char *string)
+{
+  int len = strlen (string);
+
+  if (len > *left)
+    error (_("Packet too long for target."));
+
+  memcpy (*buffer, string, len);
+  *buffer += len;
+  *left -= len;
+
+  /* NUL-terminate the buffer as a convenience, if there is
+     room.  */
+  if (*left)
+    **buffer = '\0';
+}
+
+/* If *LEFT is large enough, hex encode LEN bytes from BYTES into
+   *BUFFER, update *BUFFER to point to the new end of the buffer, and
+   decrease *LEFT.  Otherwise raise an error.  */
+
+static void
+remote_buffer_add_bytes (char **buffer, int *left, const gdb_byte *bytes,
+                        int len)
+{
+  if (2 * len > *left)
+    error (_("Packet too long for target."));
+
+  bin2hex (bytes, *buffer, len);
+  *buffer += 2 * len;
+  *left -= 2 * len;
+
+  /* NUL-terminate the buffer as a convenience, if there is
+     room.  */
+  if (*left)
+    **buffer = '\0';
+}
+
+/* If *LEFT is large enough, convert VALUE to hex and add it to
+   *BUFFER, update *BUFFER to point to the new end of the buffer, and
+   decrease *LEFT.  Otherwise raise an error.  */
+
+static void
+remote_buffer_add_int (char **buffer, int *left, ULONGEST value)
+{
+  int len = hexnumlen (value);
+
+  if (len > *left)
+    error (_("Packet too long for target."));
+
+  hexnumstr (*buffer, value);
+  *buffer += len;
+  *left -= len;
+
+  /* NUL-terminate the buffer as a convenience, if there is
+     room.  */
+  if (*left)
+    **buffer = '\0';
+}
+
+/* Parse an I/O result packet from BUFFER.  Set RETCODE to the return
+   value, *REMOTE_ERRNO to the remote error number or zero if none
+   was included, and *ATTACHMENT to point to the start of the annex
+   if any.  The length of the packet isn't needed here; there may
+   be NUL bytes in BUFFER, but they will be after *ATTACHMENT.
+
+   Return 0 if the packet could be parsed, -1 if it could not.  If
+   -1 is returned, the other variables may not be initialized.  */
+
+static int
+remote_hostio_parse_result (char *buffer, int *retcode,
+                           int *remote_errno, char **attachment)
+{
+  char *p, *p2;
+
+  *remote_errno = 0;
+  *attachment = NULL;
+
+  if (buffer[0] != 'F')
+    return -1;
+
+  errno = 0;
+  *retcode = strtol (&buffer[1], &p, 16);
+  if (errno != 0 || p == &buffer[1])
+    return -1;
+
+  /* Check for ",errno".  */
+  if (*p == ',')
+    {
+      errno = 0;
+      *remote_errno = strtol (p + 1, &p2, 16);
+      if (errno != 0 || p + 1 == p2)
+       return -1;
+      p = p2;
+    }
+
+  /* Check for ";attachment".  If there is no attachment, the
+     packet should end here.  */
+  if (*p == ';')
+    {
+      *attachment = p + 1;
+      return 0;
+    }
+  else if (*p == '\0')
+    return 0;
+  else
+    return -1;
+}
+
+/* Send a prepared I/O packet to the target and read its response.
+   The prepared packet is in the global RS->BUF before this function
+   is called, and the answer is there when we return.
+
+   COMMAND_BYTES is the length of the request to send, which may include
+   binary data.  WHICH_PACKET is the packet configuration to check
+   before attempting a packet.  If an error occurs, *REMOTE_ERRNO
+   is set to the error number and -1 is returned.  Otherwise the value
+   returned by the function is returned.
+
+   ATTACHMENT and ATTACHMENT_LEN should be non-NULL if and only if an
+   attachment is expected; an error will be reported if there's a
+   mismatch.  If one is found, *ATTACHMENT will be set to point into
+   the packet buffer and *ATTACHMENT_LEN will be set to the
+   attachment's length.  */
+
+static int
+remote_hostio_send_command (int command_bytes, int which_packet,
+                           int *remote_errno, char **attachment,
+                           int *attachment_len)
+{
+  struct remote_state *rs = get_remote_state ();
+  int ret, bytes_read;
+  char *attachment_tmp;
+
+  if (remote_protocol_packets[which_packet].support == PACKET_DISABLE)
+    {
+      *remote_errno = FILEIO_ENOSYS;
+      return -1;
+    }
+
+  putpkt_binary (rs->buf, command_bytes);
+  bytes_read = getpkt_sane (&rs->buf, &rs->buf_size, 0);
+
+  /* If it timed out, something is wrong.  Don't try to parse the
+     buffer.  */
+  if (bytes_read < 0)
+    {
+      *remote_errno = FILEIO_EINVAL;
+      return -1;
+    }
+
+  switch (packet_ok (rs->buf, &remote_protocol_packets[which_packet]))
+    {
+    case PACKET_ERROR:
+      *remote_errno = FILEIO_EINVAL;
+      return -1;
+    case PACKET_UNKNOWN:
+      *remote_errno = FILEIO_ENOSYS;
+      return -1;
+    case PACKET_OK:
+      break;
+    }
+
+  if (remote_hostio_parse_result (rs->buf, &ret, remote_errno,
+                                 &attachment_tmp))
+    {
+      *remote_errno = FILEIO_EINVAL;
+      return -1;
+    }
+
+  /* Make sure we saw an attachment if and only if we expected one.  */
+  if ((attachment_tmp == NULL && attachment != NULL)
+      || (attachment_tmp != NULL && attachment == NULL))
+    {
+      *remote_errno = FILEIO_EINVAL;
+      return -1;
+    }
+
+  /* If an attachment was found, it must point into the packet buffer;
+     work out how many bytes there were.  */
+  if (attachment_tmp != NULL)
+    {
+      *attachment = attachment_tmp;
+      *attachment_len = bytes_read - (*attachment - rs->buf);
+    }
+
+  return ret;
+}
+
+/* Open FILENAME on the remote target, using FLAGS and MODE.  Return a
+   remote file descriptor, or -1 if an error occurs (and set
+   *REMOTE_ERRNO).  */
+
+static int
+remote_hostio_open (const char *filename, int flags, int mode,
+                   int *remote_errno)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *p = rs->buf;
+  int left = get_remote_packet_size () - 1;
+
+  remote_buffer_add_string (&p, &left, "vFile:open:");
+
+  remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
+                          strlen (filename));
+  remote_buffer_add_string (&p, &left, ",");
+
+  remote_buffer_add_int (&p, &left, flags);
+  remote_buffer_add_string (&p, &left, ",");
+
+  remote_buffer_add_int (&p, &left, mode);
+
+  return remote_hostio_send_command (p - rs->buf, PACKET_vFile_open,
+                                    remote_errno, NULL, NULL);
+}
+
+/* Write up to LEN bytes from WRITE_BUF to FD on the remote target.
+   Return the number of bytes written, or -1 if an error occurs (and
+   set *REMOTE_ERRNO).  */
+
+static int
+remote_hostio_pwrite (int fd, const gdb_byte *write_buf, int len,
+                     ULONGEST offset, int *remote_errno)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *p = rs->buf;
+  int left = get_remote_packet_size ();
+  int out_len;
+
+  remote_buffer_add_string (&p, &left, "vFile:pwrite:");
+
+  remote_buffer_add_int (&p, &left, fd);
+  remote_buffer_add_string (&p, &left, ",");
+
+  remote_buffer_add_int (&p, &left, offset);
+  remote_buffer_add_string (&p, &left, ",");
+
+  p += remote_escape_output (write_buf, len, p, &out_len,
+                            get_remote_packet_size () - (p - rs->buf));
+
+  return remote_hostio_send_command (p - rs->buf, PACKET_vFile_pwrite,
+                                    remote_errno, NULL, NULL);
+}
+
+/* Read up to LEN bytes FD on the remote target into READ_BUF
+   Return the number of bytes read, or -1 if an error occurs (and
+   set *REMOTE_ERRNO).  */
+
+static int
+remote_hostio_pread (int fd, gdb_byte *read_buf, int len,
+                    ULONGEST offset, int *remote_errno)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *p = rs->buf;
+  char *attachment;
+  int left = get_remote_packet_size ();
+  int ret, attachment_len;
+  int read_len;
+
+  remote_buffer_add_string (&p, &left, "vFile:pread:");
+
+  remote_buffer_add_int (&p, &left, fd);
+  remote_buffer_add_string (&p, &left, ",");
+
+  remote_buffer_add_int (&p, &left, len);
+  remote_buffer_add_string (&p, &left, ",");
+
+  remote_buffer_add_int (&p, &left, offset);
+
+  ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_pread,
+                                   remote_errno, &attachment,
+                                   &attachment_len);
+
+  if (ret < 0)
+    return ret;
+
+  read_len = remote_unescape_input (attachment, attachment_len,
+                                   read_buf, len);
+  if (read_len != ret)
+    error (_("Read returned %d, but %d bytes."), ret, (int) read_len);
+
+  return ret;
+}
+
+/* Close FD on the remote target.  Return 0, or -1 if an error occurs
+   (and set *REMOTE_ERRNO).  */
+
+static int
+remote_hostio_close (int fd, int *remote_errno)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *p = rs->buf;
+  int left = get_remote_packet_size () - 1;
+
+  remote_buffer_add_string (&p, &left, "vFile:close:");
+
+  remote_buffer_add_int (&p, &left, fd);
+
+  return remote_hostio_send_command (p - rs->buf, PACKET_vFile_close,
+                                    remote_errno, NULL, NULL);
+}
+
+/* Unlink FILENAME on the remote target.  Return 0, or -1 if an error
+   occurs (and set *REMOTE_ERRNO).  */
+
+static int
+remote_hostio_unlink (const char *filename, int *remote_errno)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *p = rs->buf;
+  int left = get_remote_packet_size () - 1;
+
+  remote_buffer_add_string (&p, &left, "vFile:unlink:");
+
+  remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
+                          strlen (filename));
+
+  return remote_hostio_send_command (p - rs->buf, PACKET_vFile_unlink,
+                                    remote_errno, NULL, NULL);
+}
+
+static int
+remote_fileio_errno_to_host (int errnum)
+{
+  switch (errnum)
+    {
+      case FILEIO_EPERM:
+        return EPERM;
+      case FILEIO_ENOENT:
+        return ENOENT;
+      case FILEIO_EINTR:
+        return EINTR;
+      case FILEIO_EIO:
+        return EIO;
+      case FILEIO_EBADF:
+        return EBADF;
+      case FILEIO_EACCES:
+        return EACCES;
+      case FILEIO_EFAULT:
+        return EFAULT;
+      case FILEIO_EBUSY:
+        return EBUSY;
+      case FILEIO_EEXIST:
+        return EEXIST;
+      case FILEIO_ENODEV:
+        return ENODEV;
+      case FILEIO_ENOTDIR:
+        return ENOTDIR;
+      case FILEIO_EISDIR:
+        return EISDIR;
+      case FILEIO_EINVAL:
+        return EINVAL;
+      case FILEIO_ENFILE:
+        return ENFILE;
+      case FILEIO_EMFILE:
+        return EMFILE;
+      case FILEIO_EFBIG:
+        return EFBIG;
+      case FILEIO_ENOSPC:
+        return ENOSPC;
+      case FILEIO_ESPIPE:
+        return ESPIPE;
+      case FILEIO_EROFS:
+        return EROFS;
+      case FILEIO_ENOSYS:
+        return ENOSYS;
+      case FILEIO_ENAMETOOLONG:
+        return ENAMETOOLONG;
+    }
+  return -1;
+}
+
+static char *
+remote_hostio_error (int errnum)
+{
+  int host_error = remote_fileio_errno_to_host (errnum);
+
+  if (host_error == -1)
+    error (_("Unknown remote I/O error %d"), errnum);
+  else
+    error (_("Remote I/O error: %s"), safe_strerror (host_error));
+}
+
+static void
+fclose_cleanup (void *file)
+{
+  fclose (file);
+}
+
+static void
+remote_hostio_close_cleanup (void *opaque)
+{
+  int fd = *(int *) opaque;
+  int remote_errno;
+
+  remote_hostio_close (fd, &remote_errno);
+}
+
+void
+remote_file_put (const char *local_file, const char *remote_file, int from_tty)
+{
+  struct cleanup *back_to, *close_cleanup;
+  int retcode, fd, remote_errno, bytes, io_size;
+  FILE *file;
+  gdb_byte *buffer;
+  int bytes_in_buffer;
+  int saw_eof;
+  ULONGEST offset;
+
+  if (!remote_desc)
+    error (_("command can only be used with remote target"));
+
+  file = fopen (local_file, "rb");
+  if (file == NULL)
+    perror_with_name (local_file);
+  back_to = make_cleanup (fclose_cleanup, file);
+
+  fd = remote_hostio_open (remote_file, (FILEIO_O_WRONLY | FILEIO_O_CREAT
+                                        | FILEIO_O_TRUNC),
+                          0700, &remote_errno);
+  if (fd == -1)
+    remote_hostio_error (remote_errno);
+
+  /* Send up to this many bytes at once.  They won't all fit in the
+     remote packet limit, so we'll transfer slightly fewer.  */
+  io_size = get_remote_packet_size ();
+  buffer = xmalloc (io_size);
+  make_cleanup (xfree, buffer);
+
+  close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
+
+  bytes_in_buffer = 0;
+  saw_eof = 0;
+  offset = 0;
+  while (bytes_in_buffer || !saw_eof)
+    {
+      if (!saw_eof)
+       {
+         bytes = fread (buffer + bytes_in_buffer, 1, io_size - bytes_in_buffer,
+                        file);
+         if (bytes == 0)
+           {
+             if (ferror (file))
+               error (_("Error reading %s."), local_file);
+             else
+               {
+                 /* EOF.  Unless there is something still in the
+                    buffer from the last iteration, we are done.  */
+                 saw_eof = 1;
+                 if (bytes_in_buffer == 0)
+                   break;
+               }
+           }
+       }
+      else
+       bytes = 0;
+
+      bytes += bytes_in_buffer;
+      bytes_in_buffer = 0;
+
+      retcode = remote_hostio_pwrite (fd, buffer, bytes, offset, &remote_errno);
+
+      if (retcode < 0)
+       remote_hostio_error (remote_errno);
+      else if (retcode == 0)
+       error (_("Remote write of %d bytes returned 0!"), bytes);
+      else if (retcode < bytes)
+       {
+         /* Short write.  Save the rest of the read data for the next
+            write.  */
+         bytes_in_buffer = bytes - retcode;
+         memmove (buffer, buffer + retcode, bytes_in_buffer);
+       }
+
+      offset += retcode;
+    }
+
+  discard_cleanups (close_cleanup);
+  if (remote_hostio_close (fd, &remote_errno))
+    remote_hostio_error (remote_errno);
+
+  if (from_tty)
+    printf_filtered (_("Successfully sent file \"%s\".\n"), local_file);
+  do_cleanups (back_to);
+}
+
+void
+remote_file_get (const char *remote_file, const char *local_file, int from_tty)
+{
+  struct cleanup *back_to, *close_cleanup;
+  int retcode, fd, remote_errno, bytes, io_size;
+  FILE *file;
+  gdb_byte *buffer;
+  ULONGEST offset;
+
+  if (!remote_desc)
+    error (_("command can only be used with remote target"));
+
+  fd = remote_hostio_open (remote_file, FILEIO_O_RDONLY, 0, &remote_errno);
+  if (fd == -1)
+    remote_hostio_error (remote_errno);
+
+  file = fopen (local_file, "wb");
+  if (file == NULL)
+    perror_with_name (local_file);
+  back_to = make_cleanup (fclose_cleanup, file);
+
+  /* Send up to this many bytes at once.  They won't all fit in the
+     remote packet limit, so we'll transfer slightly fewer.  */
+  io_size = get_remote_packet_size ();
+  buffer = xmalloc (io_size);
+  make_cleanup (xfree, buffer);
+
+  close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
+
+  offset = 0;
+  while (1)
+    {
+      bytes = remote_hostio_pread (fd, buffer, io_size, offset, &remote_errno);
+      if (bytes == 0)
+       /* Success, but no bytes, means end-of-file.  */
+       break;
+      if (bytes == -1)
+       remote_hostio_error (remote_errno);
+
+      offset += bytes;
+
+      bytes = fwrite (buffer, 1, bytes, file);
+      if (bytes == 0)
+       perror_with_name (local_file);
+    }
+
+  discard_cleanups (close_cleanup);
+  if (remote_hostio_close (fd, &remote_errno))
+    remote_hostio_error (remote_errno);
+
+  if (from_tty)
+    printf_filtered (_("Successfully fetched file \"%s\".\n"), remote_file);
+  do_cleanups (back_to);
+}
+
+void
+remote_file_delete (const char *remote_file, int from_tty)
+{
+  int retcode, remote_errno;
+
+  if (!remote_desc)
+    error (_("command can only be used with remote target"));
+
+  retcode = remote_hostio_unlink (remote_file, &remote_errno);
+  if (retcode == -1)
+    remote_hostio_error (remote_errno);
+
+  if (from_tty)
+    printf_filtered (_("Successfully deleted file \"%s\".\n"), remote_file);
+}
+
+static void
+remote_put_command (char *args, int from_tty)
+{
+  struct cleanup *back_to;
+  char **argv;
+
+  argv = buildargv (args);
+  if (argv == NULL)
+    nomem (0);
+  back_to = make_cleanup_freeargv (argv);
+  if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
+    error (_("Invalid parameters to remote put"));
+
+  remote_file_put (argv[0], argv[1], from_tty);
+
+  do_cleanups (back_to);
+}
+
+static void
+remote_get_command (char *args, int from_tty)
+{
+  struct cleanup *back_to;
+  char **argv;
+
+  argv = buildargv (args);
+  if (argv == NULL)
+    nomem (0);
+  back_to = make_cleanup_freeargv (argv);
+  if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
+    error (_("Invalid parameters to remote get"));
+
+  remote_file_get (argv[0], argv[1], from_tty);
+
+  do_cleanups (back_to);
+}
+
+static void
+remote_delete_command (char *args, int from_tty)
+{
+  struct cleanup *back_to;
+  char **argv;
+
+  argv = buildargv (args);
+  if (argv == NULL)
+    nomem (0);
+  back_to = make_cleanup_freeargv (argv);
+  if (argv[0] == NULL || argv[1] != NULL)
+    error (_("Invalid parameters to remote delete"));
+
+  remote_file_delete (argv[0], from_tty);
+
+  do_cleanups (back_to);
+}
+
+static void
+remote_command (char *args, int from_tty)
+{
+  help_list (remote_cmdlist, "remote ", -1, gdb_stdout);
+}
+
 static void
 init_remote_ops (void)
 {
@@ -6315,6 +6950,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_stop = remote_stop;
   remote_ops.to_xfer_partial = remote_xfer_partial;
   remote_ops.to_rcmd = remote_rcmd;
+  remote_ops.to_log_command = serial_log_command;
   remote_ops.to_get_thread_local_address = remote_get_thread_local_address;
   remote_ops.to_stratum = process_stratum;
   remote_ops.to_has_all_memory = 1;
@@ -6719,6 +7355,21 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
                         "qSupported", "supported-packets", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
+                        "vFile:open", "hostio-open", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_pread],
+                        "vFile:pread", "hostio-pread", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_pwrite],
+                        "vFile:pwrite", "hostio-pwrite", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_close],
+                        "vFile:close", "hostio-close", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_unlink],
+                        "vFile:unlink", "hostio-unlink", 0);
+
   /* Keep the old ``set remote Z-packet ...'' working.  Each individual
      Z sub-packet has its own set and show commands, but users may
      have sets to this variable in their .gdbinit files (or in their
@@ -6733,6 +7384,24 @@ packets."),
                                show_remote_protocol_Z_packet_cmd, /* FIXME: i18n: Use of remote protocol `Z' packets is %s.  */
                                &remote_set_cmdlist, &remote_show_cmdlist);
 
+  add_prefix_cmd ("remote", class_files, remote_command, _("\
+Manipulate files on the remote system\n\
+Transfer files to and from the remote target system."),
+                 &remote_cmdlist, "remote ",
+                 0 /* allow-unknown */, &cmdlist);
+
+  add_cmd ("put", class_files, remote_put_command,
+          _("Copy a local file to the remote system."),
+          &remote_cmdlist);
+
+  add_cmd ("get", class_files, remote_get_command,
+          _("Copy a remote file to the local system."),
+          &remote_cmdlist);
+
+  add_cmd ("delete", class_files, remote_delete_command,
+          _("Delete a remote file."),
+          &remote_cmdlist);
+
   /* Eventually initialize fileio.  See fileio.c */
   initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);
 }
This page took 0.030307 seconds and 4 git commands to generate.