PowerPC: Make test gdb.arch/powerpc-power10.exp Endian independent.
[binutils-gdb.git] / gdb / gdb_bfd.c
index 15bf9f79c2038933b84175e1ead398f178687779..22828482d5b39d85b678f3342cbe605d7aaff60f 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions for BFD wrappers used by GDB.
 
-   Copyright (C) 2011-2020 Free Software Foundation, Inc.
+   Copyright (C) 2011-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -32,6 +32,7 @@
 #include "target.h"
 #include "gdb/fileio.h"
 #include "inferior.h"
+#include "cli/cli-style.h"
 
 /* An object of this type is stored in the section's user data when
    mapping a section.  */
@@ -131,17 +132,23 @@ 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);
+  gdb_printf (file, _("BFD sharing is %s.\n"), value);
 }
 
-/* When non-zero debugging of the bfd caches is enabled.  */
+/* When true debugging of the bfd caches is enabled.  */
+
+static bool debug_bfd_cache;
+
+/* Print an "bfd-cache" debug statement.  */
+
+#define bfd_cache_debug_printf(fmt, ...) \
+  debug_prefixed_printf_cond (debug_bfd_cache, "bfd-cache", fmt, ##__VA_ARGS__)
 
-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);
+  gdb_printf (file, _("BFD cache debugging is %s.\n"), value);
 }
 
 /* The type of an object being looked up in gdb_bfd_cache.  We use
@@ -207,6 +214,91 @@ gdb_bfd_has_target_filename (struct bfd *abfd)
   return is_target_filename (bfd_get_filename (abfd));
 }
 
+/* For `gdb_bfd_open_from_target_memory`.  */
+
+struct target_buffer
+{
+  CORE_ADDR base;
+  ULONGEST size;
+};
+
+/* For `gdb_bfd_open_from_target_memory`.  Opening the file is a no-op.  */
+
+static void *
+mem_bfd_iovec_open (struct bfd *abfd, void *open_closure)
+{
+  return open_closure;
+}
+
+/* For `gdb_bfd_open_from_target_memory`.  Closing the file is just freeing the
+   base/size pair on our side.  */
+
+static int
+mem_bfd_iovec_close (struct bfd *abfd, void *stream)
+{
+  xfree (stream);
+
+  /* Zero means success.  */
+  return 0;
+}
+
+/* For `gdb_bfd_open_from_target_memory`.  For reading the file, we just need to
+   pass through to target_read_memory and fix up the arguments and return
+   values.  */
+
+static file_ptr
+mem_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
+                    file_ptr nbytes, file_ptr offset)
+{
+  int err;
+  struct target_buffer *buffer = (struct target_buffer *) stream;
+
+  /* If this read will read all of the file, limit it to just the rest.  */
+  if (offset + nbytes > buffer->size)
+    nbytes = buffer->size - offset;
+
+  /* If there are no more bytes left, we've reached EOF.  */
+  if (nbytes == 0)
+    return 0;
+
+  err = target_read_memory (buffer->base + offset, (gdb_byte *) buf, nbytes);
+  if (err)
+    return -1;
+
+  return nbytes;
+}
+
+/* For `gdb_bfd_open_from_target_memory`.  For statting the file, we only
+   support the st_size attribute.  */
+
+static int
+mem_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
+{
+  struct target_buffer *buffer = (struct target_buffer*) stream;
+
+  memset (sb, 0, sizeof (struct stat));
+  sb->st_size = buffer->size;
+  return 0;
+}
+
+/* See gdb_bfd.h.  */
+
+gdb_bfd_ref_ptr
+gdb_bfd_open_from_target_memory (CORE_ADDR addr, ULONGEST size,
+                                const char *target,
+                                const char *filename)
+{
+  struct target_buffer *buffer = XNEW (struct target_buffer);
+
+  buffer->base = addr;
+  buffer->size = size;
+  return gdb_bfd_openr_iovec (filename ? filename : "<in-memory>", target,
+                             mem_bfd_iovec_open,
+                             buffer,
+                             mem_bfd_iovec_pread,
+                             mem_bfd_iovec_close,
+                             mem_bfd_iovec_stat);
+}
 
 /* Return the system error number corresponding to ERRNUM.  */
 
@@ -216,47 +308,47 @@ fileio_errno_to_host (int errnum)
   switch (errnum)
     {
       case FILEIO_EPERM:
-        return EPERM;
+       return EPERM;
       case FILEIO_ENOENT:
-        return ENOENT;
+       return ENOENT;
       case FILEIO_EINTR:
-        return EINTR;
+       return EINTR;
       case FILEIO_EIO:
-        return EIO;
+       return EIO;
       case FILEIO_EBADF:
-        return EBADF;
+       return EBADF;
       case FILEIO_EACCES:
-        return EACCES;
+       return EACCES;
       case FILEIO_EFAULT:
-        return EFAULT;
+       return EFAULT;
       case FILEIO_EBUSY:
-        return EBUSY;
+       return EBUSY;
       case FILEIO_EEXIST:
-        return EEXIST;
+       return EEXIST;
       case FILEIO_ENODEV:
-        return ENODEV;
+       return ENODEV;
       case FILEIO_ENOTDIR:
-        return ENOTDIR;
+       return ENOTDIR;
       case FILEIO_EISDIR:
-        return EISDIR;
+       return EISDIR;
       case FILEIO_EINVAL:
-        return EINVAL;
+       return EINVAL;
       case FILEIO_ENFILE:
-        return ENFILE;
+       return ENFILE;
       case FILEIO_EMFILE:
-        return EMFILE;
+       return EMFILE;
       case FILEIO_EFBIG:
-        return EFBIG;
+       return EFBIG;
       case FILEIO_ENOSPC:
-        return ENOSPC;
+       return ENOSPC;
       case FILEIO_ESPIPE:
-        return ESPIPE;
+       return ESPIPE;
       case FILEIO_EROFS:
-        return EROFS;
+       return EROFS;
       case FILEIO_ENOSYS:
-        return ENOSYS;
+       return ENOSYS;
       case FILEIO_ENAMETOOLONG:
-        return ENAMETOOLONG;
+       return ENAMETOOLONG;
     }
   return -1;
 }
@@ -317,8 +409,8 @@ gdb_bfd_iovec_fileio_pread (struct bfd *abfd, void *stream, void *buf,
                                   nbytes - pos, offset + pos,
                                   &target_errno);
       if (bytes == 0)
-        /* Success, but no bytes, means end-of-file.  */
-        break;
+       /* Success, but no bytes, means end-of-file.  */
+       break;
       if (bytes == -1)
        {
          errno = fileio_errno_to_host (target_errno);
@@ -332,6 +424,15 @@ gdb_bfd_iovec_fileio_pread (struct bfd *abfd, void *stream, void *buf,
   return pos;
 }
 
+/* Warn that it wasn't possible to close a bfd for file NAME, because
+   of REASON.  */
+
+static void
+gdb_bfd_close_warning (const char *name, const char *reason)
+{
+  warning (_("cannot close \"%s\": %s"), name, reason);
+}
+
 /* Wrapper for target_fileio_close suitable for passing as the
    CLOSE_FUNC argument to gdb_bfd_openr_iovec.  */
 
@@ -345,7 +446,16 @@ gdb_bfd_iovec_fileio_close (struct bfd *abfd, void *stream)
 
   /* Ignore errors on close.  These may happen with remote
      targets if the connection has already been torn down.  */
-  target_fileio_close (fd, &target_errno);
+  try
+    {
+      target_fileio_close (fd, &target_errno);
+    }
+  catch (const gdb_exception &ex)
+    {
+      /* Also avoid crossing exceptions over bfd.  */
+      gdb_bfd_close_warning (bfd_get_filename (abfd),
+                            ex.message->c_str ());
+    }
 
   /* Zero means success.  */
   return 0;
@@ -432,7 +542,7 @@ gdb_bfd_open (const char *name, const char *target, int fd,
 
   if (fd == -1)
     {
-      fd = gdb_open_cloexec (name, O_RDONLY | O_BINARY, 0);
+      fd = gdb_open_cloexec (name, O_RDONLY | O_BINARY, 0).release ();
       if (fd == -1)
        {
          bfd_set_error (bfd_error_system_call);
@@ -443,11 +553,10 @@ gdb_bfd_open (const char *name, const char *target, int fd,
   if (fstat (fd, &st) < 0)
     {
       /* Weird situation here -- don't cache if we can't stat.  */
-      if (debug_bfd_cache)
-       fprintf_unfiltered (gdb_stdlog,
-                           "Could not stat bfd %s for %s - not caching\n",
-                           host_address_to_string (abfd),
-                           bfd_get_filename (abfd));
+      bfd_cache_debug_printf ("Could not stat %s - not caching", name);
+      abfd = bfd_fopen (name, target, FOPEN_RB, fd);
+      if (abfd == nullptr)
+       return nullptr;
       return gdb_bfd_ref_ptr::new_reference (abfd);
     }
 
@@ -465,11 +574,9 @@ gdb_bfd_open (const char *name, const char *target, int fd,
   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));
+      bfd_cache_debug_printf ("Reusing cached bfd %s for %s",
+                             host_address_to_string (abfd),
+                             bfd_get_filename (abfd));
       close (fd);
       return gdb_bfd_ref_ptr::new_reference (abfd);
     }
@@ -478,11 +585,9 @@ gdb_bfd_open (const char *name, const char *target, int fd,
   if (abfd == NULL)
     return NULL;
 
-  if (debug_bfd_cache)
-    fprintf_unfiltered (gdb_stdlog,
-                       "Creating new bfd %s for %s\n",
-                       host_address_to_string (abfd),
-                       bfd_get_filename (abfd));
+  bfd_cache_debug_printf ("Creating new bfd %s for %s",
+                         host_address_to_string (abfd),
+                         bfd_get_filename (abfd));
 
   if (bfd_sharing)
     {
@@ -505,7 +610,7 @@ gdb_bfd_open (const char *name, const char *target, int fd,
    BFD.  */
 
 static void
-free_one_bfd_section (bfd *abfd, asection *sectp, void *ignore)
+free_one_bfd_section (asection *sectp)
 {
   struct gdb_bfd_section_data *sect
     = (struct gdb_bfd_section_data *) bfd_section_userdata (sectp);
@@ -534,13 +639,14 @@ gdb_bfd_close_or_warn (struct bfd *abfd)
   int ret;
   const char *name = bfd_get_filename (abfd);
 
-  bfd_map_over_sections (abfd, free_one_bfd_section, NULL);
+  for (asection *sect : gdb_bfd_sections (abfd))
+    free_one_bfd_section (sect);
 
   ret = bfd_close (abfd);
 
   if (!ret)
-    warning (_("cannot close \"%s\": %s"),
-            name, bfd_errmsg (bfd_get_error ()));
+    gdb_bfd_close_warning (name,
+                          bfd_errmsg (bfd_get_error ()));
 
   return ret;
 }
@@ -557,11 +663,9 @@ gdb_bfd_ref (struct bfd *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));
+  bfd_cache_debug_printf ("Increase reference count on bfd %s (%s)",
+                         host_address_to_string (abfd),
+                         bfd_get_filename (abfd));
 
   if (gdata != NULL)
     {
@@ -592,19 +696,15 @@ gdb_bfd_unref (struct bfd *abfd)
   gdata->refc -= 1;
   if (gdata->refc > 0)
     {
-      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));
+      bfd_cache_debug_printf ("Decrease reference count on bfd %s (%s)",
+                             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));
+  bfd_cache_debug_printf ("Delete final reference count on bfd %s (%s)",
+                         host_address_to_string (abfd),
+                         bfd_get_filename (abfd));
 
   archive_bfd = gdata->archive_bfd;
   search.filename = bfd_get_filename (abfd);
@@ -960,6 +1060,36 @@ gdb_bfd_get_full_section_contents (bfd *abfd, asection *section,
                                   section_size);
 }
 
+#define AMBIGUOUS_MESS1        ".\nMatching formats:"
+#define AMBIGUOUS_MESS2        \
+  ".\nUse \"set gnutarget format-name\" to specify the format."
+
+/* See gdb_bfd.h.  */
+
+std::string
+gdb_bfd_errmsg (bfd_error_type error_tag, char **matching)
+{
+  char **p;
+
+  /* Check if errmsg just need simple return.  */
+  if (error_tag != bfd_error_file_ambiguously_recognized || matching == NULL)
+    return bfd_errmsg (error_tag);
+
+  std::string ret (bfd_errmsg (error_tag));
+  ret += AMBIGUOUS_MESS1;
+
+  for (p = matching; *p; p++)
+    {
+      ret += " ";
+      ret += *p;
+    }
+  ret += AMBIGUOUS_MESS2;
+
+  xfree (matching);
+
+  return ret;
+}
+
 /* A callback for htab_traverse that prints a single BFD.  */
 
 static int
@@ -972,7 +1102,8 @@ print_one_bfd (void **slot, void *data)
   ui_out_emit_tuple tuple_emitter (uiout, NULL);
   uiout->field_signed ("refcount", gdata->refc);
   uiout->field_string ("addr", host_address_to_string (abfd));
-  uiout->field_string ("filename", bfd_get_filename (abfd));
+  uiout->field_string ("filename", bfd_get_filename (abfd),
+                      file_name_style.style ());
   uiout->text ("\n");
 
   return 1;
@@ -1017,12 +1148,13 @@ filename, file size, file modification time, and file inode."),
                           &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."), _("\
+  add_setshow_boolean_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);
+                          NULL,
+                          &show_bfd_cache_debug,
+                          &setdebuglist, &showdebuglist);
 }