| Index: bfd/opncls.c
|
| diff --git a/bfd/opncls.c b/bfd/opncls.c
|
| index 7c1d2f99a5815990d97da36958079a91e8538946..3f09420bf735db821a88bc6395702b6f26c7e06d 100644
|
| --- a/bfd/opncls.c
|
| +++ b/bfd/opncls.c
|
| @@ -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.
|
|
|
| @@ -82,31 +80,18 @@ _bfd_new_bfd (void)
|
|
|
| nbfd->arch_info = &bfd_default_arch_struct;
|
|
|
| - nbfd->direction = no_direction;
|
| - 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;
|
| }
|
| - nbfd->sections = NULL;
|
| - nbfd->section_last = NULL;
|
| - nbfd->format = bfd_unknown;
|
| - nbfd->my_archive = NULL;
|
| - nbfd->origin = 0;
|
| - nbfd->opened_once = FALSE;
|
| - nbfd->output_has_begun = FALSE;
|
| - nbfd->section_count = 0;
|
| - nbfd->usrdata = NULL;
|
| - nbfd->cacheable = FALSE;
|
| - nbfd->flags = BFD_NO_FLAGS;
|
| - nbfd->mtime_set = FALSE;
|
|
|
| return nbfd;
|
| }
|
|
|
| +static const struct bfd_iovec opncls_iovec;
|
| +
|
| /* Allocate a new BFD as a member of archive OBFD. */
|
|
|
| bfd *
|
| @@ -119,6 +104,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;
|
| @@ -127,7 +114,7 @@ _bfd_new_bfd_contained_in (bfd *obfd)
|
|
|
| /* Delete a BFD. */
|
|
|
| -void
|
| +static void
|
| _bfd_delete_bfd (bfd *abfd)
|
| {
|
| if (abfd->memory)
|
| @@ -135,6 +122,8 @@ _bfd_delete_bfd (bfd *abfd)
|
| bfd_hash_table_free (&abfd->section_htab);
|
| objalloc_free ((struct objalloc *) abfd->memory);
|
| }
|
| +
|
| + free (abfd->arelt_data);
|
| free (abfd);
|
| }
|
|
|
| @@ -180,7 +169,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.
|
| @@ -216,7 +205,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);
|
| @@ -235,7 +224,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')
|
| @@ -249,12 +238,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;
|
| }
|
| @@ -707,8 +697,6 @@ bfd_boolean
|
| bfd_close (bfd *abfd)
|
| {
|
| bfd_boolean ret;
|
| - bfd *nbfd;
|
| - bfd *next;
|
|
|
| if (bfd_write_p (abfd))
|
| {
|
| @@ -716,17 +704,10 @@ bfd_close (bfd *abfd)
|
| return FALSE;
|
| }
|
|
|
| - /* Close nested archives (if this bfd is a thin archive). */
|
| - for (nbfd = abfd->nested_archives; nbfd; nbfd = next)
|
| - {
|
| - next = nbfd->archive_next;
|
| - bfd_close (nbfd);
|
| - }
|
| -
|
| 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);
|
| @@ -1052,10 +1033,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
|
| @@ -1138,25 +1120,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;
|
| @@ -1191,6 +1175,60 @@ get_debug_link_info (bfd *abfd, unsigned long *crc32_out)
|
| }
|
|
|
| /*
|
| +FUNCTION
|
| + bfd_get_alt_debug_link_info
|
| +
|
| +SYNOPSIS
|
| + char *bfd_get_alt_debug_link_info (bfd * abfd,
|
| + bfd_size_type *buildid_len,
|
| + bfd_byte **buildid_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_len} and
|
| + @var{buildid_out}. The returned filename and build_id are
|
| + allocated with @code{malloc}; freeing them is the
|
| + responsibility of the caller.
|
| +*/
|
| +
|
| +char *
|
| +bfd_get_alt_debug_link_info (bfd * abfd, bfd_size_type *buildid_len,
|
| + bfd_byte **buildid_out)
|
| +{
|
| + asection *sect;
|
| + bfd_byte *contents;
|
| + int buildid_offset;
|
| + char *name;
|
| +
|
| + BFD_ASSERT (abfd);
|
| + BFD_ASSERT (buildid_len);
|
| + 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. */
|
| + name = (char *) contents;
|
| + buildid_offset = strlen (name) + 1;
|
| +
|
| + *buildid_len = bfd_get_section_size (sect) - buildid_offset;
|
| + *buildid_out = bfd_malloc (*buildid_len);
|
| + memcpy (*buildid_out, contents + buildid_offset, *buildid_len);
|
| +
|
| + return name;
|
| +}
|
| +
|
| +/*
|
| INTERNAL_FUNCTION
|
| separate_debug_file_exists
|
|
|
| @@ -1225,6 +1263,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
|
| @@ -1234,16 +1303,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;
|
| @@ -1264,7 +1341,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;
|
|
|
| @@ -1303,37 +1381,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);
|
| @@ -1345,19 +1408,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;
|
| }
|
|
|
|
|
| @@ -1390,7 +1452,61 @@ 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);
|
| +}
|
| +
|
| +/* Helper for bfd_follow_gnu_debugaltlink. It just pretends to return
|
| + a CRC. .gnu_debugaltlink supplies a build-id, which is different,
|
| + but this is ok because separate_alt_debug_file_exists ignores the
|
| + CRC anyway. */
|
| +
|
| +static char *
|
| +get_alt_debug_link_info_shim (bfd * abfd, unsigned long *crc32_out)
|
| +{
|
| + bfd_size_type len;
|
| + bfd_byte *buildid = NULL;
|
| + char *result = bfd_get_alt_debug_link_info (abfd, &len, &buildid);
|
| +
|
| + *crc32_out = 0;
|
| + free (buildid);
|
| +
|
| + return result;
|
| +}
|
| +
|
| +/*
|
| +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,
|
| + get_alt_debug_link_info_shim,
|
| + separate_alt_debug_file_exists);
|
| }
|
|
|
| /*
|
|
|