Move linux_find_memory_regions_full & co.
authorJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 15 Jul 2015 15:37:27 +0000 (17:37 +0200)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 15 Jul 2015 15:40:38 +0000 (17:40 +0200)
This should be just a move with no changes.

gdb/ChangeLog
2015-07-15  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-07-15  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/ChangeLog
gdb/gdbserver/ChangeLog
gdb/gdbserver/target.c
gdb/linux-tdep.c
gdb/nat/linux-maps.c
gdb/nat/linux-maps.h
gdb/target.c
gdb/target.h
gdb/target/target-utils.c
gdb/target/target-utils.h
gdb/target/target.h

index a33a34579d13d89377f5f49f40939516586edd79..2f2ec28a619361f95fad86df8fcdfe2c69480d9f 100644 (file)
@@ -1,3 +1,35 @@
+2015-07-15  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.
+
 2015-07-15  Aleksandar Ristovski  <aristovski@qnx.com
            Jan Kratochvil  <jan.kratochvil@redhat.com>
 
index e269b970a3ba75f8cd25c582dde7cf5c7256145c..f4896ebe514e9aeb5ef23bf67660a28c61a30ad6 100644 (file)
@@ -1,3 +1,10 @@
+2015-07-15  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.
+
 2015-07-15  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * Makefile.in (OBS): Add gdb_regex.o.
index 14999e6eb6f444a88167354cae9598bde4cc0b0f..5525b1f8f48d352b6fb104d4a9bacadd712671fe 100644 (file)
@@ -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);
+}
index 982599e397262101bc3082724ee696f9b7e56ab7..5309016f6f21067b2b5a3c48a3f17a1edc6319b6 100644 (file)
 #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.  */
 
index 01c8836f6b726e7c450b4dc6b92e4a3b60e3e2dd..ef3da6aa2d282dd49ec097cde3a4db0a514228a2 100644 (file)
 
 #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;
+}
index 2cff321328286819bd2cd903befc86b134fd6a65..7e10d6586599e0ca4aa56363ad1c627530efa658 100644 (file)
 #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 */
index 2dd3116f13e098e9a3a806a2c2baf15a14158d38..d25cfd4d046ee26fbe71b26d1087bed96fe78e9e 100644 (file)
@@ -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
@@ -2995,57 +2993,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
    target_fileio_read_alloc; see the declaration of that function for
    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)
index 32234f7bba3fa8c9b2fa31ef25c513919df86e9c..ae93a37d0fdff74bf9a9e0aec201c25c3e92e619 100644 (file)
@@ -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.  */
 
index 4e8fae7bb5b119171f862040b4b2d7f4f87ca9d2..cdfa6e698036162c67833b1126a7d26757fd2479 100644 (file)
 
 #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;
+}
index 443ffc3ddad02e11a14dca8121e7926bde9cfdac..e8bf52ac4f6d75b10d6f375bc4cedf4166b7c25c 100644 (file)
 #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 */
index 6ee0feeec0b47f37ec5c4233027daa3882665aaa..4c85fe019ede5926a9c30c3fb0cb714a89d7ad2d 100644 (file)
@@ -70,4 +70,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 */