/* opncls.c -- open and close a BFD.
- Copyright (C) 1990-2020 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
Written by Cygnus Support.
if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc,
sizeof (struct section_hash_entry), 13))
{
+ objalloc_free ((struct objalloc *) nbfd->memory);
free (nbfd);
return NULL;
}
+ nbfd->archive_plugin_fd = -1;
+
return nbfd;
}
bfd_hash_table_free (&abfd->section_htab);
objalloc_free ((struct objalloc *) abfd->memory);
}
+ else
+ free ((char *) bfd_get_filename (abfd));
- free ((char *) bfd_get_filename (abfd));
free (abfd->arelt_data);
free (abfd);
}
/* Free objalloc memory. */
-bfd_boolean
+bool
_bfd_free_cached_info (bfd *abfd)
{
if (abfd->memory)
{
+ const char *filename = bfd_get_filename (abfd);
+ if (filename)
+ {
+ /* We can't afford to lose the bfd filename when freeing
+ abfd->memory, because that would kill the cache.c scheme
+ of closing and reopening files in order to limit the
+ number of open files. To reopen, you need the filename.
+ And indeed _bfd_compute_and_write_armap calls
+ _bfd_free_cached_info to free up space used by symbols
+ and by check_format_matches. Which we want to continue
+ doing to handle very large archives. Later the archive
+ elements are copied, which might require reopening files.
+ We also want to keep using objalloc memory for the
+ filename since that allows the name to be updated
+ without either leaking memory or implementing some sort
+ of reference counted string for copies of the filename. */
+ size_t len = strlen (filename) + 1;
+ char *copy = bfd_malloc (len);
+ if (copy == NULL)
+ return false;
+ memcpy (copy, filename, len);
+ abfd->filename = copy;
+ }
bfd_hash_table_free (&abfd->section_htab);
objalloc_free ((struct objalloc *) abfd->memory);
abfd->memory = NULL;
}
- return TRUE;
+ return true;
}
/*
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = bfd_strdup (filename);
- if (nbfd->filename == NULL)
+ if (!bfd_set_filename (nbfd, filename))
{
fclose (nbfd->iostream);
_bfd_delete_bfd (nbfd);
_bfd_delete_bfd (nbfd);
return NULL;
}
- nbfd->opened_once = TRUE;
+ 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)
- (void) bfd_set_cacheable (nbfd, TRUE);
+ (void) bfd_set_cacheable (nbfd, true);
return nbfd;
}
return bfd_fopen (filename, target, mode, fd);
}
+/*
+FUNCTION
+ bfd_fdopenw
+
+SYNOPSIS
+ bfd *bfd_fdopenw (const char *filename, const char *target, int fd);
+
+DESCRIPTION
+ <<bfd_fdopenw>> is exactly like <<bfd_fdopenr>> with the exception that
+ the resulting BFD is suitable for output.
+*/
+
+bfd *
+bfd_fdopenw (const char *filename, const char *target, int fd)
+{
+ bfd *out = bfd_fdopenr (filename, target, fd);
+
+ if (out != NULL)
+ {
+ if (!bfd_write_p (out))
+ {
+ close (fd);
+ _bfd_delete_bfd (out);
+ out = NULL;
+ bfd_set_error (bfd_error_invalid_operation);
+ }
+ else
+ out->direction = write_direction;
+ }
+
+ return out;
+}
+
/*
FUNCTION
bfd_openstreamr
nbfd->iostream = stream;
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = bfd_strdup (filename);
- if (nbfd->filename == NULL)
+ if (!bfd_set_filename (nbfd, filename))
{
_bfd_delete_bfd (nbfd);
return NULL;
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = bfd_strdup (filename);
- if (nbfd->filename == NULL)
+ if (!bfd_set_filename (nbfd, filename))
{
_bfd_delete_bfd (nbfd);
return NULL;
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = bfd_strdup (filename);
- if (nbfd->filename == NULL)
+ if (!bfd_set_filename (nbfd, filename))
{
_bfd_delete_bfd (nbfd);
return NULL;
bfd_close
SYNOPSIS
- bfd_boolean bfd_close (bfd *abfd);
+ bool bfd_close (bfd *abfd);
DESCRIPTION
Close a BFD. If the BFD was open for writing, then pending
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>.
*/
-bfd_boolean
+bool
bfd_close (bfd *abfd)
{
if (bfd_write_p (abfd))
{
if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)))
- return FALSE;
+ return false;
}
return bfd_close_all_done (abfd);
bfd_close_all_done
SYNOPSIS
- bfd_boolean bfd_close_all_done (bfd *);
+ bool bfd_close_all_done (bfd *);
DESCRIPTION
Close a BFD. Differs from <<bfd_close>> since it does not
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>.
*/
-bfd_boolean
+bool
bfd_close_all_done (bfd *abfd)
{
- bfd_boolean ret;
+ bool ret;
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
- return FALSE;
+ return false;
ret = abfd->iovec->bclose (abfd) == 0;
return NULL;
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = bfd_strdup (filename);
- if (nbfd->filename == NULL)
+ if (!bfd_set_filename (nbfd, filename))
{
_bfd_delete_bfd (nbfd);
return NULL;
bfd_make_writable
SYNOPSIS
- bfd_boolean bfd_make_writable (bfd *abfd);
+ bool bfd_make_writable (bfd *abfd);
DESCRIPTION
Takes a BFD as created by <<bfd_create>> and converts it
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>.
*/
-bfd_boolean
+bool
bfd_make_writable (bfd *abfd)
{
struct bfd_in_memory *bim;
if (abfd->direction != no_direction)
{
bfd_set_error (bfd_error_invalid_operation);
- return FALSE;
+ return false;
}
bim = (struct bfd_in_memory *) bfd_malloc (sizeof (struct bfd_in_memory));
if (bim == NULL)
- return FALSE; /* bfd_error already set. */
+ return false; /* bfd_error already set. */
abfd->iostream = bim;
/* bfd_bwrite will grow these as needed. */
bim->size = 0;
abfd->direction = write_direction;
abfd->where = 0;
- return TRUE;
+ return true;
}
/*
bfd_make_readable
SYNOPSIS
- bfd_boolean bfd_make_readable (bfd *abfd);
+ bool bfd_make_readable (bfd *abfd);
DESCRIPTION
Takes a BFD as created by <<bfd_create>> and
RETURNS
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>. */
-bfd_boolean
+bool
bfd_make_readable (bfd *abfd)
{
if (abfd->direction != write_direction || !(abfd->flags & BFD_IN_MEMORY))
{
bfd_set_error (bfd_error_invalid_operation);
- return FALSE;
+ return false;
}
if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)))
- return FALSE;
+ return false;
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
- return FALSE;
+ return false;
abfd->arch_info = &bfd_default_arch_struct;
abfd->format = bfd_unknown;
abfd->my_archive = NULL;
abfd->origin = 0;
- abfd->opened_once = FALSE;
- abfd->output_has_begun = FALSE;
+ abfd->opened_once = false;
+ abfd->output_has_begun = false;
abfd->section_count = 0;
abfd->usrdata = NULL;
- abfd->cacheable = FALSE;
+ abfd->cacheable = false;
abfd->flags |= BFD_IN_MEMORY;
- abfd->mtime_set = FALSE;
+ abfd->mtime_set = false;
- abfd->target_defaulted = TRUE;
+ abfd->target_defaulted = true;
abfd->direction = read_direction;
abfd->sections = 0;
abfd->symcount = 0;
bfd_section_list_clear (abfd);
bfd_check_format (abfd, bfd_object);
- return TRUE;
+ return true;
}
/*
ret = objalloc_alloc ((struct objalloc *) abfd->memory, ul_size);
if (ret == NULL)
bfd_set_error (bfd_error_no_memory);
+ else
+ abfd->alloc_size += size;
return ret;
}
if (!bfd_malloc_and_get_section (abfd, sect, &contents))
{
- if (contents != NULL)
- free (contents);
+ free (contents);
return NULL;
}
if (!bfd_malloc_and_get_section (abfd, sect, & contents))
{
- if (contents != NULL)
- free (contents);
+ free (contents);
return NULL;
}
separate_debug_file_exists
SYNOPSIS
- bfd_boolean separate_debug_file_exists
+ bool separate_debug_file_exists
(char *name, void *crc32_p);
DESCRIPTION
this routine is used as a @code{check_func_type} function.
*/
-static bfd_boolean
+static bool
separate_debug_file_exists (const char *name, void *crc32_p)
{
- static unsigned char buffer [8 * 1024];
+ unsigned char buffer[8 * 1024];
unsigned long file_crc = 0;
FILE *f;
bfd_size_type count;
f = _bfd_real_fopen (name, FOPEN_RB);
if (f == NULL)
- return FALSE;
+ return false;
while ((count = fread (buffer, 1, sizeof (buffer), f)) > 0)
file_crc = bfd_calc_gnu_debuglink_crc32 (file_crc, buffer, count);
separate_alt_debug_file_exists
SYNOPSIS
- bfd_boolean separate_alt_debug_file_exists
+ bool separate_alt_debug_file_exists
(char *name, void *unused);
DESCRIPTION
Checks to see if @var{name} is a file.
*/
-static bfd_boolean
+static bool
separate_alt_debug_file_exists (const char *name, void *unused ATTRIBUTE_UNUSED)
{
FILE *f;
f = _bfd_real_fopen (name, FOPEN_RB);
if (f == NULL)
- return FALSE;
+ return false;
fclose (f);
- return TRUE;
+ return true;
}
/*
SYNOPSIS
char *find_separate_debug_file
- (bfd *abfd, const char *dir, bfd_boolean include_dirs,
+ (bfd *abfd, const char *dir, bool include_dirs,
get_func_type get, check_func_type check, void *data);
DESCRIPTION
Returns NULL if no valid file could be found.
*/
-typedef char * (* get_func_type) (bfd *, void *);
-typedef bfd_boolean (* check_func_type) (const char *, void *);
+typedef char * (*get_func_type) (bfd *, void *);
+typedef bool (*check_func_type) (const char *, void *);
static char *
-find_separate_debug_file (bfd * abfd,
- const char * debug_file_directory,
- bfd_boolean include_dirs,
- get_func_type get_func,
+find_separate_debug_file (bfd *abfd,
+ const char *debug_file_directory,
+ bool include_dirs,
+ get_func_type get_func,
check_func_type check_func,
- void * func_data)
+ void *func_data)
{
char *base;
char *dir;
{
unsigned long crc32;
- return find_separate_debug_file (abfd, dir, TRUE,
+ return find_separate_debug_file (abfd, dir, true,
bfd_get_debug_link_info_1,
separate_debug_file_exists, &crc32);
}
char *
bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir)
{
- return find_separate_debug_file (abfd, dir, TRUE,
+ return find_separate_debug_file (abfd, dir, true,
get_alt_debug_link_info_shim,
separate_alt_debug_file_exists,
NULL);
bfd_fill_in_gnu_debuglink_section
SYNOPSIS
- bfd_boolean bfd_fill_in_gnu_debuglink_section
+ bool bfd_fill_in_gnu_debuglink_section
(bfd *abfd, struct bfd_section *sect, const char *filename);
DESCRIPTION
and bfd_error is set.
*/
-bfd_boolean
+bool
bfd_fill_in_gnu_debuglink_section (bfd *abfd,
struct bfd_section *sect,
const char *filename)
char * contents;
bfd_size_type crc_offset;
FILE * handle;
- static unsigned char buffer[8 * 1024];
+ unsigned char buffer[8 * 1024];
size_t count;
size_t filelen;
if (abfd == NULL || sect == NULL || filename == NULL)
{
bfd_set_error (bfd_error_invalid_operation);
- return FALSE;
+ return false;
}
/* Make sure that we can read the file.
if (handle == NULL)
{
bfd_set_error (bfd_error_system_call);
- return FALSE;
+ return false;
}
crc32 = 0;
if (contents == NULL)
{
/* XXX Should we delete the section from the bfd ? */
- return FALSE;
+ return false;
}
crc_offset = debuglink_size - 4;
{
/* XXX Should we delete the section from the bfd ? */
free (contents);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/*
if (!bfd_malloc_and_get_section (abfd, sect, & contents))
{
- if (contents != NULL)
- free (contents);
+ free (contents);
return NULL;
}
if (inote.descsz <= 0
|| inote.type != NT_GNU_BUILD_ID
|| inote.namesz != 4 /* sizeof "GNU" */
- || strncmp (inote.namedata, "GNU", 4) != 0
+ || !startswith (inote.namedata, "GNU")
|| inote.descsz > 0x7ffffffe
|| size < (12 + BFD_ALIGN (inote.namesz, 4) + inote.descsz))
{
check_build_id_file
SYNOPSIS
- bfd_boolean check_build_id_file (char *name, void *buildid_p);
+ bool check_build_id_file (char *name, void *buildid_p);
DESCRIPTION
Checks to see if @var{name} is a readable file and if its build-id
@var{build_id_p} (which is really a @code{struct bfd_build_id **}).
*/
-static bfd_boolean
+static bool
check_build_id_file (const char *name, void *buildid_p)
{
struct bfd_build_id *orig_build_id;
struct bfd_build_id *build_id;
bfd * file;
- bfd_boolean result;
+ bool result;
BFD_ASSERT (name);
BFD_ASSERT (buildid_p);
file = bfd_openr (name, NULL);
if (file == NULL)
- return FALSE;
+ return false;
/* If the file is an archive, process all of its elements. */
if (! bfd_check_format (file, bfd_object))
{
bfd_close (file);
- return FALSE;
+ return false;
}
build_id = get_build_id (file);
if (build_id == NULL)
{
bfd_close (file);
- return FALSE;
+ return false;
}
orig_build_id = *(struct bfd_build_id **) buildid_p;
{
struct bfd_build_id *build_id;
- return find_separate_debug_file (abfd, dir, FALSE,
+ return find_separate_debug_file (abfd, dir, false,
get_build_id_name,
check_build_id_file, &build_id);
}
bfd_set_filename
SYNOPSIS
- void bfd_set_filename (bfd *abfd, char *filename);
+ const char *bfd_set_filename (bfd *abfd, const char *filename);
DESCRIPTION
- Set the filename of @var{abfd}. The old filename, if any, is freed.
- @var{filename} must be allocated using @code{xmalloc}. After
- this call, it is owned @var{abfd}.
+ Set the filename of @var{abfd}, copying the FILENAME parameter to
+ bfd_alloc'd memory owned by @var{abfd}. Returns a pointer the
+ newly allocated name, or NULL if the allocation failed.
*/
-void
-bfd_set_filename (bfd *abfd, char *filename)
+const char *
+bfd_set_filename (bfd *abfd, const char *filename)
{
- free ((char *) abfd->filename);
- abfd->filename = filename;
+ size_t len = strlen (filename) + 1;
+ char *n = bfd_alloc (abfd, len);
+
+ if (n == NULL)
+ return NULL;
+
+ if (abfd->filename != NULL)
+ {
+ /* PR 29389. If we attempt to rename a file that has been closed due
+ to caching, then we will not be able to reopen it later on. */
+ if (abfd->iostream == NULL && (abfd->flags & BFD_CLOSED_BY_CACHE))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ /* Similarly if we attempt to close a renamed file because the
+ cache is now full, we will not be able to reopen it later on. */
+ if (abfd->iostream != NULL)
+ abfd->cacheable = 0;
+ }
+
+ memcpy (n, filename, len);
+ abfd->filename = n;
+
+ return n;
}