gdb: clear regcaches at the start of regcaches selftest
[binutils-gdb.git] / gdb / linux-tdep.c
index fd4337f100d6f6af18e03de3c94177ab12b2ae44..0b2b032dc74280bbba1631a7488bfc0e4e1a1b63 100644 (file)
@@ -726,6 +726,25 @@ dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
   return dump_p;
 }
 
+/* As above, but return true only when we should dump the NT_FILE
+   entry.  */
+
+static int
+dump_note_entry_p (filter_flags filterflags, const struct smaps_vmflags *v,
+               int maybe_private_p, int mapping_anon_p, int mapping_file_p,
+               const char *filename, ULONGEST addr, ULONGEST offset)
+{
+  /* vDSO and vsyscall mappings will end up in the core file.  Don't
+     put them in the NT_FILE note.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 0;
+
+  /* Otherwise, any other file-based mapping should be placed in the
+     note.  */
+  return filename != nullptr;
+}
+
 /* Implement the "info proc" command.  */
 
 static void
@@ -1018,106 +1037,174 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
     }
 }
 
-/* Implement "info proc mappings" for a corefile.  */
+/* Implementation of `gdbarch_read_core_file_mappings', as defined in
+   gdbarch.h.
+   
+   This function reads the NT_FILE note (which BFD turns into the
+   section ".note.linuxcore.file").  The format of this note / section
+   is described as follows in the Linux kernel sources in
+   fs/binfmt_elf.c:
+   
+      long count     -- how many files are mapped
+      long page_size -- units for file_ofs
+      array of [COUNT] elements of
+       long start
+       long end
+       long file_ofs
+      followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
+      
+   CBFD is the BFD of the core file.
+
+   PRE_LOOP_CB is the callback function to invoke prior to starting
+   the loop which processes individual entries.  This callback will
+   only be executed after the note has been examined in enough
+   detail to verify that it's not malformed in some way.
+   
+   LOOP_CB is the callback function that will be executed once
+   for each mapping.  */
 
 static void
-linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args)
+linux_read_core_file_mappings (struct gdbarch *gdbarch,
+                              struct bfd *cbfd,
+                              gdb::function_view<void (ULONGEST count)>
+                                pre_loop_cb,
+                              gdb::function_view<void (int num,
+                                                       ULONGEST start,
+                                                       ULONGEST end,
+                                                       ULONGEST file_ofs,
+                                                       const char *filename,
+                                                       const void *other)>
+                                loop_cb)
 {
-  asection *section;
-  ULONGEST count, page_size;
-  unsigned char *descdata, *filenames, *descend;
-  size_t note_size;
-  unsigned int addr_size_bits, addr_size;
-  struct gdbarch *core_gdbarch = gdbarch_from_bfd (core_bfd);
-  /* We assume this for reading 64-bit core files.  */
+  /* Ensure that ULONGEST is big enough for reading 64-bit core files.  */
   gdb_static_assert (sizeof (ULONGEST) >= 8);
 
-  section = bfd_get_section_by_name (core_bfd, ".note.linuxcore.file");
-  if (section == NULL)
-    {
-      warning (_("unable to find mappings in core file"));
-      return;
-    }
+  /* It's not required that the NT_FILE note exists, so return silently
+     if it's not found.  Beyond this point though, we'll complain
+     if problems are found.  */
+  asection *section = bfd_get_section_by_name (cbfd, ".note.linuxcore.file");
+  if (section == nullptr)
+    return;
 
-  addr_size_bits = gdbarch_addr_bit (core_gdbarch);
-  addr_size = addr_size_bits / 8;
-  note_size = bfd_section_size (section);
+  unsigned int addr_size_bits = gdbarch_addr_bit (gdbarch);
+  unsigned int addr_size = addr_size_bits / 8;
+  size_t note_size = bfd_section_size (section);
 
   if (note_size < 2 * addr_size)
-    error (_("malformed core note - too short for header"));
+    {
+      warning (_("malformed core note - too short for header"));
+      return;
+    }
 
-  gdb::def_vector<unsigned char> contents (note_size);
+  gdb::def_vector<gdb_byte> contents (note_size);
   if (!bfd_get_section_contents (core_bfd, section, contents.data (),
                                 0, note_size))
-    error (_("could not get core note contents"));
+    {
+      warning (_("could not get core note contents"));
+      return;
+    }
 
-  descdata = contents.data ();
-  descend = descdata + note_size;
+  gdb_byte *descdata = contents.data ();
+  char *descend = (char *) descdata + note_size;
 
   if (descdata[note_size - 1] != '\0')
-    error (_("malformed note - does not end with \\0"));
+    {
+      warning (_("malformed note - does not end with \\0"));
+      return;
+    }
 
-  count = bfd_get (addr_size_bits, core_bfd, descdata);
+  ULONGEST count = bfd_get (addr_size_bits, core_bfd, descdata);
   descdata += addr_size;
 
-  page_size = bfd_get (addr_size_bits, core_bfd, descdata);
+  ULONGEST page_size = bfd_get (addr_size_bits, core_bfd, descdata);
   descdata += addr_size;
 
   if (note_size < 2 * addr_size + count * 3 * addr_size)
-    error (_("malformed note - too short for supplied file count"));
-
-  printf_filtered (_("Mapped address spaces:\n\n"));
-  if (gdbarch_addr_bit (gdbarch) == 32)
     {
-      printf_filtered ("\t%10s %10s %10s %10s %s\n",
-                      "Start Addr",
-                      "  End Addr",
-                      "      Size", "    Offset", "objfile");
-    }
-  else
-    {
-      printf_filtered ("  %18s %18s %10s %10s %s\n",
-                      "Start Addr",
-                      "  End Addr",
-                      "      Size", "    Offset", "objfile");
+      warning (_("malformed note - too short for supplied file count"));
+      return;
     }
 
-  filenames = descdata + count * 3 * addr_size;
-  while (--count > 0)
+  char *filenames = (char *) descdata + count * 3 * addr_size;
+
+  /* Make sure that the correct number of filenames exist.  Complain
+     if there aren't enough or are too many.  */
+  char *f = filenames;
+  for (int i = 0; i < count; i++)
     {
-      ULONGEST start, end, file_ofs;
+      if (f >= descend)
+        {
+         warning (_("malformed note - filename area is too small"));
+         return;
+       }
+      f += strnlen (f, descend - f) + 1;
+    }
+  /* Complain, but don't return early if the filename area is too big.  */
+  if (f != descend)
+    warning (_("malformed note - filename area is too big"));
 
-      if (filenames == descend)
-       error (_("malformed note - filenames end too early"));
+  pre_loop_cb (count);
 
-      start = bfd_get (addr_size_bits, core_bfd, descdata);
+  for (int i = 0; i < count; i++)
+    {
+      ULONGEST start = bfd_get (addr_size_bits, core_bfd, descdata);
       descdata += addr_size;
-      end = bfd_get (addr_size_bits, core_bfd, descdata);
+      ULONGEST end = bfd_get (addr_size_bits, core_bfd, descdata);
       descdata += addr_size;
-      file_ofs = bfd_get (addr_size_bits, core_bfd, descdata);
+      ULONGEST file_ofs
+        = bfd_get (addr_size_bits, core_bfd, descdata) * page_size;
       descdata += addr_size;
+      char * filename = filenames;
+      filenames += strlen ((char *) filenames) + 1;
 
-      file_ofs *= page_size;
-
-      if (gdbarch_addr_bit (gdbarch) == 32)
-       printf_filtered ("\t%10s %10s %10s %10s %s\n",
-                        paddress (gdbarch, start),
-                        paddress (gdbarch, end),
-                        hex_string (end - start),
-                        hex_string (file_ofs),
-                        filenames);
-      else
-       printf_filtered ("  %18s %18s %10s %10s %s\n",
-                        paddress (gdbarch, start),
-                        paddress (gdbarch, end),
-                        hex_string (end - start),
-                        hex_string (file_ofs),
-                        filenames);
-
-      filenames += 1 + strlen ((char *) filenames);
+      loop_cb (i, start, end, file_ofs, filename, nullptr);
     }
 }
 
+/* Implement "info proc mappings" for a corefile.  */
+
+static void
+linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args)
+{
+  linux_read_core_file_mappings (gdbarch, core_bfd,
+    [=] (ULONGEST count)
+      {
+       printf_filtered (_("Mapped address spaces:\n\n"));
+       if (gdbarch_addr_bit (gdbarch) == 32)
+         {
+           printf_filtered ("\t%10s %10s %10s %10s %s\n",
+                            "Start Addr",
+                            "  End Addr",
+                            "      Size", "    Offset", "objfile");
+         }
+       else
+         {
+           printf_filtered ("  %18s %18s %10s %10s %s\n",
+                            "Start Addr",
+                            "  End Addr",
+                            "      Size", "    Offset", "objfile");
+         }
+      },
+    [=] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
+         const char *filename, const void *other)
+      {
+       if (gdbarch_addr_bit (gdbarch) == 32)
+         printf_filtered ("\t%10s %10s %10s %10s %s\n",
+                          paddress (gdbarch, start),
+                          paddress (gdbarch, end),
+                          hex_string (end - start),
+                          hex_string (file_ofs),
+                          filename);
+       else
+         printf_filtered ("  %18s %18s %10s %10s %s\n",
+                          paddress (gdbarch, start),
+                          paddress (gdbarch, end),
+                          hex_string (end - start),
+                          hex_string (file_ofs),
+                          filename);
+      });
+}
+
 /* Implement "info proc" for a corefile.  */
 
 static void
@@ -1172,10 +1259,20 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
                                            const char *filename,
                                            void *data);
 
+typedef int linux_dump_mapping_p_ftype (filter_flags filterflags,
+                                       const struct smaps_vmflags *v,
+                                       int maybe_private_p,
+                                       int mapping_anon_p,
+                                       int mapping_file_p,
+                                       const char *filename,
+                                       ULONGEST addr,
+                                       ULONGEST offset);
+
 /* List memory regions in the inferior for a corefile.  */
 
 static int
 linux_find_memory_regions_full (struct gdbarch *gdbarch,
+                               linux_dump_mapping_p_ftype *should_dump_mapping_p,
                                linux_find_memory_region_ftype *func,
                                void *obfd)
 {
@@ -1326,9 +1423,10 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
            }
 
          if (has_anonymous)
-           should_dump_p = dump_mapping_p (filterflags, &v, priv,
-                                           mapping_anon_p, mapping_file_p,
-                                           filename, addr, offset);
+           should_dump_p = should_dump_mapping_p (filterflags, &v, priv,
+                                                  mapping_anon_p,
+                                                  mapping_file_p,
+                                                  filename, addr, offset);
          else
            {
              /* Older Linux kernels did not support the "Anonymous:" counter.
@@ -1392,6 +1490,7 @@ linux_find_memory_regions (struct gdbarch *gdbarch,
   data.obfd = obfd;
 
   return linux_find_memory_regions_full (gdbarch,
+                                        dump_mapping_p,
                                         linux_find_memory_regions_thunk,
                                         &data);
 }
@@ -1475,7 +1574,9 @@ 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_full (gdbarch, linux_make_mappings_callback,
+  linux_find_memory_regions_full (gdbarch, 
+                                 dump_note_entry_p,
+                                 linux_make_mappings_callback,
                                  &mapping_data);
 
   if (mapping_data.file_count != 0)
@@ -2472,6 +2573,7 @@ linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_info_proc (gdbarch, linux_info_proc);
   set_gdbarch_core_info_proc (gdbarch, linux_core_info_proc);
   set_gdbarch_core_xfer_siginfo (gdbarch, linux_core_xfer_siginfo);
+  set_gdbarch_read_core_file_mappings (gdbarch, linux_read_core_file_mappings);
   set_gdbarch_find_memory_regions (gdbarch, linux_find_memory_regions);
   set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes);
   set_gdbarch_has_shared_address_space (gdbarch,