]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/gdb_bfd.c
Fix thinko in linker documentation.
[thirdparty/binutils-gdb.git] / gdb / gdb_bfd.c
index ee2953117b330705d3fe1c0259e16aa42e4745d7..5c6bbef551d94376b9fb27e1f69ba5298cdcb48a 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions for BFD wrappers used by GDB.
 
-   Copyright (C) 2011-2015 Free Software Foundation, Inc.
+   Copyright (C) 2011-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -22,8 +22,8 @@
 #include "ui-out.h"
 #include "gdbcmd.h"
 #include "hashtab.h"
-#include "filestuff.h"
-#include "vec.h"
+#include "common/filestuff.h"
+#include "common/vec.h"
 #ifdef HAVE_MMAP
 #include <sys/mman.h>
 #ifndef MAP_FAILED
@@ -34,9 +34,6 @@
 #include "gdb/fileio.h"
 #include "inferior.h"
 
-typedef bfd *bfdp;
-DEF_VEC_P (bfdp);
-
 /* An object of this type is stored in the section's user data when
    mapping a section.  */
 
@@ -63,8 +60,34 @@ static htab_t all_bfds;
 
 struct gdb_bfd_data
 {
+  gdb_bfd_data (bfd *abfd)
+    : mtime (bfd_get_mtime (abfd)),
+      size (bfd_get_size (abfd)),
+      relocation_computed (0),
+      needs_relocations (0),
+      crc_computed (0)
+  {
+    struct stat buf;
+
+    if (bfd_stat (abfd, &buf) == 0)
+      {
+       inode = buf.st_ino;
+       device_id = buf.st_dev;
+      }
+    else
+      {
+       /* The stat failed.  */
+       inode = 0;
+       device_id = 0;
+      }
+  }
+
+  ~gdb_bfd_data ()
+  {
+  }
+
   /* The reference count.  */
-  int refc;
+  int refc = 1;
 
   /* The mtime of the BFD at the point the cache entry was made.  */
   time_t mtime;
@@ -89,17 +112,17 @@ struct gdb_bfd_data
   unsigned int crc_computed : 1;
 
   /* The file's CRC.  */
-  unsigned long crc;
+  unsigned long crc = 0;
 
   /* If the BFD comes from an archive, this points to the archive's
      BFD.  Otherwise, this is NULL.  */
-  bfd *archive_bfd;
+  bfd *archive_bfd = nullptr;
 
   /* Table of all the bfds this bfd has included.  */
-  VEC (bfdp) *included_bfds;
+  std::vector<gdb_bfd_ref_ptr> included_bfds;
 
   /* The registry.  */
-  REGISTRY_FIELDS;
+  REGISTRY_FIELDS = {};
 };
 
 #define GDB_BFD_DATA_ACCESSOR(ABFD) \
@@ -111,6 +134,27 @@ DEFINE_REGISTRY (bfd, GDB_BFD_DATA_ACCESSOR)
 
 static htab_t gdb_bfd_cache;
 
+/* When true gdb will reuse an existing bfd object if the filename,
+   modification time, and file size all match.  */
+
+static int bfd_sharing = 1;
+static void
+show_bfd_sharing  (struct ui_file *file, int from_tty,
+                  struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("BFD sharing is %s.\n"), value);
+}
+
+/* When non-zero debugging of the bfd caches is enabled.  */
+
+static unsigned int debug_bfd_cache;
+static void
+show_bfd_cache_debug (struct ui_file *file, int from_tty,
+                     struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("BFD cache debugging is %s.\n"), value);
+}
+
 /* The type of an object being looked up in gdb_bfd_cache.  We use
    htab's capability of storing one kind of object (BFD in this case)
    and using a different sort of object for searching.  */
@@ -134,7 +178,7 @@ struct gdb_bfd_cache_search
 static hashval_t
 hash_bfd (const void *b)
 {
-  const bfd *abfd = b;
+  const bfd *abfd = (const struct bfd *) b;
 
   /* It is simplest to just hash the filename.  */
   return htab_hash_string (bfd_get_filename (abfd));
@@ -146,9 +190,10 @@ hash_bfd (const void *b)
 static int
 eq_bfd (const void *a, const void *b)
 {
-  const bfd *abfd = a;
-  const struct gdb_bfd_cache_search *s = b;
-  struct gdb_bfd_data *gdata = bfd_usrdata (abfd);
+  const bfd *abfd = (const struct bfd *) a;
+  const struct gdb_bfd_cache_search *s
+    = (const struct gdb_bfd_cache_search *) b;
+  struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
 
   return (gdata->mtime == s->mtime
          && gdata->size == s->size
@@ -240,10 +285,11 @@ gdb_bfd_iovec_fileio_open (struct bfd *abfd, void *inferior)
 
   gdb_assert (is_target_filename (filename));
 
-  fd = target_fileio_open ((struct inferior *) inferior,
-                          filename + strlen (TARGET_SYSROOT_PREFIX),
-                          FILEIO_O_RDONLY, 0,
-                          &target_errno);
+  fd = target_fileio_open_warn_if_slow ((struct inferior *) inferior,
+                                       filename
+                                       + strlen (TARGET_SYSROOT_PREFIX),
+                                       FILEIO_O_RDONLY, 0,
+                                       &target_errno);
   if (fd == -1)
     {
       errno = fileio_errno_to_host (target_errno);
@@ -270,6 +316,8 @@ gdb_bfd_iovec_fileio_pread (struct bfd *abfd, void *stream, void *buf,
   pos = 0;
   while (nbytes > pos)
     {
+      QUIT;
+
       bytes = target_fileio_pread (fd, (gdb_byte *) buf + pos,
                                   nbytes - pos, offset + pos,
                                   &target_errno);
@@ -331,7 +379,7 @@ gdb_bfd_iovec_fileio_fstat (struct bfd *abfd, void *stream,
 
 /* See gdb_bfd.h.  */
 
-struct bfd *
+gdb_bfd_ref_ptr
 gdb_bfd_open (const char *name, const char *target, int fd)
 {
   hashval_t hash;
@@ -393,24 +441,36 @@ gdb_bfd_open (const char *name, const char *target, int fd)
   /* Note that we cannot use htab_find_slot_with_hash here, because
      opening the BFD may fail; and this would violate hashtab
      invariants.  */
-  abfd = htab_find_with_hash (gdb_bfd_cache, &search, hash);
-  if (abfd != NULL)
+  abfd = (struct bfd *) htab_find_with_hash (gdb_bfd_cache, &search, hash);
+  if (bfd_sharing && abfd != NULL)
     {
+      if (debug_bfd_cache)
+       fprintf_unfiltered (gdb_stdlog,
+                           "Reusing cached bfd %s for %s\n",
+                           host_address_to_string (abfd),
+                           bfd_get_filename (abfd));
       close (fd);
-      gdb_bfd_ref (abfd);
-      return abfd;
+      return gdb_bfd_ref_ptr::new_reference (abfd);
     }
 
   abfd = bfd_fopen (name, target, FOPEN_RB, fd);
   if (abfd == NULL)
     return NULL;
 
-  slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT);
-  gdb_assert (!*slot);
-  *slot = abfd;
+  if (debug_bfd_cache)
+    fprintf_unfiltered (gdb_stdlog,
+                       "Creating new bfd %s for %s\n",
+                       host_address_to_string (abfd),
+                       bfd_get_filename (abfd));
 
-  gdb_bfd_ref (abfd);
-  return abfd;
+  if (bfd_sharing)
+    {
+      slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT);
+      gdb_assert (!*slot);
+      *slot = abfd;
+    }
+
+  return gdb_bfd_ref_ptr::new_reference (abfd);
 }
 
 /* A helper function that releases any section data attached to the
@@ -419,7 +479,8 @@ gdb_bfd_open (const char *name, const char *target, int fd)
 static void
 free_one_bfd_section (bfd *abfd, asection *sectp, void *ignore)
 {
-  struct gdb_bfd_section_data *sect = bfd_get_section_userdata (abfd, sectp);
+  struct gdb_bfd_section_data *sect
+    = (struct gdb_bfd_section_data *) bfd_get_section_userdata (abfd, sectp);
 
   if (sect != NULL && sect->data != NULL)
     {
@@ -461,14 +522,19 @@ gdb_bfd_close_or_warn (struct bfd *abfd)
 void
 gdb_bfd_ref (struct bfd *abfd)
 {
-  struct stat buf;
   struct gdb_bfd_data *gdata;
   void **slot;
 
   if (abfd == NULL)
     return;
 
-  gdata = bfd_usrdata (abfd);
+  gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
+
+  if (debug_bfd_cache)
+    fprintf_unfiltered (gdb_stdlog,
+                       "Increase reference count on bfd %s (%s)\n",
+                       host_address_to_string (abfd),
+                       bfd_get_filename (abfd));
 
   if (gdata != NULL)
     {
@@ -479,24 +545,8 @@ gdb_bfd_ref (struct bfd *abfd)
   /* Ask BFD to decompress sections in bfd_get_full_section_contents.  */
   abfd->flags |= BFD_DECOMPRESS;
 
-  gdata = bfd_zalloc (abfd, sizeof (struct gdb_bfd_data));
-  gdata->refc = 1;
-  gdata->mtime = bfd_get_mtime (abfd);
-  gdata->size = bfd_get_size (abfd);
-  gdata->archive_bfd = NULL;
-  if (bfd_stat (abfd, &buf) == 0)
-    {
-      gdata->inode = buf.st_ino;
-      gdata->device_id = buf.st_dev;
-    }
-  else
-    {
-      /* The stat failed.  */
-      gdata->inode = 0;
-      gdata->device_id = 0;
-    }
+  gdata = new gdb_bfd_data (abfd);
   bfd_usrdata (abfd) = gdata;
-
   bfd_alloc_data (abfd);
 
   /* This is the first we've seen it, so add it to the hash table.  */
@@ -510,20 +560,32 @@ gdb_bfd_ref (struct bfd *abfd)
 void
 gdb_bfd_unref (struct bfd *abfd)
 {
-  int ix;
   struct gdb_bfd_data *gdata;
   struct gdb_bfd_cache_search search;
-  bfd *archive_bfd, *included_bfd;
+  bfd *archive_bfd;
 
   if (abfd == NULL)
     return;
 
-  gdata = bfd_usrdata (abfd);
+  gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
   gdb_assert (gdata->refc >= 1);
 
   gdata->refc -= 1;
   if (gdata->refc > 0)
-    return;
+    {
+      if (debug_bfd_cache)
+       fprintf_unfiltered (gdb_stdlog,
+                           "Decrease reference count on bfd %s (%s)\n",
+                           host_address_to_string (abfd),
+                           bfd_get_filename (abfd));
+      return;
+    }
+
+  if (debug_bfd_cache)
+    fprintf_unfiltered (gdb_stdlog,
+                       "Delete final reference count on bfd %s (%s)\n",
+                       host_address_to_string (abfd),
+                       bfd_get_filename (abfd));
 
   archive_bfd = gdata->archive_bfd;
   search.filename = bfd_get_filename (abfd);
@@ -544,13 +606,8 @@ gdb_bfd_unref (struct bfd *abfd)
        htab_clear_slot (gdb_bfd_cache, slot);
     }
 
-  for (ix = 0;
-       VEC_iterate (bfdp, gdata->included_bfds, ix, included_bfd);
-       ++ix)
-    gdb_bfd_unref (included_bfd);
-  VEC_free (bfdp, gdata->included_bfds);
-
   bfd_free_data (abfd);
+  delete gdata;
   bfd_usrdata (abfd) = NULL;  /* Paranoia.  */
 
   htab_remove_elt (all_bfds, abfd);
@@ -569,11 +626,13 @@ get_section_descriptor (asection *section)
 {
   struct gdb_bfd_section_data *result;
 
-  result = bfd_get_section_userdata (section->owner, section);
+  result = ((struct gdb_bfd_section_data *)
+           bfd_get_section_userdata (section->owner, section));
 
   if (result == NULL)
     {
-      result = bfd_zalloc (section->owner, sizeof (*result));
+      result = ((struct gdb_bfd_section_data *)
+               bfd_zalloc (section->owner, sizeof (*result)));
       bfd_set_section_userdata (section->owner, section, result);
     }
 
@@ -643,15 +702,21 @@ gdb_bfd_map_section (asection *sectp, bfd_size_type *size)
 
   data = NULL;
   if (!bfd_get_full_section_contents (abfd, sectp, &data))
-    error (_("Can't read data for section '%s' in file '%s'"),
-          bfd_get_section_name (abfd, sectp),
-          bfd_get_filename (abfd));
+    {
+      warning (_("Can't read data for section '%s' in file '%s'"),
+              bfd_get_section_name (abfd, sectp),
+              bfd_get_filename (abfd));
+      /* Set size to 0 to prevent further attempts to read the invalid
+        section.  */
+      *size = 0;
+      return (const gdb_byte *) NULL;
+    }
   descriptor->data = data;
 
  done:
   gdb_assert (descriptor->data != NULL);
   *size = descriptor->size;
-  return descriptor->data;
+  return (const gdb_byte *) descriptor->data;
 }
 
 /* Return 32-bit CRC for ABFD.  If successful store it to *FILE_CRC_RETURN and
@@ -696,7 +761,7 @@ get_file_crc (bfd *abfd, unsigned long *file_crc_return)
 int
 gdb_bfd_crc (struct bfd *abfd, unsigned long *crc_out)
 {
-  struct gdb_bfd_data *gdata = bfd_usrdata (abfd);
+  struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
 
   if (!gdata->crc_computed)
     gdata->crc_computed = get_file_crc (abfd, &gdata->crc);
@@ -710,47 +775,38 @@ gdb_bfd_crc (struct bfd *abfd, unsigned long *crc_out)
 
 /* See gdb_bfd.h.  */
 
-bfd *
+gdb_bfd_ref_ptr
 gdb_bfd_fopen (const char *filename, const char *target, const char *mode,
               int fd)
 {
   bfd *result = bfd_fopen (filename, target, mode, fd);
 
-  if (result)
-    gdb_bfd_ref (result);
-
-  return result;
+  return gdb_bfd_ref_ptr::new_reference (result);
 }
 
 /* See gdb_bfd.h.  */
 
-bfd *
+gdb_bfd_ref_ptr
 gdb_bfd_openr (const char *filename, const char *target)
 {
   bfd *result = bfd_openr (filename, target);
 
-  if (result)
-    gdb_bfd_ref (result);
-
-  return result;
+  return gdb_bfd_ref_ptr::new_reference (result);
 }
 
 /* See gdb_bfd.h.  */
 
-bfd *
+gdb_bfd_ref_ptr
 gdb_bfd_openw (const char *filename, const char *target)
 {
   bfd *result = bfd_openw (filename, target);
 
-  if (result)
-    gdb_bfd_ref (result);
-
-  return result;
+  return gdb_bfd_ref_ptr::new_reference (result);
 }
 
 /* See gdb_bfd.h.  */
 
-bfd *
+gdb_bfd_ref_ptr
 gdb_bfd_openr_iovec (const char *filename, const char *target,
                     void *(*open_func) (struct bfd *nbfd,
                                         void *open_closure),
@@ -770,10 +826,7 @@ gdb_bfd_openr_iovec (const char *filename, const char *target,
                                 open_func, open_closure,
                                 pread_func, close_func, stat_func);
 
-  if (result)
-    gdb_bfd_ref (result);
-
-  return result;
+  return gdb_bfd_ref_ptr::new_reference (result);
 }
 
 /* See gdb_bfd.h.  */
@@ -787,7 +840,7 @@ gdb_bfd_mark_parent (bfd *child, bfd *parent)
   /* No need to stash the filename here, because we also keep a
      reference on the parent archive.  */
 
-  gdata = bfd_usrdata (child);
+  gdata = (struct gdb_bfd_data *) bfd_usrdata (child);
   if (gdata->archive_bfd == NULL)
     {
       gdata->archive_bfd = parent;
@@ -799,7 +852,7 @@ gdb_bfd_mark_parent (bfd *child, bfd *parent)
 
 /* See gdb_bfd.h.  */
 
-bfd *
+gdb_bfd_ref_ptr
 gdb_bfd_openr_next_archived_file (bfd *archive, bfd *previous)
 {
   bfd *result = bfd_openr_next_archived_file (archive, previous);
@@ -807,7 +860,7 @@ gdb_bfd_openr_next_archived_file (bfd *archive, bfd *previous)
   if (result)
     gdb_bfd_mark_parent (result, archive);
 
-  return result;
+  return gdb_bfd_ref_ptr (result);
 }
 
 /* See gdb_bfd.h.  */
@@ -817,22 +870,8 @@ gdb_bfd_record_inclusion (bfd *includer, bfd *includee)
 {
   struct gdb_bfd_data *gdata;
 
-  gdb_bfd_ref (includee);
-  gdata = bfd_usrdata (includer);
-  VEC_safe_push (bfdp, gdata->included_bfds, includee);
-}
-
-/* See gdb_bfd.h.  */
-
-bfd *
-gdb_bfd_fdopenr (const char *filename, const char *target, int fd)
-{
-  bfd *result = bfd_fdopenr (filename, target, fd);
-
-  if (result)
-    gdb_bfd_ref (result);
-
-  return result;
+  gdata = (struct gdb_bfd_data *) bfd_usrdata (includer);
+  gdata->included_bfds.push_back (gdb_bfd_ref_ptr::new_reference (includee));
 }
 
 \f
@@ -870,7 +909,7 @@ gdb_bfd_count_sections (bfd *abfd)
 int
 gdb_bfd_requires_relocations (bfd *abfd)
 {
-  struct gdb_bfd_data *gdata = bfd_usrdata (abfd);
+  struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
 
   if (gdata->relocation_computed == 0)
     {
@@ -896,17 +935,15 @@ gdb_bfd_requires_relocations (bfd *abfd)
 static int
 print_one_bfd (void **slot, void *data)
 {
-  bfd *abfd = *slot;
-  struct gdb_bfd_data *gdata = bfd_usrdata (abfd);
-  struct ui_out *uiout = data;
-  struct cleanup *inner;
+  bfd *abfd = (struct bfd *) *slot;
+  struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
+  struct ui_out *uiout = (struct ui_out *) data;
 
-  inner = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-  ui_out_field_int (uiout, "refcount", gdata->refc);
-  ui_out_field_string (uiout, "addr", host_address_to_string (abfd));
-  ui_out_field_string (uiout, "filename", bfd_get_filename (abfd));
-  ui_out_text (uiout, "\n");
-  do_cleanups (inner);
+  ui_out_emit_tuple tuple_emitter (uiout, NULL);
+  uiout->field_int ("refcount", gdata->refc);
+  uiout->field_string ("addr", host_address_to_string (abfd));
+  uiout->field_string ("filename", bfd_get_filename (abfd));
+  uiout->text ("\n");
 
   return 1;
 }
@@ -914,25 +951,19 @@ print_one_bfd (void **slot, void *data)
 /* Implement the 'maint info bfd' command.  */
 
 static void
-maintenance_info_bfds (char *arg, int from_tty)
+maintenance_info_bfds (const char *arg, int from_tty)
 {
-  struct cleanup *cleanup;
   struct ui_out *uiout = current_uiout;
 
-  cleanup = make_cleanup_ui_out_table_begin_end (uiout, 3, -1, "bfds");
-  ui_out_table_header (uiout, 10, ui_left, "refcount", "Refcount");
-  ui_out_table_header (uiout, 18, ui_left, "addr", "Address");
-  ui_out_table_header (uiout, 40, ui_left, "filename", "Filename");
+  ui_out_emit_table table_emitter (uiout, 3, -1, "bfds");
+  uiout->table_header (10, ui_left, "refcount", "Refcount");
+  uiout->table_header (18, ui_left, "addr", "Address");
+  uiout->table_header (40, ui_left, "filename", "Filename");
 
-  ui_out_table_body (uiout);
+  uiout->table_body ();
   htab_traverse (all_bfds, print_one_bfd, uiout);
-
-  do_cleanups (cleanup);
 }
 
-/* -Wmissing-prototypes */
-extern initialize_file_ftype _initialize_gdb_bfd;
-
 void
 _initialize_gdb_bfd (void)
 {
@@ -942,4 +973,25 @@ _initialize_gdb_bfd (void)
   add_cmd ("bfds", class_maintenance, maintenance_info_bfds, _("\
 List the BFDs that are currently open."),
           &maintenanceinfolist);
+
+  add_setshow_boolean_cmd ("bfd-sharing", no_class,
+                          &bfd_sharing, _("\
+Set whether gdb will share bfds that appear to be the same file."), _("\
+Show whether gdb will share bfds that appear to be the same file."), _("\
+When enabled gdb will reuse existing bfds rather than reopening the\n\
+same file.  To decide if two files are the same then gdb compares the\n\
+filename, file size, file modification time, and file inode."),
+                          NULL,
+                          &show_bfd_sharing,
+                          &maintenance_set_cmdlist,
+                          &maintenance_show_cmdlist);
+
+  add_setshow_zuinteger_cmd ("bfd-cache", class_maintenance,
+                            &debug_bfd_cache, _("\
+Set bfd cache debugging."), _("\
+Show bfd cache debugging."), _("\
+When non-zero, bfd cache specific debugging is enabled."),
+                            NULL,
+                            &show_bfd_cache_debug,
+                            &setdebuglist, &showdebuglist);
 }