#include "bfd.h"
#include "sysdep.h"
#include "objalloc.h"
#include "libbfd.h"
#if USE_MMAP
#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE
#include <sys/types.h>
#include <sys/mman.h>
#endif
#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE
#include <sys/types.h>
#include <sys/mman.h>
#endif
#undef MAP_SHARED
#define MAP_SHARED MAP_PRIVATE
#ifndef MAP_FILE
#define MAP_FILE 0
#endif
#endif
#ifndef S_IXUSR
#define S_IXUSR 0100
#endif
#ifndef S_IXGRP
#define S_IXGRP 0010
#endif
#ifndef S_IXOTH
#define S_IXOTH 0001
#endif
static unsigned int _bfd_id_counter = 0;
bfd *
_bfd_new_bfd ()
{
bfd *nbfd;
nbfd = (bfd *) bfd_zmalloc ((bfd_size_type) sizeof (bfd));
if (nbfd == NULL)
return NULL;
nbfd->id = _bfd_id_counter++;
nbfd->memory = (PTR) objalloc_create ();
if (nbfd->memory == NULL)
{
bfd_set_error (bfd_error_no_memory);
free (nbfd);
return NULL;
}
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,
251))
{
free (nbfd);
return NULL;
}
nbfd->sections = (asection *) NULL;
nbfd->section_tail = &nbfd->sections;
nbfd->format = bfd_unknown;
nbfd->my_archive = (bfd *) NULL;
nbfd->origin = 0;
nbfd->opened_once = FALSE;
nbfd->output_has_begun = FALSE;
nbfd->section_count = 0;
nbfd->usrdata = (PTR) NULL;
nbfd->cacheable = FALSE;
nbfd->flags = BFD_NO_FLAGS;
nbfd->mtime_set = FALSE;
return nbfd;
}
bfd *
_bfd_new_bfd_contained_in (obfd)
bfd *obfd;
{
bfd *nbfd;
nbfd = _bfd_new_bfd ();
if (nbfd == NULL)
return NULL;
nbfd->xvec = obfd->xvec;
nbfd->my_archive = obfd;
nbfd->direction = read_direction;
nbfd->target_defaulted = obfd->target_defaulted;
return nbfd;
}
void
_bfd_delete_bfd (abfd)
bfd *abfd;
{
bfd_hash_table_free (&abfd->section_htab);
objalloc_free ((struct objalloc *) abfd->memory);
memset (abfd, '\0', sizeof (bfd));
free (abfd);
}
bfd *
bfd_openr (filename, target)
const char *filename;
const char *target;
{
bfd *nbfd;
const bfd_target *target_vec;
nbfd = _bfd_new_bfd ();
if (nbfd == NULL)
return NULL;
target_vec = bfd_find_target (target, nbfd);
if (target_vec == NULL)
{
_bfd_delete_bfd (nbfd);
return NULL;
}
nbfd->filename = filename;
nbfd->direction = read_direction;
if (bfd_open_file (nbfd) == NULL)
{
bfd_set_error (bfd_error_system_call);
_bfd_delete_bfd (nbfd);
return NULL;
}
return nbfd;
}
bfd_boolean bfd_mmap_file (abfd, addr)
bfd *abfd ATTRIBUTE_UNUSED;
void *addr ATTRIBUTE_UNUSED;
{
#if USE_MMAP
struct bfd_in_memory *mem;
struct stat statbuf;
FILE *fp;
int fd;
unsigned int prot;
unsigned int flags;
BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) == 0);
abfd->mtime = bfd_get_mtime (abfd);
mem = bfd_alloc (abfd, sizeof (struct bfd_in_memory));
if (mem == NULL) {
return FALSE;
}
fp = bfd_cache_lookup (abfd);
fd = fileno (fp);
if (fstat (fd, &statbuf) != 0) {
bfd_set_error (bfd_error_system_call);
return FALSE;
}
mem->size = statbuf.st_size;
switch (abfd->direction) {
case no_direction:
prot = 0;
flags = MAP_FILE | MAP_SHARED;
break;
case read_direction:
prot = PROT_READ;
flags = MAP_FILE | MAP_SHARED;
break;
case write_direction:
case both_direction:
prot = PROT_READ | PROT_WRITE;
flags = MAP_FILE | MAP_SHARED;
break;
default:
abort ();
}
if (addr != ((void *) -1)) {
flags |= MAP_FIXED;
} else {
addr = NULL;
}
mem->buffer = mmap (addr, mem->size, prot, flags, fd, 0);
if ((caddr_t) mem->buffer == (caddr_t) -1) {
bfd_set_error (bfd_error_system_call);
return FALSE;
}
BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) == 0);
bfd_cache_close (abfd);
abfd->iostream = mem;
abfd->flags |= BFD_IN_MEMORY;
return TRUE;
#else
bfd_set_error (bfd_error_system_call);
return FALSE;
#endif
}
bfd *
bfd_funopenr (filename, target, fdata)
const char *filename;
const char *target;
struct bfd_io_functions *fdata;
{
bfd *nbfd;
const bfd_target *target_vec;
struct bfd_io_functions *fun;
nbfd = _bfd_new_bfd ();
if (nbfd == NULL)
return NULL;
fun = bfd_alloc (nbfd, sizeof (struct bfd_io_functions));
if (fun == NULL)
return NULL;
target_vec = bfd_find_target (target, nbfd);
if (target_vec == NULL)
{
objalloc_free ((struct objalloc *) nbfd->memory);
free (nbfd);
bfd_set_error (bfd_error_invalid_target);
return NULL;
}
*fun = *fdata;
nbfd->filename = filename;
nbfd->direction = read_direction;
nbfd->iostream = fun;
nbfd->flags |= BFD_IO_FUNCS;
return nbfd;
}
bfd *
bfd_memopenr (filename, target, addr, len)
const char *filename;
const char *target;
unsigned char *addr;
bfd_size_type len;
{
bfd *nbfd;
const bfd_target *target_vec;
struct bfd_in_memory *mem;
nbfd = _bfd_new_bfd ();
if (nbfd == NULL)
return NULL;
mem = bfd_alloc (nbfd, sizeof (struct bfd_in_memory));
if (mem == NULL)
return NULL;
target_vec = bfd_find_target (target, nbfd);
if (target_vec == NULL)
{
objalloc_free ((struct objalloc *) nbfd->memory);
free (nbfd);
bfd_set_error (bfd_error_invalid_target);
return NULL;
}
mem->buffer = addr;
mem->size = len;
nbfd->filename = filename;
nbfd->direction = read_direction;
nbfd->iostream = mem;
nbfd->flags |= BFD_IN_MEMORY;
return nbfd;
}
bfd *
bfd_fdopenr (filename, target, fd)
const char *filename;
const char *target;
int fd;
{
bfd *nbfd;
const bfd_target *target_vec;
int fdflags;
bfd_set_error (bfd_error_system_call);
#if ! defined(HAVE_FCNTL) || ! defined(F_GETFL)
fdflags = O_RDWR;
#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);
return NULL;
}
#ifndef HAVE_FDOPEN
nbfd->iostream = (PTR) fopen (filename, FOPEN_RB);
#else
switch (fdflags & (O_ACCMODE))
{
case O_RDONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RB); break;
case O_WRONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break;
case O_RDWR: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break;
default: abort ();
}
#endif
if (nbfd->iostream == NULL)
{
_bfd_delete_bfd (nbfd);
return NULL;
}
nbfd->filename = filename;
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;
}
bfd *
bfd_openstreamr (filename, target, streamarg)
const char *filename;
const char *target;
PTR streamarg;
{
FILE *stream = (FILE *) streamarg;
bfd *nbfd;
const bfd_target *target_vec;
nbfd = _bfd_new_bfd ();
if (nbfd == NULL)
return NULL;
target_vec = bfd_find_target (target, nbfd);
if (target_vec == NULL)
{
_bfd_delete_bfd (nbfd);
return NULL;
}
nbfd->iostream = (PTR) stream;
nbfd->filename = filename;
nbfd->direction = read_direction;
if (! bfd_cache_init (nbfd))
{
_bfd_delete_bfd (nbfd);
return NULL;
}
return nbfd;
}
bfd *
bfd_openw (filename, target)
const char *filename;
const char *target;
{
bfd *nbfd;
const bfd_target *target_vec;
nbfd = _bfd_new_bfd ();
if (nbfd == NULL)
return NULL;
target_vec = bfd_find_target (target, nbfd);
if (target_vec == NULL)
{
_bfd_delete_bfd (nbfd);
return NULL;
}
nbfd->filename = filename;
nbfd->direction = write_direction;
if (bfd_open_file (nbfd) == NULL)
{
bfd_set_error (bfd_error_system_call);
_bfd_delete_bfd (nbfd);
return NULL;
}
return nbfd;
}
bfd_boolean
bfd_close (abfd)
bfd *abfd;
{
bfd_boolean ret = TRUE;
if (bfd_write_p (abfd))
{
if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)))
return FALSE;
}
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
return FALSE;
ret = _bfd_io_close (abfd);
_bfd_delete_bfd (abfd);
return ret;
}
bfd_boolean
bfd_close_all_done (abfd)
bfd *abfd;
{
bfd_boolean ret;
ret = _bfd_io_close (abfd);
if (ret
&& abfd->direction == write_direction
&& abfd->flags & EXEC_P)
{
struct stat buf;
if (stat (abfd->filename, &buf) == 0)
{
unsigned int mask = umask (0);
umask (mask);
chmod (abfd->filename,
(0777
& (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask))));
}
}
_bfd_delete_bfd (abfd);
return ret;
}
bfd *
bfd_create (filename, templ)
const char *filename;
bfd *templ;
{
bfd *nbfd;
nbfd = _bfd_new_bfd ();
if (nbfd == NULL)
return NULL;
nbfd->filename = filename;
if (templ)
nbfd->xvec = templ->xvec;
nbfd->direction = no_direction;
bfd_set_format (nbfd, bfd_object);
return nbfd;
}
bfd_boolean
bfd_make_writable(abfd)
bfd *abfd;
{
struct bfd_in_memory *bim;
if (abfd->direction != no_direction)
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
bim = ((struct bfd_in_memory *)
bfd_malloc ((bfd_size_type) sizeof (struct bfd_in_memory)));
abfd->iostream = (PTR) bim;
bim->size = 0;
bim->buffer = 0;
abfd->flags |= BFD_IN_MEMORY;
abfd->direction = write_direction;
abfd->where = 0;
return TRUE;
}
bfd_boolean
bfd_make_readable(abfd)
bfd *abfd;
{
if (abfd->direction != write_direction || !(abfd->flags & BFD_IN_MEMORY))
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)))
return FALSE;
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
return FALSE;
abfd->arch_info = &bfd_default_arch_struct;
abfd->where = 0;
abfd->format = bfd_unknown;
abfd->my_archive = (bfd *) NULL;
abfd->origin = 0;
abfd->opened_once = FALSE;
abfd->output_has_begun = FALSE;
abfd->section_count = 0;
abfd->usrdata = (PTR) NULL;
abfd->cacheable = FALSE;
abfd->flags = BFD_IN_MEMORY;
abfd->mtime_set = FALSE;
abfd->target_defaulted = TRUE;
abfd->direction = read_direction;
abfd->sections = 0;
abfd->symcount = 0;
abfd->outsymbols = 0;
abfd->tdata.any = 0;
bfd_section_list_clear (abfd);
bfd_check_format (abfd, bfd_object);
return TRUE;
}
PTR
bfd_alloc (abfd, size)
bfd *abfd;
bfd_size_type size;
{
PTR ret;
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;
}
PTR
bfd_zalloc (abfd, size)
bfd *abfd;
bfd_size_type size;
{
PTR res;
res = bfd_alloc (abfd, size);
if (res)
memset (res, 0, (size_t) size);
return res;
}
void
bfd_release (abfd, block)
bfd *abfd;
PTR block;
{
objalloc_free_block ((struct objalloc *) abfd->memory, block);
}