X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fopncls.c;h=b86bbab1d302dd2ec60d5734b15efe97bdc81739;hb=46a2d504dd875caf60f9be191a55c9ff676bcd5c;hp=b2ed9beb9019460173996a82e6db57ddbe915ae7;hpb=eeb1f9aea6773f39b281b43600d38ec0aa3fed6d;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/opncls.c b/bfd/opncls.c index b2ed9beb90..b86bbab1d3 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 (C) 1990-2016 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,9 +104,13 @@ _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; + nbfd->lto_output = obfd->lto_output; + nbfd->no_export = obfd->no_export; return nbfd; } @@ -136,6 +125,9 @@ _bfd_delete_bfd (bfd *abfd) objalloc_free ((struct objalloc *) abfd->memory); } + if (abfd->filename) + free ((char *) abfd->filename); + free (abfd->arelt_data); free (abfd); } @@ -181,7 +173,7 @@ DESCRIPTION Return a pointer to the created BFD. If @var{fd} is not -1, then <> is used to open the file; otherwise, <> is used. @var{mode} is passed directly to <> or - <>. + <>. Calls <>, so @var{target} is interpreted as by that function. @@ -193,6 +185,9 @@ DESCRIPTION <> error. On error, @var{fd} is always closed. + + A copy of the @var{filename} argument is stored in the newly created + BFD. It can be accessed via the bfd_get_filename() macro. */ bfd * @@ -217,7 +212,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); @@ -232,11 +227,14 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd) } /* OK, put everything where it belongs. */ - nbfd->filename = filename; + + /* PR 11983: Do not cache the original filename, but + rather make a copy - the original might go away. */ + nbfd->filename = xstrdup (filename); /* 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') @@ -250,12 +248,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; } @@ -277,6 +276,9 @@ DESCRIPTION If <> is returned then an error has occured. Possible errors are <>, <> or <> error. + + A copy of the @var{filename} argument is stored in the newly created + BFD. It can be accessed via the bfd_get_filename() macro. */ bfd * @@ -318,6 +320,9 @@ DESCRIPTION <> and <>. On error, @var{fd} is closed. + + A copy of the @var{filename} argument is stored in the newly created + BFD. It can be accessed via the bfd_get_filename() macro. */ bfd * @@ -360,12 +365,15 @@ FUNCTION bfd_openstreamr SYNOPSIS - bfd *bfd_openstreamr (const char *, const char *, void *); + bfd *bfd_openstreamr (const char * filename, const char * target, void * stream); DESCRIPTION Open a BFD for read access on an existing stdio stream. When the BFD is passed to <>, the stream will be closed. + + A copy of the @var{filename} argument is stored in the newly created + BFD. It can be accessed via the bfd_get_filename() macro. */ bfd * @@ -387,7 +395,9 @@ bfd_openstreamr (const char *filename, const char *target, void *streamarg) } nbfd->iostream = stream; - nbfd->filename = filename; + /* PR 11983: Do not cache the original filename, but + rather make a copy - the original might go away. */ + nbfd->filename = xstrdup (filename); nbfd->direction = read_direction; if (! bfd_cache_init (nbfd)) @@ -452,6 +462,8 @@ DESCRIPTION occurred. Possible errors are <>, <> and <>. + A copy of the @var{filename} argument is stored in the newly created + BFD. It can be accessed via the bfd_get_filename() macro. */ struct opncls @@ -577,7 +589,9 @@ bfd_openr_iovec (const char *filename, const char *target, return NULL; } - nbfd->filename = filename; + /* PR 11983: Do not cache the original filename, but + rather make a copy - the original might go away. */ + nbfd->filename = xstrdup (filename); nbfd->direction = read_direction; /* `open_p (...)' would get expanded by an the open(2) syscall macro. */ @@ -618,6 +632,9 @@ DESCRIPTION Possible errors are <>, <>, <>. + + A copy of the @var{filename} argument is stored in the newly created + BFD. It can be accessed via the bfd_get_filename() macro. */ bfd * @@ -639,7 +656,9 @@ bfd_openw (const char *filename, const char *target) return NULL; } - nbfd->filename = filename; + /* PR 11983: Do not cache the original filename, but + rather make a copy - the original might go away. */ + nbfd->filename = xstrdup (filename); nbfd->direction = write_direction; if (bfd_open_file (nbfd) == NULL) @@ -718,7 +737,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); @@ -776,6 +795,9 @@ DESCRIPTION Create a new BFD in the manner of <>, but without opening a file. The new BFD takes the target from the target used by @var{templ}. The format is always set to <>. + + A copy of the @var{filename} argument is stored in the newly created + BFD. It can be accessed via the bfd_get_filename() macro. */ bfd * @@ -786,7 +808,9 @@ bfd_create (const char *filename, bfd *templ) nbfd = _bfd_new_bfd (); if (nbfd == NULL) return NULL; - nbfd->filename = filename; + /* PR 11983: Do not cache the original filename, but + rather make a copy - the original might go away. */ + nbfd->filename = xstrdup (filename); if (templ) nbfd->xvec = templ->xvec; nbfd->direction = no_direction; @@ -915,14 +939,23 @@ void * bfd_alloc (bfd *abfd, bfd_size_type size) { void *ret; - - if (size != (unsigned long) size) + unsigned long ul_size = (unsigned long) size; + + if (size != ul_size + /* Note - although objalloc_alloc takes an unsigned long as its + argument, internally the size is treated as a signed long. This can + lead to problems where, for example, a request to allocate -1 bytes + can result in just 1 byte being allocated, rather than + ((unsigned long) -1) bytes. Also memory checkers will often + complain about attempts to allocate a negative amount of memory. + So to stop these problems we fail if the size is negative. */ + || ((signed long) ul_size) < 0) { bfd_set_error (bfd_error_no_memory); return NULL; } - ret = objalloc_alloc ((struct objalloc *) abfd->memory, (unsigned long) size); + ret = objalloc_alloc ((struct objalloc *) abfd->memory, ul_size); if (ret == NULL) bfd_set_error (bfd_error_no_memory); return ret; @@ -943,8 +976,6 @@ DESCRIPTION void * bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) { - void *ret; - if ((nmemb | size) >= HALF_BFD_SIZE_TYPE && size != 0 && nmemb > ~(bfd_size_type) 0 / size) @@ -953,18 +984,7 @@ bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) return NULL; } - size *= nmemb; - - if (size != (unsigned long) size) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - - ret = objalloc_alloc ((struct objalloc *) abfd->memory, (unsigned long) size); - if (ret == NULL) - bfd_set_error (bfd_error_no_memory); - return ret; + return bfd_alloc (abfd, size * nmemb); } /* @@ -1044,10 +1064,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 @@ -1130,30 +1151,32 @@ 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}. + 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}. 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; bfd_byte *contents; - int crc_offset; + unsigned int crc_offset; char *name; BFD_ASSERT (abfd); @@ -1171,10 +1194,13 @@ get_debug_link_info (bfd *abfd, unsigned long *crc32_out) return NULL; } - /* Crc value is stored after the filename, aligned up to 4 bytes. */ + /* CRC value is stored after the filename, aligned up to 4 bytes. */ name = (char *) contents; - crc_offset = strlen (name) + 1; + /* PR 17597: avoid reading off the end of the buffer. */ + crc_offset = strnlen (name, bfd_get_section_size (sect)) + 1; crc_offset = (crc_offset + 3) & ~3; + if (crc_offset >= bfd_get_section_size (sect)) + return NULL; crc32 = bfd_get_32 (abfd, contents + crc_offset); @@ -1182,6 +1208,62 @@ 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, + 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; + unsigned 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 = strnlen (name, bfd_get_section_size (sect)) + 1; + if (buildid_offset >= bfd_get_section_size (sect)) + return NULL; + + *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 @@ -1217,6 +1299,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 @@ -1226,16 +1339,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; @@ -1256,7 +1377,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; @@ -1295,37 +1417,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); @@ -1337,19 +1444,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; } @@ -1382,7 +1488,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 + <> 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); } /*