diff mbox

[v7,07/10] Move linux_find_memory_regions_full & co.

Message ID 20150614192637.18346.28062.stgit@host1.jankratochvil.net
State New
Headers show

Commit Message

Jan Kratochvil June 14, 2015, 7:26 p.m. UTC
Hi,

this should be just a move with no changes.

Approved by:
	https://sourceware.org/ml/gdb-patches/2014-05/msg00372.html


Jan


gdb/ChangeLog
2014-02-26  Aleksandar Ristovski  <aristovski@qnx.com
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

	Move linux_find_memory_regions_full & co.
	* linux-tdep.c (nat/linux-maps.h): Include.
	(gdb_regex.h): Remove the include.
	(enum filterflags, struct smaps_vmflags, read_mapping, decode_vmflags)
	(mapping_is_anonymous_p, dump_mapping_p): Moved to nat/linux-maps.c.
	(linux_find_memory_region_ftype): Moved typedef to nat/linux-maps.h.
	(linux_find_memory_regions_full): Moved definition to nat/linux-maps.c.
	* nat/linux-maps.c: Include ctype.h, target/target-utils.h, gdb_regex.h
	and target/target.h.
	(struct smaps_vmflags, read_mapping, decode_vmflags)
	(mapping_is_anonymous_p, dump_mapping_p): Move from linux-tdep.c.
	(linux_find_memory_regions_full): Move from linux-tdep.c.
	* nat/linux-maps.h (read_mapping): New declaration.
	(linux_find_memory_region_ftype, enum filterflags): Moved from
	linux-tdep.c.
	(linux_find_memory_regions_full): New declaration.
	* target.c (target/target-utils.h): Include.
	(read_alloc_pread_ftype): Moved typedef to target/target-utils.h.
	(read_alloc, read_stralloc_func_ftype, read_stralloc): Moved
	definitions to target/target-utils.c.
	* target.h (target_fileio_read_stralloc): Move it to target/target.h.
	* target/target-utils.c (read_alloc, read_stralloc): Move definitions
	from target.c.
	* target/target-utils.h (read_alloc_pread_ftype): New typedef.
	(read_alloc): New declaration.
	(read_stralloc_func_ftype): New typedef.
	(read_stralloc): New declaration.
	* target/target.h (target_fileio_read_stralloc): Move it from target.h.

gdb/gdbserver/ChangeLog
2015-06-14  Aleksandar Ristovski  <aristovski@qnx.com
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

	* target.c: Include target/target-utils.h and fcntl.h.
	(target_fileio_read_stralloc_1_pread, target_fileio_read_stralloc_1)
	(target_fileio_read_stralloc): New functions.
---
 gdb/gdbserver/target.c    |   36 +++
 gdb/linux-tdep.c          |  499 ---------------------------------------------
 gdb/nat/linux-maps.c      |  473 +++++++++++++++++++++++++++++++++++++++++++
 gdb/nat/linux-maps.h      |   42 ++++
 gdb/target.c              |   91 --------
 gdb/target.h              |   10 -
 gdb/target/target-utils.c |   79 +++++++
 gdb/target/target-utils.h |   12 +
 gdb/target/target.h       |   11 +
 9 files changed, 656 insertions(+), 597 deletions(-)
diff mbox

Patch

diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index 14999e6..5525b1f 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -20,6 +20,8 @@ 
 
 #include "server.h"
 #include "tracepoint.h"
+#include "target/target-utils.h"
+#include <fcntl.h>
 
 struct target_ops *the_target;
 
@@ -218,3 +220,37 @@  kill_inferior (int pid)
 
   return (*the_target->kill) (pid);
 }
+
+static int
+target_fileio_read_stralloc_1_pread (int handle, gdb_byte *read_buf, int len,
+				     ULONGEST offset, int *target_errno)
+{
+  int retval = pread (handle, read_buf, len, offset);
+
+  *target_errno = errno;
+  return retval;
+}
+
+static LONGEST
+target_fileio_read_stralloc_1 (struct inferior *inf, const char *filename,
+			       gdb_byte **buf_p, int padding)
+{
+  int fd;
+  LONGEST retval;
+
+  fd = open (filename, O_RDONLY);
+  if (fd == -1)
+    return -1;
+
+  retval = read_alloc (buf_p, fd, target_fileio_read_stralloc_1_pread, padding);
+
+  close (fd);
+
+  return retval;
+}
+
+char *
+target_fileio_read_stralloc (struct inferior *inf, const char *filename)
+{
+  return read_stralloc (inf, filename, target_fileio_read_stralloc_1);
+}
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index fb59305..3bd672a 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -35,56 +35,11 @@ 
 #include "observer.h"
 #include "objfiles.h"
 #include "infcall.h"
+#include "nat/linux-maps.h"
 #include "gdbcmd.h"
-#include "gdb_regex.h"
 
 #include <ctype.h>
 
-/* This enum represents the values that the user can choose when
-   informing the Linux kernel about which memory mappings will be
-   dumped in a corefile.  They are described in the file
-   Documentation/filesystems/proc.txt, inside the Linux kernel
-   tree.  */
-
-enum filterflags
-  {
-    COREFILTER_ANON_PRIVATE = 1 << 0,
-    COREFILTER_ANON_SHARED = 1 << 1,
-    COREFILTER_MAPPED_PRIVATE = 1 << 2,
-    COREFILTER_MAPPED_SHARED = 1 << 3,
-    COREFILTER_ELF_HEADERS = 1 << 4,
-    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
-    COREFILTER_HUGETLB_SHARED = 1 << 6,
-  };
-
-/* This struct is used to map flags found in the "VmFlags:" field (in
-   the /proc/<PID>/smaps file).  */
-
-struct smaps_vmflags
-  {
-    /* Zero if this structure has not been initialized yet.  It
-       probably means that the Linux kernel being used does not emit
-       the "VmFlags:" field on "/proc/PID/smaps".  */
-
-    unsigned int initialized_p : 1;
-
-    /* Memory mapped I/O area (VM_IO, "io").  */
-
-    unsigned int io_page : 1;
-
-    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
-
-    unsigned int uses_huge_tlb : 1;
-
-    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
-
-    unsigned int exclude_coredump : 1;
-
-    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
-
-    unsigned int shared_mapping : 1;
-  };
-
 /* Whether to take the /proc/PID/coredump_filter into account when
    generating a corefile.  */
 
@@ -395,286 +350,6 @@  linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
-/* Service function for corefiles and info proc.  */
-
-static void
-read_mapping (const char *line,
-	      ULONGEST *addr, ULONGEST *endaddr,
-	      const char **permissions, size_t *permissions_len,
-	      ULONGEST *offset,
-              const char **device, size_t *device_len,
-	      ULONGEST *inode,
-	      const char **filename)
-{
-  const char *p = line;
-
-  *addr = strtoulst (p, &p, 16);
-  if (*p == '-')
-    p++;
-  *endaddr = strtoulst (p, &p, 16);
-
-  p = skip_spaces_const (p);
-  *permissions = p;
-  while (*p && !isspace (*p))
-    p++;
-  *permissions_len = p - *permissions;
-
-  *offset = strtoulst (p, &p, 16);
-
-  p = skip_spaces_const (p);
-  *device = p;
-  while (*p && !isspace (*p))
-    p++;
-  *device_len = p - *device;
-
-  *inode = strtoulst (p, &p, 10);
-
-  p = skip_spaces_const (p);
-  *filename = p;
-}
-
-/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
-
-   This function was based on the documentation found on
-   <Documentation/filesystems/proc.txt>, on the Linux kernel.
-
-   Linux kernels before commit
-   834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
-   field on smaps.  */
-
-static void
-decode_vmflags (char *p, struct smaps_vmflags *v)
-{
-  char *saveptr = NULL;
-  const char *s;
-
-  v->initialized_p = 1;
-  p = skip_to_space (p);
-  p = skip_spaces (p);
-
-  for (s = strtok_r (p, " ", &saveptr);
-       s != NULL;
-       s = strtok_r (NULL, " ", &saveptr))
-    {
-      if (strcmp (s, "io") == 0)
-	v->io_page = 1;
-      else if (strcmp (s, "ht") == 0)
-	v->uses_huge_tlb = 1;
-      else if (strcmp (s, "dd") == 0)
-	v->exclude_coredump = 1;
-      else if (strcmp (s, "sh") == 0)
-	v->shared_mapping = 1;
-    }
-}
-
-/* Return 1 if the memory mapping is anonymous, 0 otherwise.
-
-   FILENAME is the name of the file present in the first line of the
-   memory mapping, in the "/proc/PID/smaps" output.  For example, if
-   the first line is:
-
-   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
-
-   Then FILENAME will be "/path/to/file".  */
-
-static int
-mapping_is_anonymous_p (const char *filename)
-{
-  static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
-  static int init_regex_p = 0;
-
-  if (!init_regex_p)
-    {
-      struct cleanup *c = make_cleanup (null_cleanup, NULL);
-
-      /* Let's be pessimistic and assume there will be an error while
-	 compiling the regex'es.  */
-      init_regex_p = -1;
-
-      /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
-	 without the "(deleted)" string in the end).  We know for
-	 sure, based on the Linux kernel code, that memory mappings
-	 whose associated filename is "/dev/zero" are guaranteed to be
-	 MAP_ANONYMOUS.  */
-      compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
-			   _("Could not compile regex to match /dev/zero "
-			     "filename"));
-      /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
-	 without the "(deleted)" string in the end).  These filenames
-	 refer to shared memory (shmem), and memory mappings
-	 associated with them are MAP_ANONYMOUS as well.  */
-      compile_rx_or_error (&shmem_file_regex,
-			   "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
-			   _("Could not compile regex to match shmem "
-			     "filenames"));
-      /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
-	 Linux kernel's 'n_link == 0' code, which is responsible to
-	 decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
-	 mapping.  In other words, if FILE_DELETED_REGEX matches, it
-	 does not necessarily mean that we are dealing with an
-	 anonymous shared mapping.  However, there is no easy way to
-	 detect this currently, so this is the best approximation we
-	 have.
-
-	 As a result, GDB will dump readonly pages of deleted
-	 executables when using the default value of coredump_filter
-	 (0x33), while the Linux kernel will not dump those pages.
-	 But we can live with that.  */
-      compile_rx_or_error (&file_deleted_regex, " (deleted)$",
-			   _("Could not compile regex to match "
-			     "'<file> (deleted)'"));
-      /* We will never release these regexes, so just discard the
-	 cleanups.  */
-      discard_cleanups (c);
-
-      /* If we reached this point, then everything succeeded.  */
-      init_regex_p = 1;
-    }
-
-  if (init_regex_p == -1)
-    {
-      const char deleted[] = " (deleted)";
-      size_t del_len = sizeof (deleted) - 1;
-      size_t filename_len = strlen (filename);
-
-      /* There was an error while compiling the regex'es above.  In
-	 order to try to give some reliable information to the caller,
-	 we just try to find the string " (deleted)" in the filename.
-	 If we managed to find it, then we assume the mapping is
-	 anonymous.  */
-      return (filename_len >= del_len
-	      && strcmp (filename + filename_len - del_len, deleted) == 0);
-    }
-
-  if (*filename == '\0'
-      || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
-      || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
-      || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
-    return 1;
-
-  return 0;
-}
-
-/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
-   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
-   greater than 0 if it should.
-
-   In a nutshell, this is the logic that we follow in order to decide
-   if a mapping should be dumped or not.
-
-   - If the mapping is associated to a file whose name ends with
-     " (deleted)", or if the file is "/dev/zero", or if it is
-     "/SYSV%08x" (shared memory), or if there is no file associated
-     with it, or if the AnonHugePages: or the Anonymous: fields in the
-     /proc/PID/smaps have contents, then GDB considers this mapping to
-     be anonymous.  Otherwise, GDB considers this mapping to be a
-     file-backed mapping (because there will be a file associated with
-     it).
- 
-     It is worth mentioning that, from all those checks described
-     above, the most fragile is the one to see if the file name ends
-     with " (deleted)".  This does not necessarily mean that the
-     mapping is anonymous, because the deleted file associated with
-     the mapping may have been a hard link to another file, for
-     example.  The Linux kernel checks to see if "i_nlink == 0", but
-     GDB cannot easily (and normally) do this check (iff running as
-     root, it could find the mapping in /proc/PID/map_files/ and
-     determine whether there still are other hard links to the
-     inode/file).  Therefore, we made a compromise here, and we assume
-     that if the file name ends with " (deleted)", then the mapping is
-     indeed anonymous.  FWIW, this is something the Linux kernel could
-     do better: expose this information in a more direct way.
- 
-   - If we see the flag "sh" in the "VmFlags:" field (in
-     /proc/PID/smaps), then certainly the memory mapping is shared
-     (VM_SHARED).  If we have access to the VmFlags, and we don't see
-     the "sh" there, then certainly the mapping is private.  However,
-     Linux kernels before commit
-     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
-     "VmFlags:" field; in that case, we use another heuristic: if we
-     see 'p' in the permission flags, then we assume that the mapping
-     is private, even though the presence of the 's' flag there would
-     mean VM_MAYSHARE, which means the mapping could still be private.
-     This should work OK enough, however.  */
-
-static int
-dump_mapping_p (enum filterflags filterflags, const struct smaps_vmflags *v,
-		int maybe_private_p, int mapping_anon_p, int mapping_file_p,
-		const char *filename)
-{
-  /* Initially, we trust in what we received from our caller.  This
-     value may not be very precise (i.e., it was probably gathered
-     from the permission line in the /proc/PID/smaps list, which
-     actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
-     what we have until we take a look at the "VmFlags:" field
-     (assuming that the version of the Linux kernel being used
-     supports it, of course).  */
-  int private_p = maybe_private_p;
-
-  /* We always dump vDSO and vsyscall mappings, because it's likely that
-     there'll be no file to read the contents from at core load time.
-     The kernel does the same.  */
-  if (strcmp ("[vdso]", filename) == 0
-      || strcmp ("[vsyscall]", filename) == 0)
-    return 1;
-
-  if (v->initialized_p)
-    {
-      /* We never dump I/O mappings.  */
-      if (v->io_page)
-	return 0;
-
-      /* Check if we should exclude this mapping.  */
-      if (v->exclude_coredump)
-	return 0;
-
-      /* Update our notion of whether this mapping is shared or
-	 private based on a trustworthy value.  */
-      private_p = !v->shared_mapping;
-
-      /* HugeTLB checking.  */
-      if (v->uses_huge_tlb)
-	{
-	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
-	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
-	    return 1;
-
-	  return 0;
-	}
-    }
-
-  if (private_p)
-    {
-      if (mapping_anon_p && mapping_file_p)
-	{
-	  /* This is a special situation.  It can happen when we see a
-	     mapping that is file-backed, but that contains anonymous
-	     pages.  */
-	  return ((filterflags & COREFILTER_ANON_PRIVATE) != 0
-		  || (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
-	}
-      else if (mapping_anon_p)
-	return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
-      else
-	return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
-    }
-  else
-    {
-      if (mapping_anon_p && mapping_file_p)
-	{
-	  /* This is a special situation.  It can happen when we see a
-	     mapping that is file-backed, but that contains anonymous
-	     pages.  */
-	  return ((filterflags & COREFILTER_ANON_SHARED) != 0
-		  || (filterflags & COREFILTER_MAPPED_SHARED) != 0);
-	}
-      else if (mapping_anon_p)
-	return (filterflags & COREFILTER_ANON_SHARED) != 0;
-      else
-	return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
-    }
-}
-
 /* Implement the "info proc" command.  */
 
 static void
@@ -1098,178 +773,6 @@  linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
     error (_("unable to handle request"));
 }
 
-/* Callback function for linux_find_memory_regions_full.  If it returns
-   non-zero linux_find_memory_regions_full returns immediately with that
-   value.  */
-
-typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
-					    ULONGEST offset, ULONGEST inode,
-					    int read, int write,
-					    int exec, int modified,
-					    const char *filename,
-					    void *data);
-
-/* List memory regions in the inferior PID matched to FILTERFLAGS for
-   a corefile.  Call FUNC with FUNC_DATA for each such region.  Return
-   immediately with the value returned by FUNC if it is non-zero.
-   *MEMORY_TO_FREE_PTR should be registered to be freed automatically if
-   called FUNC throws an exception.  MEMORY_TO_FREE_PTR can be also
-   passed as NULL if it is not used.  Return -1 if error occurs, 0 if
-   all memory regions have been processed or return the value from FUNC
-   if FUNC returns non-zero.  */
-
-static int
-linux_find_memory_regions_full (pid_t pid, enum filterflags filterflags,
-				linux_find_memory_region_ftype *func,
-				void *func_data)
-{
-  char mapsfilename[100];
-  char *data;
-
-  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
-  data = target_fileio_read_stralloc (NULL, mapsfilename);
-  if (data == NULL)
-    {
-      /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
-      data = target_fileio_read_stralloc (NULL, mapsfilename);
-    }
-
-  if (data != NULL)
-    {
-      struct cleanup *cleanup = make_cleanup (xfree, data);
-      char *line, *t;
-      int retval = 0;
-
-      line = strtok_r (data, "\n", &t);
-      while (line != NULL)
-	{
-	  ULONGEST addr, endaddr, offset, inode;
-	  const char *permissions, *device, *filename;
-	  struct smaps_vmflags v;
-	  size_t permissions_len, device_len;
-	  int read, write, exec, priv;
-	  int has_anonymous = 0;
-	  int should_dump_p = 0;
-	  int mapping_anon_p;
-	  int mapping_file_p;
-
-	  memset (&v, 0, sizeof (v));
-	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
-			&offset, &device, &device_len, &inode, &filename);
-	  mapping_anon_p = mapping_is_anonymous_p (filename);
-	  /* If the mapping is not anonymous, then we can consider it
-	     to be file-backed.  These two states (anonymous or
-	     file-backed) seem to be exclusive, but they can actually
-	     coexist.  For example, if a file-backed mapping has
-	     "Anonymous:" pages (see more below), then the Linux
-	     kernel will dump this mapping when the user specified
-	     that she only wants anonymous mappings in the corefile
-	     (*even* when she explicitly disabled the dumping of
-	     file-backed mappings).  */
-	  mapping_file_p = !mapping_anon_p;
-
-	  /* Decode permissions.  */
-	  read = (memchr (permissions, 'r', permissions_len) != 0);
-	  write = (memchr (permissions, 'w', permissions_len) != 0);
-	  exec = (memchr (permissions, 'x', permissions_len) != 0);
-	  /* 'private' here actually means VM_MAYSHARE, and not
-	     VM_SHARED.  In order to know if a mapping is really
-	     private or not, we must check the flag "sh" in the
-	     VmFlags field.  This is done by decode_vmflags.  However,
-	     if we are using a Linux kernel released before the commit
-	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
-	     not have the VmFlags there.  In this case, there is
-	     really no way to know if we are dealing with VM_SHARED,
-	     so we just assume that VM_MAYSHARE is enough.  */
-	  priv = memchr (permissions, 'p', permissions_len) != 0;
-
-	  /* Try to detect if region should be dumped by parsing smaps
-	     counters.  */
-	  for (line = strtok_r (NULL, "\n", &t);
-	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
-	       line = strtok_r (NULL, "\n", &t))
-	    {
-	      char keyword[64 + 1];
-
-	      if (sscanf (line, "%64s", keyword) != 1)
-		{
-		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
-		  break;
-		}
-
-	      if (strcmp (keyword, "Anonymous:") == 0)
-		{
-		  /* Older Linux kernels did not support the
-		     "Anonymous:" counter.  Check it here.  */
-		  has_anonymous = 1;
-		}
-	      else if (strcmp (keyword, "VmFlags:") == 0)
-		decode_vmflags (line, &v);
-
-	      if (strcmp (keyword, "AnonHugePages:") == 0
-		  || strcmp (keyword, "Anonymous:") == 0)
-		{
-		  unsigned long number;
-
-		  if (sscanf (line, "%*s%lu", &number) != 1)
-		    {
-		      warning (_("Error parsing {s,}maps file '%s' number"),
-			       mapsfilename);
-		      break;
-		    }
-		  if (number > 0)
-		    {
-		      /* Even if we are dealing with a file-backed
-			 mapping, if it contains anonymous pages we
-			 consider it to be *also* an anonymous
-			 mapping, because this is what the Linux
-			 kernel does:
-
-			 // Dump segments that have been written to.
-			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
-			 	goto whole;
-
-			 Note that if the mapping is already marked as
-			 file-backed (i.e., mapping_file_p is
-			 non-zero), then this is a special case, and
-			 this mapping will be dumped either when the
-			 user wants to dump file-backed *or* anonymous
-			 mappings.  */
-		      mapping_anon_p = 1;
-		    }
-		}
-	    }
-
-	  if (has_anonymous)
-	    should_dump_p = dump_mapping_p (filterflags, &v, priv,
-					    mapping_anon_p, mapping_file_p,
-					    filename);
-	  else
-	    {
-	      /* Older Linux kernels did not support the "Anonymous:" counter.
-		 If it is missing, we can't be sure - dump all the pages.  */
-	      should_dump_p = 1;
-	    }
-
-	  /* Invoke the callback function to create the corefile segment.  */
-	  if (should_dump_p)
-	    retval = func (addr, endaddr - addr, offset, inode,
-			   read, write, exec,
-			   1, /* MODIFIED is true because we want to dump the
-				 mapping.  */
-			   filename, func_data);
-	  if (retval != 0)
-	    break;
-	}
-
-      do_cleanups (cleanup);
-      return retval;
-    }
-
-  return -1;
-}
-
 /* A structure for passing information through
    linux_find_memory_regions_full.  */
 
diff --git a/gdb/nat/linux-maps.c b/gdb/nat/linux-maps.c
index 01c8836..ef3da6a 100644
--- a/gdb/nat/linux-maps.c
+++ b/gdb/nat/linux-maps.c
@@ -18,3 +18,476 @@ 
 
 #include "common-defs.h"
 #include "linux-maps.h"
+#include <ctype.h>
+#include "target/target-utils.h"
+#include "gdb_regex.h"
+#include "target/target.h"
+
+/* This struct is used to map flags found in the "VmFlags:" field (in
+   the /proc/<PID>/smaps file).  */
+
+struct smaps_vmflags
+  {
+    /* Zero if this structure has not been initialized yet.  It
+       probably means that the Linux kernel being used does not emit
+       the "VmFlags:" field on "/proc/PID/smaps".  */
+
+    unsigned int initialized_p : 1;
+
+    /* Memory mapped I/O area (VM_IO, "io").  */
+
+    unsigned int io_page : 1;
+
+    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
+
+    unsigned int uses_huge_tlb : 1;
+
+    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
+
+    unsigned int exclude_coredump : 1;
+
+    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
+
+    unsigned int shared_mapping : 1;
+  };
+
+/* Service function for corefiles and info proc.  */
+
+void
+read_mapping (const char *line,
+	      ULONGEST *addr, ULONGEST *endaddr,
+	      const char **permissions, size_t *permissions_len,
+	      ULONGEST *offset,
+              const char **device, size_t *device_len,
+	      ULONGEST *inode,
+	      const char **filename)
+{
+  const char *p = line;
+
+  *addr = strtoulst (p, &p, 16);
+  if (*p == '-')
+    p++;
+  *endaddr = strtoulst (p, &p, 16);
+
+  p = skip_spaces_const (p);
+  *permissions = p;
+  while (*p && !isspace (*p))
+    p++;
+  *permissions_len = p - *permissions;
+
+  *offset = strtoulst (p, &p, 16);
+
+  p = skip_spaces_const (p);
+  *device = p;
+  while (*p && !isspace (*p))
+    p++;
+  *device_len = p - *device;
+
+  *inode = strtoulst (p, &p, 10);
+
+  p = skip_spaces_const (p);
+  *filename = p;
+}
+
+/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
+
+   This function was based on the documentation found on
+   <Documentation/filesystems/proc.txt>, on the Linux kernel.
+
+   Linux kernels before commit
+   834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
+   field on smaps.  */
+
+static void
+decode_vmflags (char *p, struct smaps_vmflags *v)
+{
+  char *saveptr = NULL;
+  const char *s;
+
+  v->initialized_p = 1;
+  p = skip_to_space (p);
+  p = skip_spaces (p);
+
+  for (s = strtok_r (p, " ", &saveptr);
+       s != NULL;
+       s = strtok_r (NULL, " ", &saveptr))
+    {
+      if (strcmp (s, "io") == 0)
+	v->io_page = 1;
+      else if (strcmp (s, "ht") == 0)
+	v->uses_huge_tlb = 1;
+      else if (strcmp (s, "dd") == 0)
+	v->exclude_coredump = 1;
+      else if (strcmp (s, "sh") == 0)
+	v->shared_mapping = 1;
+    }
+}
+
+/* Return 1 if the memory mapping is anonymous, 0 otherwise.
+
+   FILENAME is the name of the file present in the first line of the
+   memory mapping, in the "/proc/PID/smaps" output.  For example, if
+   the first line is:
+
+   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
+
+   Then FILENAME will be "/path/to/file".  */
+
+static int
+mapping_is_anonymous_p (const char *filename)
+{
+  static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
+  static int init_regex_p = 0;
+
+  if (!init_regex_p)
+    {
+      struct cleanup *c = make_cleanup (null_cleanup, NULL);
+
+      /* Let's be pessimistic and assume there will be an error while
+	 compiling the regex'es.  */
+      init_regex_p = -1;
+
+      /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
+	 without the "(deleted)" string in the end).  We know for
+	 sure, based on the Linux kernel code, that memory mappings
+	 whose associated filename is "/dev/zero" are guaranteed to be
+	 MAP_ANONYMOUS.  */
+      compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match /dev/zero "
+			     "filename"));
+      /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
+	 without the "(deleted)" string in the end).  These filenames
+	 refer to shared memory (shmem), and memory mappings
+	 associated with them are MAP_ANONYMOUS as well.  */
+      compile_rx_or_error (&shmem_file_regex,
+			   "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match shmem "
+			     "filenames"));
+      /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
+	 Linux kernel's 'n_link == 0' code, which is responsible to
+	 decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
+	 mapping.  In other words, if FILE_DELETED_REGEX matches, it
+	 does not necessarily mean that we are dealing with an
+	 anonymous shared mapping.  However, there is no easy way to
+	 detect this currently, so this is the best approximation we
+	 have.
+
+	 As a result, GDB will dump readonly pages of deleted
+	 executables when using the default value of coredump_filter
+	 (0x33), while the Linux kernel will not dump those pages.
+	 But we can live with that.  */
+      compile_rx_or_error (&file_deleted_regex, " (deleted)$",
+			   _("Could not compile regex to match "
+			     "'<file> (deleted)'"));
+      /* We will never release these regexes, so just discard the
+	 cleanups.  */
+      discard_cleanups (c);
+
+      /* If we reached this point, then everything succeeded.  */
+      init_regex_p = 1;
+    }
+
+  if (init_regex_p == -1)
+    {
+      const char deleted[] = " (deleted)";
+      size_t del_len = sizeof (deleted) - 1;
+      size_t filename_len = strlen (filename);
+
+      /* There was an error while compiling the regex'es above.  In
+	 order to try to give some reliable information to the caller,
+	 we just try to find the string " (deleted)" in the filename.
+	 If we managed to find it, then we assume the mapping is
+	 anonymous.  */
+      return (filename_len >= del_len
+	      && strcmp (filename + filename_len - del_len, deleted) == 0);
+    }
+
+  if (*filename == '\0'
+      || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
+      || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
+      || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
+   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
+   greater than 0 if it should.
+
+   In a nutshell, this is the logic that we follow in order to decide
+   if a mapping should be dumped or not.
+
+   - If the mapping is associated to a file whose name ends with
+     " (deleted)", or if the file is "/dev/zero", or if it is
+     "/SYSV%08x" (shared memory), or if there is no file associated
+     with it, or if the AnonHugePages: or the Anonymous: fields in the
+     /proc/PID/smaps have contents, then GDB considers this mapping to
+     be anonymous.  Otherwise, GDB considers this mapping to be a
+     file-backed mapping (because there will be a file associated with
+     it).
+ 
+     It is worth mentioning that, from all those checks described
+     above, the most fragile is the one to see if the file name ends
+     with " (deleted)".  This does not necessarily mean that the
+     mapping is anonymous, because the deleted file associated with
+     the mapping may have been a hard link to another file, for
+     example.  The Linux kernel checks to see if "i_nlink == 0", but
+     GDB cannot easily (and normally) do this check (iff running as
+     root, it could find the mapping in /proc/PID/map_files/ and
+     determine whether there still are other hard links to the
+     inode/file).  Therefore, we made a compromise here, and we assume
+     that if the file name ends with " (deleted)", then the mapping is
+     indeed anonymous.  FWIW, this is something the Linux kernel could
+     do better: expose this information in a more direct way.
+ 
+   - If we see the flag "sh" in the "VmFlags:" field (in
+     /proc/PID/smaps), then certainly the memory mapping is shared
+     (VM_SHARED).  If we have access to the VmFlags, and we don't see
+     the "sh" there, then certainly the mapping is private.  However,
+     Linux kernels before commit
+     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
+     "VmFlags:" field; in that case, we use another heuristic: if we
+     see 'p' in the permission flags, then we assume that the mapping
+     is private, even though the presence of the 's' flag there would
+     mean VM_MAYSHARE, which means the mapping could still be private.
+     This should work OK enough, however.  */
+
+static int
+dump_mapping_p (enum filterflags filterflags, const struct smaps_vmflags *v,
+		int maybe_private_p, int mapping_anon_p, int mapping_file_p,
+		const char *filename)
+{
+  /* Initially, we trust in what we received from our caller.  This
+     value may not be very precise (i.e., it was probably gathered
+     from the permission line in the /proc/PID/smaps list, which
+     actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
+     what we have until we take a look at the "VmFlags:" field
+     (assuming that the version of the Linux kernel being used
+     supports it, of course).  */
+  int private_p = maybe_private_p;
+
+  /* We always dump vDSO and vsyscall mappings, because it's likely that
+     there'll be no file to read the contents from at core load time.
+     The kernel does the same.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 1;
+
+  if (v->initialized_p)
+    {
+      /* We never dump I/O mappings.  */
+      if (v->io_page)
+	return 0;
+
+      /* Check if we should exclude this mapping.  */
+      if (v->exclude_coredump)
+	return 0;
+
+      /* Update our notion of whether this mapping is shared or
+	 private based on a trustworthy value.  */
+      private_p = !v->shared_mapping;
+
+      /* HugeTLB checking.  */
+      if (v->uses_huge_tlb)
+	{
+	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
+	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
+	    return 1;
+
+	  return 0;
+	}
+    }
+
+  if (private_p)
+    {
+      if (mapping_anon_p && mapping_file_p)
+	{
+	  /* This is a special situation.  It can happen when we see a
+	     mapping that is file-backed, but that contains anonymous
+	     pages.  */
+	  return ((filterflags & COREFILTER_ANON_PRIVATE) != 0
+		  || (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
+	}
+      else if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
+    }
+  else
+    {
+      if (mapping_anon_p && mapping_file_p)
+	{
+	  /* This is a special situation.  It can happen when we see a
+	     mapping that is file-backed, but that contains anonymous
+	     pages.  */
+	  return ((filterflags & COREFILTER_ANON_SHARED) != 0
+		  || (filterflags & COREFILTER_MAPPED_SHARED) != 0);
+	}
+      else if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_SHARED) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
+    }
+}
+
+/* List memory regions in the inferior PID matched to FILTERFLAGS for
+   a corefile.  Call FUNC with FUNC_DATA for each such region.  Return
+   immediately with the value returned by FUNC if it is non-zero.
+   *MEMORY_TO_FREE_PTR should be registered to be freed automatically if
+   called FUNC throws an exception.  MEMORY_TO_FREE_PTR can be also
+   passed as NULL if it is not used.  Return -1 if error occurs, 0 if
+   all memory regions have been processed or return the value from FUNC
+   if FUNC returns non-zero.  */
+
+int
+linux_find_memory_regions_full (pid_t pid, enum filterflags filterflags,
+				linux_find_memory_region_ftype *func,
+				void *func_data)
+{
+  char mapsfilename[100];
+  char *data;
+
+  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
+  data = target_fileio_read_stralloc (NULL, mapsfilename);
+  if (data == NULL)
+    {
+      /* Older Linux kernels did not support /proc/PID/smaps.  */
+      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
+      data = target_fileio_read_stralloc (NULL, mapsfilename);
+    }
+
+  if (data != NULL)
+    {
+      struct cleanup *cleanup = make_cleanup (xfree, data);
+      char *line, *t;
+      int retval = 0;
+
+      line = strtok_r (data, "\n", &t);
+      while (line != NULL)
+	{
+	  ULONGEST addr, endaddr, offset, inode;
+	  const char *permissions, *device, *filename;
+	  struct smaps_vmflags v;
+	  size_t permissions_len, device_len;
+	  int read, write, exec, priv;
+	  int has_anonymous = 0;
+	  int should_dump_p = 0;
+	  int mapping_anon_p;
+	  int mapping_file_p;
+
+	  memset (&v, 0, sizeof (v));
+	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
+			&offset, &device, &device_len, &inode, &filename);
+	  mapping_anon_p = mapping_is_anonymous_p (filename);
+	  /* If the mapping is not anonymous, then we can consider it
+	     to be file-backed.  These two states (anonymous or
+	     file-backed) seem to be exclusive, but they can actually
+	     coexist.  For example, if a file-backed mapping has
+	     "Anonymous:" pages (see more below), then the Linux
+	     kernel will dump this mapping when the user specified
+	     that she only wants anonymous mappings in the corefile
+	     (*even* when she explicitly disabled the dumping of
+	     file-backed mappings).  */
+	  mapping_file_p = !mapping_anon_p;
+
+	  /* Decode permissions.  */
+	  read = (memchr (permissions, 'r', permissions_len) != 0);
+	  write = (memchr (permissions, 'w', permissions_len) != 0);
+	  exec = (memchr (permissions, 'x', permissions_len) != 0);
+	  /* 'private' here actually means VM_MAYSHARE, and not
+	     VM_SHARED.  In order to know if a mapping is really
+	     private or not, we must check the flag "sh" in the
+	     VmFlags field.  This is done by decode_vmflags.  However,
+	     if we are using a Linux kernel released before the commit
+	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
+	     not have the VmFlags there.  In this case, there is
+	     really no way to know if we are dealing with VM_SHARED,
+	     so we just assume that VM_MAYSHARE is enough.  */
+	  priv = memchr (permissions, 'p', permissions_len) != 0;
+
+	  /* Try to detect if region should be dumped by parsing smaps
+	     counters.  */
+	  for (line = strtok_r (NULL, "\n", &t);
+	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+	       line = strtok_r (NULL, "\n", &t))
+	    {
+	      char keyword[64 + 1];
+
+	      if (sscanf (line, "%64s", keyword) != 1)
+		{
+		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
+		  break;
+		}
+
+	      if (strcmp (keyword, "Anonymous:") == 0)
+		{
+		  /* Older Linux kernels did not support the
+		     "Anonymous:" counter.  Check it here.  */
+		  has_anonymous = 1;
+		}
+	      else if (strcmp (keyword, "VmFlags:") == 0)
+		decode_vmflags (line, &v);
+
+	      if (strcmp (keyword, "AnonHugePages:") == 0
+		  || strcmp (keyword, "Anonymous:") == 0)
+		{
+		  unsigned long number;
+
+		  if (sscanf (line, "%*s%lu", &number) != 1)
+		    {
+		      warning (_("Error parsing {s,}maps file '%s' number"),
+			       mapsfilename);
+		      break;
+		    }
+		  if (number > 0)
+		    {
+		      /* Even if we are dealing with a file-backed
+			 mapping, if it contains anonymous pages we
+			 consider it to be *also* an anonymous
+			 mapping, because this is what the Linux
+			 kernel does:
+
+			 // Dump segments that have been written to.
+			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
+			 	goto whole;
+
+			 Note that if the mapping is already marked as
+			 file-backed (i.e., mapping_file_p is
+			 non-zero), then this is a special case, and
+			 this mapping will be dumped either when the
+			 user wants to dump file-backed *or* anonymous
+			 mappings.  */
+		      mapping_anon_p = 1;
+		    }
+		}
+	    }
+
+	  if (has_anonymous)
+	    should_dump_p = dump_mapping_p (filterflags, &v, priv,
+					    mapping_anon_p, mapping_file_p,
+					    filename);
+	  else
+	    {
+	      /* Older Linux kernels did not support the "Anonymous:" counter.
+		 If it is missing, we can't be sure - dump all the pages.  */
+	      should_dump_p = 1;
+	    }
+
+	  /* Invoke the callback function to create the corefile segment.  */
+	  if (should_dump_p)
+	    retval = func (addr, endaddr - addr, offset, inode,
+			   read, write, exec,
+			   1, /* MODIFIED is true because we want to dump the
+				 mapping.  */
+			   filename, func_data);
+	  if (retval != 0)
+	    break;
+	}
+
+      do_cleanups (cleanup);
+      return retval;
+    }
+
+  return -1;
+}
diff --git a/gdb/nat/linux-maps.h b/gdb/nat/linux-maps.h
index 2cff321..7e10d65 100644
--- a/gdb/nat/linux-maps.h
+++ b/gdb/nat/linux-maps.h
@@ -19,4 +19,46 @@ 
 #ifndef NAT_LINUX_MAPS_H
 #define NAT_LINUX_MAPS_H
 
+extern void
+  read_mapping (const char *line,
+		ULONGEST *addr, ULONGEST *endaddr,
+		const char **permissions, size_t *permissions_len,
+		ULONGEST *offset,
+		const char **device, size_t *device_len,
+		ULONGEST *inode,
+		const char **filename);
+
+/* Callback function for linux_find_memory_regions_full.  If it returns
+   non-zero linux_find_memory_regions_full returns immediately with that
+   value.  */
+
+typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
+					    ULONGEST offset, ULONGEST inode,
+					    int read, int write,
+					    int exec, int modified,
+					    const char *filename,
+					    void *data);
+
+/* This enum represents the values that the user can choose when
+   informing the Linux kernel about which memory mappings will be
+   dumped in a corefile.  They are described in the file
+   Documentation/filesystems/proc.txt, inside the Linux kernel
+   tree.  */
+
+enum filterflags
+  {
+    COREFILTER_ANON_PRIVATE = 1 << 0,
+    COREFILTER_ANON_SHARED = 1 << 1,
+    COREFILTER_MAPPED_PRIVATE = 1 << 2,
+    COREFILTER_MAPPED_SHARED = 1 << 3,
+    COREFILTER_ELF_HEADERS = 1 << 4,
+    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
+    COREFILTER_HUGETLB_SHARED = 1 << 6,
+  };
+
+extern int
+  linux_find_memory_regions_full (pid_t pid, enum filterflags filterflags,
+				  linux_find_memory_region_ftype *func,
+				  void *func_data);
+
 #endif /* NAT_LINUX_MAPS_H */
diff --git a/gdb/target.c b/gdb/target.c
index 2dd3116..d25cfd4 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -43,6 +43,7 @@ 
 #include "agent.h"
 #include "auxv.h"
 #include "target-debug.h"
+#include "target/target-utils.h"
 
 static void target_info (char *, int);
 
@@ -2973,9 +2974,6 @@  target_fileio_close_cleanup (void *opaque)
   target_fileio_close (fd, &target_errno);
 }
 
-typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
-				      ULONGEST offset, int *target_errno);
-
 /* Helper for target_fileio_read_alloc_1 to make it interruptible.  */
 
 static int
@@ -2996,57 +2994,6 @@  target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
    more information.  */
 
 static LONGEST
-read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
-	    int padding)
-{
-  size_t buf_alloc, buf_pos;
-  gdb_byte *buf;
-  LONGEST n;
-  int target_errno;
-
-  /* Start by reading up to 4K at a time.  The target will throttle
-     this number down if necessary.  */
-  buf_alloc = 4096;
-  buf = xmalloc (buf_alloc);
-  buf_pos = 0;
-  while (1)
-    {
-      n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
-		      buf_pos, &target_errno);
-      if (n <= 0)
-	{
-	  if (n < 0 || (n == 0 && buf_pos == 0))
-	    xfree (buf);
-	  else
-	    *buf_p = buf;
-	  if (n < 0)
-	    {
-	      /* An error occurred.  */
-	      return -1;
-	    }
-	  else
-	    {
-	      /* Read all there was.  */
-	      return buf_pos;
-	    }
-	}
-
-      buf_pos += n;
-
-      /* If the buffer is filling up, expand it.  */
-      if (buf_alloc < buf_pos * 2)
-	{
-	  buf_alloc *= 2;
-	  buf = xrealloc (buf, buf_alloc);
-	}
-    }
-}
-
-typedef LONGEST (read_stralloc_func_ftype) (struct inferior *inf,
-					    const char *filename,
-					    gdb_byte **buf_p, int padding);
-
-static LONGEST
 target_fileio_read_alloc_1 (struct inferior *inf, const char *filename,
 			    gdb_byte **buf_p, int padding)
 {
@@ -3073,41 +3020,7 @@  target_fileio_read_alloc (struct inferior *inf, const char *filename,
   return target_fileio_read_alloc_1 (inf, filename, buf_p, 0);
 }
 
-/* Helper for target_fileio_read_stralloc.  */
-
-static char *
-read_stralloc (struct inferior *inf, const char *filename,
-	       read_stralloc_func_ftype *func)
-{
-  gdb_byte *buffer;
-  char *bufstr;
-  LONGEST i, transferred;
-
-  transferred = func (inf, filename, &buffer, 1);
-  bufstr = (char *) buffer;
-
-  if (transferred < 0)
-    return NULL;
-
-  if (transferred == 0)
-    return xstrdup ("");
-
-  bufstr[transferred] = 0;
-
-  /* Check for embedded NUL bytes; but allow trailing NULs.  */
-  for (i = strlen (bufstr); i < transferred; i++)
-    if (bufstr[i] != 0)
-      {
-	warning (_("target file %s "
-		   "contained unexpected null characters"),
-		 filename);
-	break;
-      }
-
-  return bufstr;
-}
-
-/* See target.h.  */
+/* See target/target.h.  */
 
 char *
 target_fileio_read_stralloc (struct inferior *inf, const char *filename)
diff --git a/gdb/target.h b/gdb/target.h
index 32234f7..ae93a37 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -2033,16 +2033,6 @@  extern LONGEST target_fileio_read_alloc (struct inferior *inf,
 					 const char *filename,
 					 gdb_byte **buf_p);
 
-/* Read target file FILENAME, in the filesystem as seen by INF.  If
-   INF is NULL, use the filesystem seen by the debugger (GDB or, for
-   remote targets, the remote stub).  The result is NUL-terminated and
-   returned as a string, allocated using xmalloc.  If an error occurs
-   or the transfer is unsupported, NULL is returned.  Empty objects
-   are returned as allocated but empty strings.  A warning is issued
-   if the result contains any embedded NUL bytes.  */
-extern char *target_fileio_read_stralloc (struct inferior *inf,
-					  const char *filename);
-
 
 /* Tracepoint-related operations.  */
 
diff --git a/gdb/target/target-utils.c b/gdb/target/target-utils.c
index 4e8fae7..cdfa6e6 100644
--- a/gdb/target/target-utils.c
+++ b/gdb/target/target-utils.c
@@ -19,3 +19,82 @@ 
 
 #include "common-defs.h"
 #include "target/target-utils.h"
+
+LONGEST
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+	    int padding)
+{
+  size_t buf_alloc, buf_pos;
+  gdb_byte *buf;
+  LONGEST n;
+  int target_errno;
+
+  /* Start by reading up to 4K at a time.  The target will throttle
+     this number down if necessary.  */
+  buf_alloc = 4096;
+  buf = xmalloc (buf_alloc);
+  buf_pos = 0;
+  while (1)
+    {
+      n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+		      buf_pos, &target_errno);
+      if (n <= 0)
+	{
+	  if (n < 0 || (n == 0 && buf_pos == 0))
+	    xfree (buf);
+	  else
+	    *buf_p = buf;
+	  if (n < 0)
+	    {
+	      /* An error occurred.  */
+	      return -1;
+	    }
+	  else
+	    {
+	      /* Read all there was.  */
+	      return buf_pos;
+	    }
+	}
+
+      buf_pos += n;
+
+      /* If the buffer is filling up, expand it.  */
+      if (buf_alloc < buf_pos * 2)
+	{
+	  buf_alloc *= 2;
+	  buf = xrealloc (buf, buf_alloc);
+	}
+    }
+}
+
+char *
+read_stralloc (struct inferior *inf, const char *filename,
+	       read_stralloc_func_ftype *func)
+{
+  gdb_byte *buffer;
+  char *bufstr;
+  LONGEST i, transferred;
+
+  transferred = func (inf, filename, &buffer, 1);
+  bufstr = (char *) buffer;
+
+  if (transferred < 0)
+    return NULL;
+
+  if (transferred == 0)
+    return xstrdup ("");
+
+  bufstr[transferred] = 0;
+
+  /* Check for embedded NUL bytes; but allow trailing NULs.  */
+  for (i = strlen (bufstr); i < transferred; i++)
+    if (bufstr[i] != 0)
+      {
+	warning (_("target file %s "
+		   "contained unexpected null characters"),
+		 filename);
+	break;
+      }
+
+  return bufstr;
+}
diff --git a/gdb/target/target-utils.h b/gdb/target/target-utils.h
index 443ffc3..e8bf52a 100644
--- a/gdb/target/target-utils.h
+++ b/gdb/target/target-utils.h
@@ -20,4 +20,16 @@ 
 #ifndef TARGET_TARGET_UTILS_H
 #define TARGET_TARGET_UTILS_H
 
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+				      ULONGEST offset, int *target_errno);
+extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
+			   read_alloc_pread_ftype *pread_func, int padding);
+
+struct inferior;
+typedef LONGEST (read_stralloc_func_ftype) (struct inferior *inf,
+					    const char *filename,
+					    gdb_byte **buf_p, int padding);
+extern char *read_stralloc (struct inferior *inf, const char *filename,
+			    read_stralloc_func_ftype *func);
+
 #endif /* TARGET_TARGET_UTILS_H */
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 05ac758..f525bbd 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -72,4 +72,15 @@  extern void target_stop_and_wait (ptid_t ptid);
 
 extern void target_continue_no_signal (ptid_t ptid);
 
+/* Read target file FILENAME, in the filesystem as seen by INF.  If
+   INF is NULL, use the filesystem seen by the debugger (GDB or, for
+   remote targets, the remote stub).  The result is NUL-terminated and
+   returned as a string, allocated using xmalloc.  If an error occurs
+   or the transfer is unsupported, NULL is returned.  Empty objects
+   are returned as allocated but empty strings.  A warning is issued
+   if the result contains any embedded NUL bytes.  */
+struct inferior;
+extern char *target_fileio_read_stralloc (struct inferior *inf,
+					  const char *filename);
+
 #endif /* TARGET_COMMON_H */