Uniquefy gdb.threads/attach-into-signal.exp
[deliverable/binutils-gdb.git] / gdb / linux-tdep.c
index 5309016f6f21067b2b5a3c48a3f17a1edc6319b6..ff3ada78c6b98e550e1c10c96e4d9be0867fa265 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.  */
 
@@ -350,6 +395,286 @@ 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
@@ -773,41 +1098,23 @@ linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
     error (_("unable to handle request"));
 }
 
-/* A structure for passing information through
-   linux_find_memory_regions_full.  */
-
-struct linux_find_memory_regions_data
-{
-  /* The original callback.  */
-
-  find_memory_region_ftype func;
-
-  /* The original datum.  */
-
-  void *data;
-};
-
-/* A callback for linux_find_memory_regions that converts between the
-   "full"-style callback and find_memory_region_ftype.  */
-
-static int
-linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
-                                ULONGEST offset, ULONGEST inode,
-                                int read, int write, int exec, int modified,
-                                const char *filename, void *arg)
-{
-  struct linux_find_memory_regions_data *data = arg;
-
-  return data->func (vaddr, size, read, write, exec, modified, data->data);
-}
+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);
 
-/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB.  */
+/* List memory regions in the inferior for a corefile.  */
 
 static int
-linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
-                              linux_find_memory_region_ftype *func,
-                              void *func_data)
+linux_find_memory_regions_full (struct gdbarch *gdbarch,
+                               linux_find_memory_region_ftype *func,
+                               void *obfd)
 {
+  char mapsfilename[100];
+  char coredumpfilter_name[100];
+  char *data, *coredumpfilterdata;
   pid_t pid;
   /* Default dump behavior of coredump_filter (0x33), according to
      Documentation/filesystems/proc.txt from the Linux kernel
@@ -817,17 +1124,14 @@ linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
                                  | COREFILTER_ELF_HEADERS
                                  | COREFILTER_HUGETLB_PRIVATE);
 
-  /* We need to know the real target PID so
-     linux_find_memory_regions_full can access /proc.  */
+  /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
-    return -1;
+    return 1;
 
   pid = current_inferior ()->pid;
 
   if (use_coredump_filter)
     {
-      char coredumpfilter_name[100], *coredumpfilterdata;
-
       xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
                 "/proc/%d/coredump_filter", pid);
       coredumpfilterdata = target_fileio_read_stralloc (NULL,
@@ -839,7 +1143,172 @@ linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
        }
     }
 
-  return linux_find_memory_regions_full (pid, filterflags, func, func_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;
+
+      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)
+           func (addr, endaddr - addr, offset, inode,
+                 read, write, exec, 1, /* MODIFIED is true because we
+                                          want to dump the mapping.  */
+                 filename, obfd);
+       }
+
+      do_cleanups (cleanup);
+      return 0;
+    }
+
+  return 1;
+}
+
+/* A structure for passing information through
+   linux_find_memory_regions_full.  */
+
+struct linux_find_memory_regions_data
+{
+  /* The original callback.  */
+
+  find_memory_region_ftype func;
+
+  /* The original datum.  */
+
+  void *obfd;
+};
+
+/* A callback for linux_find_memory_regions that converts between the
+   "full"-style callback and find_memory_region_ftype.  */
+
+static int
+linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
+                                ULONGEST offset, ULONGEST inode,
+                                int read, int write, int exec, int modified,
+                                const char *filename, void *arg)
+{
+  struct linux_find_memory_regions_data *data = arg;
+
+  return data->func (vaddr, size, read, write, exec, modified, data->obfd);
 }
 
 /* A variant of linux_find_memory_regions_full that is suitable as the
@@ -847,15 +1316,16 @@ linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
 
 static int
 linux_find_memory_regions (struct gdbarch *gdbarch,
-                          find_memory_region_ftype func, void *func_data)
+                          find_memory_region_ftype func, void *obfd)
 {
   struct linux_find_memory_regions_data data;
 
   data.func = func;
-  data.data = func_data;
+  data.obfd = obfd;
 
-  return linux_find_memory_regions_gdb (gdbarch,
-                                       linux_find_memory_regions_thunk, &data);
+  return linux_find_memory_regions_full (gdbarch,
+                                        linux_find_memory_regions_thunk,
+                                        &data);
 }
 
 /* Determine which signal stopped execution.  */
@@ -1037,8 +1507,8 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
   pack_long (buf, long_type, 1);
   obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));
 
-  linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
-                                &mapping_data);
+  linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback,
+                                 &mapping_data);
 
   if (mapping_data.file_count != 0)
     {
This page took 0.030122 seconds and 4 git commands to generate.