elf/x86: Issue an error on discarded output .plt section
[binutils-gdb.git] / gdb / corelow.c
index 367f54cd53680072c3e7ecbb139a39da8abb7745..10942e6af01fe2859ec175922fd52dfed70ef226 100644 (file)
@@ -1,6 +1,6 @@
 /* Core dump and executable file functions below target vector, for GDB.
 
-   Copyright (C) 1986-2020 Free Software Foundation, Inc.
+   Copyright (C) 1986-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -47,7 +47,9 @@
 #include "build-id.h"
 #include "gdbsupport/pathstuff.h"
 #include <unordered_map>
+#include <unordered_set>
 #include "gdbcmd.h"
+#include "xml-tdesc.h"
 
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
@@ -66,7 +68,6 @@ class core_target final : public process_stratum_target
 {
 public:
   core_target ();
-  ~core_target () override;
 
   const target_info &info () const override
   { return core_target_info; }
@@ -125,15 +126,27 @@ private: /* per-core data */
      shared library bfds.  The core bfd sections are an implementation
      detail of the core target, just like ptrace is for unix child
      targets.  */
-  target_section_table m_core_section_table {};
+  target_section_table m_core_section_table;
 
   /* File-backed address space mappings: some core files include
      information about memory mapped files.  */
-  target_section_table m_core_file_mappings {};
+  target_section_table m_core_file_mappings;
+
+  /* Unavailable mappings.  These correspond to pathnames which either
+     weren't found or could not be opened.  Knowing these addresses can
+     still be useful.  */
+  std::vector<mem_range> m_core_unavailable_mappings;
 
   /* Build m_core_file_mappings.  Called from the constructor.  */
   void build_file_mappings ();
 
+  /* Helper method for xfer_partial.  */
+  enum target_xfer_status xfer_memory_via_mappings (gdb_byte *readbuf,
+                                                   const gdb_byte *writebuf,
+                                                   ULONGEST offset,
+                                                   ULONGEST len,
+                                                   ULONGEST *xfered_len);
+
   /* FIXME: kettenis/20031023: Eventually this field should
      disappear.  */
   struct gdbarch *m_core_gdbarch = NULL;
@@ -141,29 +154,33 @@ private: /* per-core data */
 
 core_target::core_target ()
 {
+  /* Find a first arch based on the BFD.  We need the initial gdbarch so
+     we can setup the hooks to find a target description.  */
   m_core_gdbarch = gdbarch_from_bfd (core_bfd);
 
+  /* If the arch is able to read a target description from the core, it
+     could yield a more specific gdbarch.  */
+  const struct target_desc *tdesc = read_description ();
+
+  if (tdesc != nullptr)
+    {
+      struct gdbarch_info info;
+      info.abfd = core_bfd;
+      info.target_desc = tdesc;
+      m_core_gdbarch = gdbarch_find_by_info (info);
+    }
+
   if (!m_core_gdbarch
       || !gdbarch_iterate_over_regset_sections_p (m_core_gdbarch))
     error (_("\"%s\": Core file format not supported"),
           bfd_get_filename (core_bfd));
 
   /* Find the data section */
-  if (build_section_table (core_bfd,
-                          &m_core_section_table.sections,
-                          &m_core_section_table.sections_end))
-    error (_("\"%s\": Can't find sections: %s"),
-          bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
+  m_core_section_table = build_section_table (core_bfd);
 
   build_file_mappings ();
 }
 
-core_target::~core_target ()
-{
-  xfree (m_core_section_table.sections);
-  xfree (m_core_file_mappings.sections);
-}
-
 /* Construct the target_section_table for file-backed mappings if
    they exist.
 
@@ -182,24 +199,22 @@ void
 core_target::build_file_mappings ()
 {
   std::unordered_map<std::string, struct bfd *> bfd_map;
+  std::unordered_set<std::string> unavailable_paths;
 
   /* See linux_read_core_file_mappings() in linux-tdep.c for an example
      read_core_file_mappings method.  */
   gdbarch_read_core_file_mappings (m_core_gdbarch, core_bfd,
 
     /* After determining the number of mappings, read_core_file_mappings
-       will invoke this lambda which allocates target_section storage for
-       the mappings.  */
-    [&] (ULONGEST count)
+       will invoke this lambda.  */
+    [&] (ULONGEST)
       {
-       m_core_file_mappings.sections = XNEWVEC (struct target_section, count);
-       m_core_file_mappings.sections_end = m_core_file_mappings.sections;
       },
 
     /* read_core_file_mappings will invoke this lambda for each mapping
        that it finds.  */
     [&] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
-         const char *filename, const void *other)
+        const char *filename, const bfd_build_id *build_id)
       {
        /* Architecture-specific read_core_mapping methods are expected to
           weed out non-file-backed mappings.  */
@@ -216,17 +231,21 @@ core_target::build_file_mappings ()
              = exec_file_find (filename, NULL);
            if (expanded_fname == nullptr)
              {
-               warning (_("Can't open file %s during file-backed mapping "
-                          "note processing"),
-                        expanded_fname.get ());
+               m_core_unavailable_mappings.emplace_back (start, end - start);
+               /* Print just one warning per path.  */
+               if (unavailable_paths.insert (filename).second)
+                 warning (_("Can't open file %s during file-backed mapping "
+                            "note processing"),
+                          filename);
                return;
              }
 
            bfd = bfd_map[filename] = bfd_openr (expanded_fname.get (),
-                                                "binary");
+                                                "binary");
 
            if (bfd == nullptr || !bfd_check_format (bfd, bfd_object))
              {
+               m_core_unavailable_mappings.emplace_back (start, end - start);
                /* If we get here, there's a good chance that it's due to
                   an internal error.  We issue a warning instead of an
                   internal error because of the possibility that the
@@ -262,15 +281,11 @@ core_target::build_file_mappings ()
        bfd_set_section_alignment (sec, 2);
 
        /* Set target_section fields.  */
-       struct target_section *ts = m_core_file_mappings.sections_end++;
-       ts->addr = start;
-       ts->endaddr = end;
-       ts->owner = nullptr;
-       ts->the_bfd_section = sec;
+       m_core_file_mappings.emplace_back (start, end, sec);
       });
-}
 
-static void add_to_thread_list (bfd *, asection *, void *);
+  normalize_mem_ranges (&m_core_unavailable_mappings);
+}
 
 /* An arbitrary identifier for the core inferior.  */
 #define CORELOW_PID 1
@@ -287,7 +302,7 @@ core_target::close ()
       exit_inferior_silent (current_inferior ());
 
       /* Clear out solib state while the bfd is still open.  See
-         comments in clear_solib in solib.c.  */
+        comments in clear_solib in solib.c.  */
       clear_solib ();
 
       current_program_space->cbfd.reset (nullptr);
@@ -302,11 +317,10 @@ core_target::close ()
    extract the list of threads in a core file.  */
 
 static void
-add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg)
+add_to_thread_list (asection *asect, asection *reg_sect)
 {
   int core_tid;
   int pid, lwpid;
-  asection *reg_sect = (asection *) reg_sect_arg;
   bool fake_pid_p = false;
   struct inferior *inf;
 
@@ -414,7 +428,8 @@ core_target_open (const char *arg, int from_tty)
     }
 
   gdb::unique_xmalloc_ptr<char> filename (tilde_expand (arg));
-  if (!IS_ABSOLUTE_PATH (filename.get ()))
+  if (strlen (filename.get ()) != 0
+      && !IS_ABSOLUTE_PATH (filename.get ()))
     filename = gdb_abspath (filename.get ());
 
   flags = O_BINARY | O_LARGEFILE;
@@ -422,7 +437,7 @@ core_target_open (const char *arg, int from_tty)
     flags |= O_RDWR;
   else
     flags |= O_RDONLY;
-  scratch_chan = gdb_open_cloexec (filename.get (), flags, 0);
+  scratch_chan = gdb_open_cloexec (filename.get (), flags, 0).release ();
   if (scratch_chan < 0)
     perror_with_name (filename.get ());
 
@@ -436,8 +451,8 @@ core_target_open (const char *arg, int from_tty)
     {
       /* Do it after the err msg */
       /* FIXME: should be checking for errors from bfd_close (for one
-         thing, on error it does not free all the storage associated
-         with the bfd).  */
+        thing, on error it does not free all the storage associated
+        with the bfd).  */
       error (_("\"%s\" is not a core dump: %s"),
             filename.get (), bfd_errmsg (bfd_get_error ()));
     }
@@ -455,10 +470,10 @@ core_target_open (const char *arg, int from_tty)
      core file.  We don't do this unconditionally since an exec file
      typically contains more information that helps us determine the
      architecture than a core file.  */
-  if (!exec_bfd)
+  if (!current_program_space->exec_bfd ())
     set_gdbarch_from_file (core_bfd);
 
-  push_target (std::move (target_holder));
+  current_inferior ()->push_target (std::move (target_holder));
 
   switch_to_no_thread ();
 
@@ -473,8 +488,9 @@ core_target_open (const char *arg, int from_tty)
   /* Build up thread list from BFD sections, and possibly set the
      current thread to the .reg/NN section matching the .reg
      section.  */
-  bfd_map_over_sections (core_bfd, add_to_thread_list,
-                        bfd_get_section_by_name (core_bfd, ".reg"));
+  asection *reg_sect = bfd_get_section_by_name (core_bfd, ".reg");
+  for (asection *sect : gdb_bfd_sections (core_bfd))
+    add_to_thread_list (sect, reg_sect);
 
   if (inferior_ptid == null_ptid)
     {
@@ -495,10 +511,10 @@ core_target_open (const char *arg, int from_tty)
       switch_to_thread (thread);
     }
 
-  if (exec_bfd == nullptr)
+  if (current_program_space->exec_bfd () == nullptr)
     locate_exec_from_corefile_build_id (core_bfd, from_tty);
 
-  post_create_inferior (target, from_tty);
+  post_create_inferior (from_tty);
 
   /* Now go through the target stack looking for threads since there
      may be a thread_stratum target loaded on top of target core by
@@ -579,7 +595,7 @@ core_target::detach (inferior *inf, int from_tty)
   /* Note that 'this' is dangling after this call.  unpush_target
      closes the target, and our close implementation deletes
      'this'.  */
-  unpush_target (this);
+  inf->unpush_target (this);
 
   /* Clear the register cache and the frame cache.  */
   registers_changed ();
@@ -728,6 +744,56 @@ core_target::files_info ()
   print_section_info (&m_core_section_table, core_bfd);
 }
 \f
+/* Helper method for core_target::xfer_partial.  */
+
+enum target_xfer_status
+core_target::xfer_memory_via_mappings (gdb_byte *readbuf,
+                                      const gdb_byte *writebuf,
+                                      ULONGEST offset, ULONGEST len,
+                                      ULONGEST *xfered_len)
+{
+  enum target_xfer_status xfer_status;
+
+  xfer_status = (section_table_xfer_memory_partial
+                  (readbuf, writebuf,
+                   offset, len, xfered_len,
+                   m_core_file_mappings));
+
+  if (xfer_status == TARGET_XFER_OK || m_core_unavailable_mappings.empty ())
+    return xfer_status;
+
+  /* There are instances - e.g. when debugging within a docker
+     container using the AUFS storage driver - where the pathnames
+     obtained from the note section are incorrect.  Despite the path
+     being wrong, just knowing the start and end addresses of the
+     mappings is still useful; we can attempt an access of the file
+     stratum constrained to the address ranges corresponding to the
+     unavailable mappings.  */
+
+  ULONGEST memaddr = offset;
+  ULONGEST memend = offset + len;
+
+  for (const auto &mr : m_core_unavailable_mappings)
+    {
+      if (address_in_mem_range (memaddr, &mr))
+       {
+         if (!address_in_mem_range (memend, &mr))
+           len = mr.start + mr.length - memaddr;
+
+         xfer_status = this->beneath ()->xfer_partial (TARGET_OBJECT_MEMORY,
+                                                       NULL,
+                                                       readbuf,
+                                                       writebuf,
+                                                       offset,
+                                                       len,
+                                                       xfered_len);
+         break;
+       }
+    }
+
+  return xfer_status;
+}
+
 enum target_xfer_status
 core_target::xfer_partial (enum target_object object, const char *annex,
                           gdb_byte *readbuf, const gdb_byte *writebuf,
@@ -749,8 +815,7 @@ core_target::xfer_partial (enum target_object object, const char *annex,
        xfer_status = section_table_xfer_memory_partial
                        (readbuf, writebuf,
                         offset, len, xfered_len,
-                        m_core_section_table.sections,
-                        m_core_section_table.sections_end,
+                        m_core_section_table,
                         has_contents_cb);
        if (xfer_status == TARGET_XFER_OK)
          return TARGET_XFER_OK;
@@ -759,13 +824,16 @@ core_target::xfer_partial (enum target_object object, const char *annex,
           core file provided mappings (e.g. from .note.linuxcore.file
           or the like) as this should provide a more accurate
           result.  If not, check the stratum beneath us, which should
-          be the file stratum.  */
-       if (m_core_file_mappings.sections != nullptr)
-         xfer_status = section_table_xfer_memory_partial
-                         (readbuf, writebuf,
-                          offset, len, xfered_len,
-                          m_core_file_mappings.sections,
-                          m_core_file_mappings.sections_end);
+          be the file stratum.
+
+          We also check unavailable mappings due to Docker/AUFS driver
+          issues.  */
+       if (!m_core_file_mappings.empty ()
+           || !m_core_unavailable_mappings.empty ())
+         {
+           xfer_status = xfer_memory_via_mappings (readbuf, writebuf, offset,
+                                                   len, xfered_len);
+         }
        else
          xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf,
                                                        writebuf, offset, len,
@@ -782,8 +850,7 @@ core_target::xfer_partial (enum target_object object, const char *annex,
        xfer_status = section_table_xfer_memory_partial
                        (readbuf, writebuf,
                         offset, len, xfered_len,
-                        m_core_section_table.sections,
-                        m_core_section_table.sections_end,
+                        m_core_section_table,
                         no_contents_cb);
 
        return xfer_status;
@@ -949,6 +1016,29 @@ core_target::thread_alive (ptid_t ptid)
 const struct target_desc *
 core_target::read_description ()
 {
+  /* If the core file contains a target description note then we will use
+     that in preference to anything else.  */
+  bfd_size_type tdesc_note_size = 0;
+  struct bfd_section *tdesc_note_section
+    = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
+  if (tdesc_note_section != nullptr)
+    tdesc_note_size = bfd_section_size (tdesc_note_section);
+  if (tdesc_note_size > 0)
+    {
+      gdb::char_vector contents (tdesc_note_size + 1);
+      if (bfd_get_section_contents (core_bfd, tdesc_note_section,
+                                   contents.data (), (file_ptr) 0,
+                                   tdesc_note_size))
+       {
+         /* Ensure we have a null terminator.  */
+         contents[tdesc_note_size] = '\0';
+         const struct target_desc *result
+           = string_read_description_xml (contents.data ());
+         if (result != nullptr)
+           return result;
+       }
+    }
+
   if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
     {
       const struct target_desc *result;
@@ -1048,7 +1138,7 @@ get_current_core_target ()
 void
 core_target::info_proc_mappings (struct gdbarch *gdbarch)
 {
-  if (m_core_file_mappings.sections != m_core_file_mappings.sections_end)
+  if (!m_core_file_mappings.empty ())
     {
       printf_filtered (_("Mapped address spaces:\n\n"));
       if (gdbarch_addr_bit (gdbarch) == 32)
@@ -1067,14 +1157,12 @@ core_target::info_proc_mappings (struct gdbarch *gdbarch)
        }
     }
 
-  for (const struct target_section *tsp = m_core_file_mappings.sections;
-       tsp < m_core_file_mappings.sections_end;
-       tsp++)
+  for (const target_section &tsp : m_core_file_mappings)
     {
-      ULONGEST start = tsp->addr;
-      ULONGEST end = tsp->endaddr;
-      ULONGEST file_ofs = tsp->the_bfd_section->filepos;
-      const char *filename = bfd_get_filename (tsp->the_bfd_section->owner);
+      ULONGEST start = tsp.addr;
+      ULONGEST end = tsp.endaddr;
+      ULONGEST file_ofs = tsp.the_bfd_section->filepos;
+      const char *filename = bfd_get_filename (tsp.the_bfd_section->owner);
 
       if (gdbarch_addr_bit (gdbarch) == 32)
        printf_filtered ("\t%10s %10s %10s %10s %s\n",
@@ -1118,7 +1206,7 @@ _initialize_corelow ()
 {
   add_target (core_target_info, core_target_open, filename_completer);
   add_cmd ("core-file-backed-mappings", class_maintenance,
-           maintenance_print_core_file_backed_mappings,
+          maintenance_print_core_file_backed_mappings,
           _("Print core file's file-backed mappings."),
           &maintenanceprintlist);
 }