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); |
} |
/* |