/* opncls.c -- open and close a BFD.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
- 2001, 2002, 2003
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Written by Cygnus Support.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "objalloc.h"
#include "libbfd.h"
#include "libiberty.h"
nbfd->iostream = NULL;
nbfd->where = 0;
if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc,
- 251))
+ sizeof (struct section_hash_entry), 251))
{
free (nbfd);
return NULL;
}
nbfd->sections = NULL;
- nbfd->section_tail = &nbfd->sections;
+ nbfd->section_last = NULL;
nbfd->format = bfd_unknown;
nbfd->my_archive = NULL;
nbfd->origin = 0;
void
_bfd_delete_bfd (bfd *abfd)
{
- bfd_hash_table_free (&abfd->section_htab);
- objalloc_free ((struct objalloc *) abfd->memory);
+ if (abfd->memory)
+ {
+ bfd_hash_table_free (&abfd->section_htab);
+ objalloc_free ((struct objalloc *) abfd->memory);
+ }
free (abfd);
}
+/* Free objalloc memory. */
+
+bfd_boolean
+_bfd_free_cached_info (bfd *abfd)
+{
+ if (abfd->memory)
+ {
+ bfd_hash_table_free (&abfd->section_htab);
+ objalloc_free ((struct objalloc *) abfd->memory);
+
+ abfd->sections = NULL;
+ abfd->section_last = NULL;
+ abfd->outsymbols = NULL;
+ abfd->tdata.any = NULL;
+ abfd->usrdata = NULL;
+ abfd->memory = NULL;
+ }
+
+ return TRUE;
+}
+
/*
SECTION
Opening and closing BFDs
+SUBSECTION
+ Functions for opening and closing
*/
/*
FUNCTION
- bfd_openr
+ bfd_fopen
SYNOPSIS
- bfd *bfd_openr (const char *filename, const char *target);
+ bfd *bfd_fopen (const char *filename, const char *target,
+ const char *mode, int fd);
DESCRIPTION
- Open the file @var{filename} (using <<fopen>>) with the target
- @var{target}. Return a pointer to the created BFD.
+ Open the file @var{filename} with the target @var{target}.
+ 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>>.
Calls <<bfd_find_target>>, so @var{target} is interpreted as by
that function.
+ The new BFD is marked as cacheable iff @var{fd} is -1.
+
If <<NULL>> is returned then an error has occured. Possible errors
are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or
<<system_call>> error.
*/
bfd *
-bfd_openr (const char *filename, const char *target)
+bfd_fopen (const char *filename, const char *target, const char *mode, int fd)
{
bfd *nbfd;
const bfd_target *target_vec;
_bfd_delete_bfd (nbfd);
return NULL;
}
+
+#ifdef HAVE_FDOPEN
+ if (fd != -1)
+ nbfd->iostream = fdopen (fd, mode);
+ else
+#endif
+ nbfd->iostream = real_fopen (filename, mode);
+ if (nbfd->iostream == NULL)
+ {
+ bfd_set_error (bfd_error_system_call);
+ _bfd_delete_bfd (nbfd);
+ return NULL;
+ }
+ /* OK, put everything where it belongs. */
nbfd->filename = filename;
- nbfd->direction = read_direction;
- if (bfd_open_file (nbfd) == NULL)
+ /* 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')
+ && mode[1] == '+')
+ nbfd->direction = both_direction;
+ else if (mode[0] == 'r')
+ nbfd->direction = read_direction;
+ else
+ nbfd->direction = write_direction;
+
+ if (! bfd_cache_init (nbfd))
{
- /* File didn't exist, or some such. */
- bfd_set_error (bfd_error_system_call);
_bfd_delete_bfd (nbfd);
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);
return nbfd;
}
+/*
+FUNCTION
+ bfd_openr
+
+SYNOPSIS
+ bfd *bfd_openr (const char *filename, const char *target);
+
+DESCRIPTION
+ Open the file @var{filename} (using <<fopen>>) with the target
+ @var{target}. Return a pointer to the created BFD.
+
+ Calls <<bfd_find_target>>, so @var{target} is interpreted as by
+ that function.
+
+ If <<NULL>> is returned then an error has occured. Possible errors
+ are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or
+ <<system_call>> error.
+*/
+
+bfd *
+bfd_openr (const char *filename, const char *target)
+{
+ return bfd_fopen (filename, target, FOPEN_RB, -1);
+}
+
/* Don't try to `optimize' this function:
o - We lock using stack space so that interrupting the locking
bfd *
bfd_fdopenr (const char *filename, const char *target, int fd)
{
- bfd *nbfd;
- const bfd_target *target_vec;
+ const char *mode;
+#if defined(HAVE_FCNTL) && defined(F_GETFL)
int fdflags;
+#endif
- bfd_set_error (bfd_error_system_call);
#if ! defined(HAVE_FCNTL) || ! defined(F_GETFL)
- fdflags = O_RDWR; /* Assume full access. */
+ mode = FOPEN_RUB; /* Assume full access. */
#else
fdflags = fcntl (fd, F_GETFL, NULL);
-#endif
if (fdflags == -1)
- return NULL;
-
- nbfd = _bfd_new_bfd ();
- if (nbfd == NULL)
- return NULL;
-
- target_vec = bfd_find_target (target, nbfd);
- if (target_vec == NULL)
{
- _bfd_delete_bfd (nbfd);
+ bfd_set_error (bfd_error_system_call);
return NULL;
}
-#ifndef HAVE_FDOPEN
- nbfd->iostream = fopen (filename, FOPEN_RB);
-#else
/* (O_ACCMODE) parens are to avoid Ultrix header file bug. */
switch (fdflags & (O_ACCMODE))
{
- case O_RDONLY: nbfd->iostream = fdopen (fd, FOPEN_RB); break;
- case O_WRONLY: nbfd->iostream = fdopen (fd, FOPEN_RUB); break;
- case O_RDWR: nbfd->iostream = fdopen (fd, FOPEN_RUB); break;
+ case O_RDONLY: mode = FOPEN_RB; break;
+ case O_WRONLY: mode = FOPEN_RUB; break;
+ case O_RDWR: mode = FOPEN_RUB; break;
default: abort ();
}
#endif
- if (nbfd->iostream == NULL)
- {
- _bfd_delete_bfd (nbfd);
- return NULL;
- }
-
- /* OK, put everything where it belongs. */
- nbfd->filename = filename;
-
- /* As a special case we allow a FD open for read/write to
- be written through, although doing so requires that we end
- the previous clause with a preposition. */
- /* (O_ACCMODE) parens are to avoid Ultrix header file bug. */
- switch (fdflags & (O_ACCMODE))
- {
- case O_RDONLY: nbfd->direction = read_direction; break;
- case O_WRONLY: nbfd->direction = write_direction; break;
- case O_RDWR: nbfd->direction = both_direction; break;
- default: abort ();
- }
-
- if (! bfd_cache_init (nbfd))
- {
- _bfd_delete_bfd (nbfd);
- return NULL;
- }
- nbfd->opened_once = TRUE;
-
- return nbfd;
+ return bfd_fopen (filename, target, mode, fd);
}
/*
file_ptr nbytes,
file_ptr offset),
int (*close) (struct bfd *nbfd,
- void *stream));
+ void *stream),
+ int (*stat) (struct bfd *abfd,
+ void *stream,
+ struct stat *sb));
DESCRIPTION
<<bfd_close>>. @var{close} either succeeds returning 0, or
fails returning -1 (setting <<bfd_error>>).
+ Calls @var{stat} to fill in a stat structure for bfd_stat,
+ bfd_get_size, and bfd_get_mtime calls. @var{stat} returns 0
+ on success, or returns -1 on failure (setting <<bfd_error>>).
+
If <<bfd_openr_iovec>> returns <<NULL>> then an error has
occurred. Possible errors are <<bfd_error_no_memory>>,
<<bfd_error_invalid_target>> and <<bfd_error_system_call>>.
file_ptr (*pread) (struct bfd *abfd, void *stream, void *buf,
file_ptr nbytes, file_ptr offset);
int (*close) (struct bfd *abfd, void *stream);
+ int (*stat) (struct bfd *abfd, void *stream, struct stat *sb);
file_ptr where;
};
opncls_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
{
struct opncls *vec = abfd->iostream;
- file_ptr nread = vec->pread (abfd, vec->stream, buf, nbytes, vec->where);
+ file_ptr nread = (vec->pread) (abfd, vec->stream, buf, nbytes, vec->where);
if (nread < 0)
return nread;
vec->where += nread;
free it. */
int status = 0;
if (vec->close != NULL)
- status = vec->close (abfd, vec->stream);
+ status = (vec->close) (abfd, vec->stream);
abfd->iostream = NULL;
return status;
}
}
static int
-opncls_bstat (struct bfd *abfd ATTRIBUTE_UNUSED, struct stat *sb)
+opncls_bstat (struct bfd *abfd, struct stat *sb)
{
+ struct opncls *vec = abfd->iostream;
+
memset (sb, 0, sizeof (*sb));
- return 0;
+ if (vec->stat == NULL)
+ return 0;
+
+ return (vec->stat) (abfd, vec->stream, sb);
}
static const struct bfd_iovec opncls_iovec = {
file_ptr nbytes,
file_ptr offset),
int (*close) (struct bfd *nbfd,
- void *stream))
+ void *stream),
+ int (*stat) (struct bfd *abfd,
+ void *stream,
+ struct stat *sb))
{
bfd *nbfd;
const bfd_target *target_vec;
vec->stream = stream;
vec->pread = pread;
vec->close = close;
+ vec->stat = stat;
nbfd->iovec = &opncls_iovec;
nbfd->iostream = vec;
if (!(abfd->flags & BFD_IN_MEMORY))
ret = abfd->iovec->bclose (abfd);
else
- ret = 0;
+ ret = TRUE;
/* If the file was open for writing and is now executable,
make it so. */
<<abfd>> and return a pointer to it.
*/
-
void *
bfd_alloc (bfd *abfd, bfd_size_type size)
{
return ret;
}
+/*
+INTERNAL_FUNCTION
+ bfd_alloc2
+
+SYNOPSIS
+ void *bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
+
+DESCRIPTION
+ Allocate a block of @var{nmemb} elements of @var{size} bytes each
+ of memory attached to <<abfd>> and return a pointer to it.
+*/
+
+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)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ size *= nmemb;
+
+ if (size != (unsigned long) size)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ ret = objalloc_alloc (abfd->memory, (unsigned long) size);
+ if (ret == NULL)
+ bfd_set_error (bfd_error_no_memory);
+ return ret;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_zalloc
+
+SYNOPSIS
+ void *bfd_zalloc (bfd *abfd, bfd_size_type wanted);
+
+DESCRIPTION
+ Allocate a block of @var{wanted} bytes of zeroed memory
+ attached to <<abfd>> and return a pointer to it.
+*/
+
void *
bfd_zalloc (bfd *abfd, bfd_size_type size)
{
return res;
}
+/*
+INTERNAL_FUNCTION
+ bfd_zalloc2
+
+SYNOPSIS
+ void *bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
+
+DESCRIPTION
+ Allocate a block of @var{nmemb} elements of @var{size} bytes each
+ of zeroed memory attached to <<abfd>> and return a pointer to it.
+*/
+
+void *
+bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size)
+{
+ void *res;
+
+ if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
+ && size != 0
+ && nmemb > ~(bfd_size_type) 0 / size)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ size *= nmemb;
+
+ res = bfd_alloc (abfd, size);
+ if (res)
+ memset (res, 0, (size_t) size);
+ return res;
+}
+
/* Free a block allocated for a BFD.
Note: Also frees all more recently allocated blocks! */
}
-/*
- GNU Extension: separate debug-info files
-
+/*
+ GNU Extension: separate debug-info files
+
The idea here is that a special section called .gnu_debuglink might be
embedded in a binary file, which indicates that some *other* file
contains the real debugging information. This special section contains a
RETURNS
Return the updated CRC32 value.
-*/
+*/
unsigned long
bfd_calc_gnu_debuglink_crc32 (unsigned long crc,
static char *
get_debug_link_info (bfd *abfd, unsigned long *crc32_out)
{
- asection * sect;
- bfd_size_type debuglink_size;
+ asection *sect;
unsigned long crc32;
- char * contents;
+ bfd_byte *contents;
int crc_offset;
- bfd_boolean ret;
+ char *name;
BFD_ASSERT (abfd);
BFD_ASSERT (crc32_out);
if (sect == NULL)
return NULL;
- debuglink_size = bfd_section_size (abfd, sect);
-
- contents = malloc (debuglink_size);
- if (contents == NULL)
- return NULL;
-
- ret = bfd_get_section_contents (abfd, sect, contents, 0, debuglink_size);
- if (! ret)
+ if (!bfd_malloc_and_get_section (abfd, sect, &contents))
{
- free (contents);
+ if (contents != NULL)
+ free (contents);
return NULL;
}
/* Crc value is stored after the filename, aligned up to 4 bytes. */
- crc_offset = strlen (contents) + 1;
+ name = (char *) contents;
+ crc_offset = strlen (name) + 1;
crc_offset = (crc_offset + 3) & ~3;
crc32 = bfd_get_32 (abfd, contents + crc_offset);
*crc32_out = crc32;
- return contents;
+ return name;
}
/*
static bfd_boolean
separate_debug_file_exists (const char *name, const unsigned long crc)
{
- static char buffer [8 * 1024];
+ static unsigned char buffer [8 * 1024];
unsigned long file_crc = 0;
int fd;
bfd_size_type count;
return NULL;
}
BFD_ASSERT (strlen (dir) != 0);
-
+
/* Strip off filename part. */
for (i = strlen (dir) - 1; i >= 0; i--)
if (IS_DIR_SEPARATOR (dir[i]))
break;
dir[i + 1] = '\0';
- BFD_ASSERT (dir[i] == '/' || dir[0] == '\0')
+ BFD_ASSERT (dir[i] == '/' || dir[0] == '\0');
debugfile = malloc (strlen (debug_file_directory) + 1
+ strlen (dir)
+ strlen (".debug/")
- + strlen (basename)
+ + strlen (basename)
+ 1);
if (debugfile == NULL)
{
char *
bfd_follow_gnu_debuglink (bfd *abfd, const char *dir)
{
-#if 0 /* Disabled until DEBUGDIR can be defined by configure.in. */
- if (dir == NULL)
- dir = DEBUGDIR;
-#endif
return find_separate_debug_file (abfd, dir);
}
RETURNS
A pointer to the new section is returned if all is ok. Otherwise <<NULL>> is
- returned and bfd_error is set.
+ returned and bfd_error is set.
*/
asection *
{
asection *sect;
bfd_size_type debuglink_size;
+ flagword flags;
if (abfd == NULL || filename == NULL)
{
/* Strip off any path components in filename. */
filename = lbasename (filename);
-
+
sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK);
if (sect)
{
return NULL;
}
- sect = bfd_make_section (abfd, GNU_DEBUGLINK);
+ flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING;
+ sect = bfd_make_section_with_flags (abfd, GNU_DEBUGLINK, flags);
if (sect == NULL)
return NULL;
- if (! bfd_set_section_flags (abfd, sect,
- SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING))
- /* XXX Should we delete the section from the bfd ? */
- return NULL;
-
-
debuglink_size = strlen (filename) + 1;
debuglink_size += 3;
debuglink_size &= ~3;
if (! bfd_set_section_size (abfd, sect, debuglink_size))
/* XXX Should we delete the section from the bfd ? */
return NULL;
-
+
return sect;
}
RETURNS
<<TRUE>> is returned if all is ok. Otherwise <<FALSE>> is returned
- and bfd_error is set.
+ and bfd_error is set.
*/
bfd_boolean
char * contents;
bfd_size_type crc_offset;
FILE * handle;
- static char buffer[8 * 1024];
+ static unsigned char buffer[8 * 1024];
size_t count;
if (abfd == NULL || sect == NULL || filename == NULL)
.gnu_debuglink section, we insist upon the user providing us with a
correct-for-section-creation-time path, but this need not conform to
the gdb location algorithm. */
- handle = fopen (filename, FOPEN_RB);
+ handle = real_fopen (filename, FOPEN_RB);
if (handle == NULL)
{
bfd_set_error (bfd_error_system_call);
/* Strip off any path components in filename,
now that we no longer need them. */
filename = lbasename (filename);
-
+
debuglink_size = strlen (filename) + 1;
debuglink_size += 3;
debuglink_size &= ~3;