linux-nat: Exploit /proc/<pid>/mem for writing
authorAndreas Arnez <arnez@linux.vnet.ibm.com>
Tue, 14 Mar 2017 10:14:49 +0000 (11:14 +0100)
committerAndreas Arnez <arnez@linux.vnet.ibm.com>
Tue, 14 Mar 2017 10:14:49 +0000 (11:14 +0100)
So far linux_proc_xfer_partial refused to handle write requests.  This is
still based on the assumption that the Linux kernel does not support
writes to /proc/<pid>/mem.  That used to be true, but has changed with
Linux 2.6.39 released in May 2011.

This patch lifts this restriction and now exploits /proc/<pid>/mem for
writing to inferior memory as well, if possible.

gdb/ChangeLog:

* linux-nat.c (linux_proc_xfer_partial): Handle write operations
as well.

gdb/ChangeLog
gdb/linux-nat.c

index 608501b9c63f48c440ff361509ac3c9d3a81d563..e90fbc0adfd76ce6ec6fbdce529f2c759f7da2f3 100644 (file)
@@ -1,3 +1,8 @@
+2017-03-14  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+       * linux-nat.c (linux_proc_xfer_partial): Handle write operations
+       as well.
+
 2017-03-14  Pedro Alves  <palves@redhat.com>
 
        * cp-name-parser.y (cp_demangled_name_to_comp): Update comment.
index c58ed83efd0f90135568154a5ef61adfce80c393..73ef2d49473e9d1761e8391bd7acfeeb1a15cc02 100644 (file)
@@ -3978,10 +3978,9 @@ linux_child_pid_to_exec_file (struct target_ops *self, int pid)
   return linux_proc_pid_to_exec_file (pid);
 }
 
-/* Implement the to_xfer_partial interface for memory reads using the /proc
-   filesystem.  Because we can use a single read() call for /proc, this
-   can be much more efficient than banging away at PTRACE_PEEKTEXT,
-   but it doesn't support writes.  */
+/* Implement the to_xfer_partial target method using /proc/<pid>/mem.
+   Because we can use a single read/write call, this can be much more
+   efficient than banging away at PTRACE_PEEKTEXT.  */
 
 static enum target_xfer_status
 linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
@@ -3993,7 +3992,7 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
   int fd;
   char filename[64];
 
-  if (object != TARGET_OBJECT_MEMORY || !readbuf)
+  if (object != TARGET_OBJECT_MEMORY)
     return TARGET_XFER_EOF;
 
   /* Don't bother for one word.  */
@@ -4004,26 +4003,27 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
      thread.  That requires some juggling, but is even faster.  */
   xsnprintf (filename, sizeof filename, "/proc/%d/mem",
             ptid_get_pid (inferior_ptid));
-  fd = gdb_open_cloexec (filename, O_RDONLY | O_LARGEFILE, 0);
+  fd = gdb_open_cloexec (filename, ((readbuf ? O_RDONLY : O_WRONLY)
+                                   | O_LARGEFILE), 0);
   if (fd == -1)
     return TARGET_XFER_EOF;
 
-  /* If pread64 is available, use it.  It's faster if the kernel
-     supports it (only one syscall), and it's 64-bit safe even on
-     32-bit platforms (for instance, SPARC debugging a SPARC64
-     application).  */
+  /* Use pread64/pwrite64 if available, since they save a syscall and can
+     handle 64-bit offsets even on 32-bit platforms (for instance, SPARC
+     debugging a SPARC64 application).  */
 #ifdef HAVE_PREAD64
-  if (pread64 (fd, readbuf, len, offset) != len)
+  ret = (readbuf ? pread64 (fd, readbuf, len, offset)
+        : pwrite64 (fd, writebuf, len, offset));
 #else
-  if (lseek (fd, offset, SEEK_SET) == -1 || read (fd, readbuf, len) != len)
+  ret = lseek (fd, offset, SEEK_SET);
+  if (ret != -1)
+    ret = (readbuf ? read (fd, readbuf, len)
+          : write (fd, writebuf, len));
 #endif
-    ret = 0;
-  else
-    ret = len;
 
   close (fd);
 
-  if (ret == 0)
+  if (ret == -1 || ret == 0)
     return TARGET_XFER_EOF;
   else
     {