* emulparams/elf32ppccommon.sh (LIBPATH_SUFFIX): Provide 32-bit
[deliverable/binutils-gdb.git] / bfd / opncls.c
index fdccba371ecd0cebb6d623d7d11396a2ca84adad..cd9c826dd4bcf9989dc040d143d5c2feed8a7b76 100644 (file)
@@ -1,7 +1,5 @@
 /* opncls.c -- open and close a BFD.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012
-   Free Software Foundation, Inc.
+   Copyright 1990-2013 Free Software Foundation, Inc.
 
    Written by Cygnus Support.
 
@@ -86,7 +84,7 @@ _bfd_new_bfd (void)
   nbfd->iostream = NULL;
   nbfd->where = 0;
   if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc,
-                             sizeof (struct section_hash_entry), 251))
+                             sizeof (struct section_hash_entry), 13))
     {
       free (nbfd);
       return NULL;
@@ -107,6 +105,8 @@ _bfd_new_bfd (void)
   return nbfd;
 }
 
+static const struct bfd_iovec opncls_iovec;
+
 /* Allocate a new BFD as a member of archive OBFD.  */
 
 bfd *
@@ -119,6 +119,8 @@ _bfd_new_bfd_contained_in (bfd *obfd)
     return NULL;
   nbfd->xvec = obfd->xvec;
   nbfd->iovec = obfd->iovec;
+  if (obfd->iovec == &opncls_iovec)
+    nbfd->iostream = obfd->iostream;
   nbfd->my_archive = obfd;
   nbfd->direction = read_direction;
   nbfd->target_defaulted = obfd->target_defaulted;
@@ -182,7 +184,7 @@ DESCRIPTION
        Return a pointer to the created BFD.  If @var{fd} is not -1,
        then <<fdopen>> is used to open the file; otherwise, <<fopen>>
        is used.  @var{mode} is passed directly to <<fopen>> or
-       <<fdopen>>. 
+       <<fdopen>>.
 
        Calls <<bfd_find_target>>, so @var{target} is interpreted as by
        that function.
@@ -218,7 +220,7 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd)
       _bfd_delete_bfd (nbfd);
       return NULL;
     }
-  
+
 #ifdef HAVE_FDOPEN
   if (fd != -1)
     nbfd->iostream = fdopen (fd, mode);
@@ -237,7 +239,7 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd)
 
   /* Figure out whether the user is opening the file for reading,
      writing, or both, by looking at the MODE argument.  */
-  if ((mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a') 
+  if ((mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a')
       && mode[1] == '+')
     nbfd->direction = both_direction;
   else if (mode[0] == 'r')
@@ -251,12 +253,13 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd)
       return NULL;
     }
   nbfd->opened_once = TRUE;
+
   /* If we opened the file by name, mark it cacheable; we can close it
      and reopen it later.  However, if a file descriptor was provided,
      then it may have been opened with special flags that make it
      unsafe to close and reopen the file.  */
   if (fd == -1)
-    bfd_set_cacheable (nbfd, TRUE);
+    (void) bfd_set_cacheable (nbfd, TRUE);
 
   return nbfd;
 }
@@ -719,7 +722,7 @@ bfd_close (bfd *abfd)
   if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
     return FALSE;
 
-  ret = abfd->iovec->bclose (abfd);
+  ret = abfd->iovec->bclose (abfd) == 0;
 
   if (ret)
     _maybe_make_executable (abfd);
@@ -1045,10 +1048,11 @@ bfd_release (bfd *abfd, void *block)
 
    This facilitates "optional" provision of debugging information, without
    having to provide two complete copies of every binary object (with and
-   without debug symbols).
-*/
+   without debug symbols).  */
+
+#define GNU_DEBUGLINK          ".gnu_debuglink"
+#define GNU_DEBUGALTLINK       ".gnu_debugaltlink"
 
-#define GNU_DEBUGLINK  ".gnu_debuglink"
 /*
 FUNCTION
        bfd_calc_gnu_debuglink_crc32
@@ -1131,25 +1135,27 @@ bfd_calc_gnu_debuglink_crc32 (unsigned long crc,
   crc = ~crc & 0xffffffff;
   for (end = buf + len; buf < end; ++ buf)
     crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
-  return ~crc & 0xffffffff;;
+  return ~crc & 0xffffffff;
 }
 
 
 /*
-INTERNAL_FUNCTION
-       get_debug_link_info
+FUNCTION
+       bfd_get_debug_link_info
 
 SYNOPSIS
-       char *get_debug_link_info (bfd *abfd, unsigned long *crc32_out);
+       char *bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out);
 
 DESCRIPTION
        fetch the filename and CRC32 value for any separate debuginfo
        associated with @var{abfd}. Return NULL if no such info found,
-       otherwise return filename and update @var{crc32_out}.
+       otherwise return filename and update @var{crc32_out}.  The
+       returned filename is allocated with @code{malloc}; freeing it
+       is the responsibility of the caller.
 */
 
-static char *
-get_debug_link_info (bfd *abfd, unsigned long *crc32_out)
+char *
+bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out)
 {
   asection *sect;
   unsigned long crc32;
@@ -1183,6 +1189,54 @@ get_debug_link_info (bfd *abfd, unsigned long *crc32_out)
   return name;
 }
 
+/*
+FUNCTION
+       bfd_get_alt_debug_link_info
+
+SYNOPSIS
+       char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out);
+
+DESCRIPTION
+       Fetch the filename and BuildID value for any alternate debuginfo
+       associated with @var{abfd}.  Return NULL if no such info found,
+       otherwise return filename and update @var{buildid_out}.  The
+       returned filename is allocated with @code{malloc}; freeing it
+       is the responsibility of the caller.
+*/
+
+char *
+bfd_get_alt_debug_link_info (bfd * abfd, unsigned long * buildid_out)
+{
+  asection *sect;
+  bfd_byte *contents;
+  int buildid_offset;
+  char *name;
+
+  BFD_ASSERT (abfd);
+  BFD_ASSERT (buildid_out);
+
+  sect = bfd_get_section_by_name (abfd, GNU_DEBUGALTLINK);
+
+  if (sect == NULL)
+    return NULL;
+
+  if (!bfd_malloc_and_get_section (abfd, sect, & contents))
+    {
+      if (contents != NULL)
+       free (contents);
+      return NULL;
+    }
+
+  /* BuildID value is stored after the filename, aligned up to 4 bytes.  */
+  name = (char *) contents;
+  buildid_offset = strlen (name) + 1;
+  buildid_offset = (buildid_offset + 3) & ~3;
+
+  * buildid_out = bfd_get_32 (abfd, contents + buildid_offset);
+
+  return name;
+}
+
 /*
 INTERNAL_FUNCTION
        separate_debug_file_exists
@@ -1218,6 +1272,37 @@ separate_debug_file_exists (const char *name, const unsigned long crc)
   return crc == file_crc;
 }
 
+/*
+INTERNAL_FUNCTION
+       separate_alt_debug_file_exists
+
+SYNOPSIS
+       bfd_boolean separate_alt_debug_file_exists
+         (char *name, unsigned long crc32);
+
+DESCRIPTION
+       Checks to see if @var{name} is a file and if its BuildID
+       matches @var{buildid}.
+*/
+
+static bfd_boolean
+separate_alt_debug_file_exists (const char *name,
+                               const unsigned long buildid ATTRIBUTE_UNUSED)
+{
+  FILE *f;
+
+  BFD_ASSERT (name);
+
+  f = real_fopen (name, FOPEN_RB);
+  if (f == NULL)
+    return FALSE;
+
+  /* FIXME: Add code to check buildid.  */
+
+  fclose (f);
+
+  return TRUE;
+}
 
 /*
 INTERNAL_FUNCTION
@@ -1227,16 +1312,24 @@ SYNOPSIS
        char *find_separate_debug_file (bfd *abfd);
 
 DESCRIPTION
-       Searches @var{abfd} for a reference to separate debugging
-       information, scans various locations in the filesystem, including
-       the file tree rooted at @var{debug_file_directory}, and returns a
-       filename of such debugging information if the file is found and has
-       matching CRC32.  Returns NULL if no reference to debugging file
-       exists, or file cannot be found.
+       Searches @var{abfd} for a section called @var{section_name} which
+       is expected to contain a reference to a file containing separate
+       debugging information.  The function scans various locations in
+       the filesystem, including the file tree rooted at
+       @var{debug_file_directory}, and returns the first matching
+       filename that it finds.  If @var{check_crc} is TRUE then the
+       contents of the file must also match the CRC value contained in
+       @var{section_name}.  Returns NULL if no valid file could be found.
 */
 
+typedef char *      (* get_func_type) (bfd *, unsigned long *);
+typedef bfd_boolean (* check_func_type) (const char *, const unsigned long);
+
 static char *
-find_separate_debug_file (bfd *abfd, const char *debug_file_directory)
+find_separate_debug_file (bfd *           abfd,
+                         const char *    debug_file_directory,
+                         get_func_type   get_func,
+                         check_func_type check_func)
 {
   char *base;
   char *dir;
@@ -1257,7 +1350,8 @@ find_separate_debug_file (bfd *abfd, const char *debug_file_directory)
       return NULL;
     }
 
-  base = get_debug_link_info (abfd, & crc32);
+  base = get_func (abfd, & crc32);
+    
   if (base == NULL)
     return NULL;
 
@@ -1296,37 +1390,22 @@ find_separate_debug_file (bfd *abfd, const char *debug_file_directory)
                   + strlen (base)
                   + 1);
   if (debugfile == NULL)
-    {
-      free (base);
-      free (dir);
-      free (canon_dir);
-      return NULL;
-    }
+    goto found; /* Actually this returns NULL.  */
 
   /* First try in the same directory as the original file:  */
   strcpy (debugfile, dir);
   strcat (debugfile, base);
 
-  if (separate_debug_file_exists (debugfile, crc32))
-    {
-      free (base);
-      free (dir);
-      free (canon_dir);
-      return debugfile;
-    }
+  if (check_func (debugfile, crc32))
+    goto found;
 
   /* Then try in a subdirectory called .debug.  */
   strcpy (debugfile, dir);
   strcat (debugfile, ".debug/");
   strcat (debugfile, base);
 
-  if (separate_debug_file_exists (debugfile, crc32))
-    {
-      free (base);
-      free (dir);
-      free (canon_dir);
-      return debugfile;
-    }
+  if (check_func (debugfile, crc32))
+    goto found;
 
   /* Then try in the global debugfile directory.  */
   strcpy (debugfile, debug_file_directory);
@@ -1338,19 +1417,18 @@ find_separate_debug_file (bfd *abfd, const char *debug_file_directory)
   strcat (debugfile, canon_dir);
   strcat (debugfile, base);
 
-  if (separate_debug_file_exists (debugfile, crc32))
-    {
-      free (base);
-      free (dir);
-      free (canon_dir);
-      return debugfile;
-    }
+  if (check_func (debugfile, crc32))
+    goto found;
 
+  /* Failed to find the file.  */
   free (debugfile);
+  debugfile = NULL;
+
+ found:
   free (base);
   free (dir);
   free (canon_dir);
-  return NULL;
+  return debugfile;
 }
 
 
@@ -1383,7 +1461,43 @@ RETURNS
 char *
 bfd_follow_gnu_debuglink (bfd *abfd, const char *dir)
 {
-  return find_separate_debug_file (abfd, dir);
+  return find_separate_debug_file (abfd, dir,
+                                  bfd_get_debug_link_info,
+                                  separate_debug_file_exists);
+}
+
+/*
+FUNCTION
+       bfd_follow_gnu_debugaltlink
+
+SYNOPSIS
+       char *bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir);
+
+DESCRIPTION
+
+       Takes a BFD and searches it for a .gnu_debugaltlink section.  If this
+       section is found, it examines the section for the name of a file
+       containing auxiliary debugging information.  It then searches the
+       filesystem for this file in a set of standard locations, including
+       the directory tree rooted at @var{dir}, and if found returns the
+       full filename.
+
+       If @var{dir} is NULL, it will search a default path configured into
+       libbfd at build time.  [FIXME: This feature is not currently
+       implemented].
+
+RETURNS
+       <<NULL>> on any errors or failure to locate the debug file,
+       otherwise a pointer to a heap-allocated string containing the
+       filename.  The caller is responsible for freeing this string.
+*/
+
+char *
+bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir)
+{
+  return find_separate_debug_file (abfd, dir,
+                                  bfd_get_alt_debug_link_info,
+                                  separate_alt_debug_file_exists);
 }
 
 /*
This page took 0.029392 seconds and 4 git commands to generate.