X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fbfdio.c;h=792ccdab923a98328f08e41a588190136213502c;hb=5430098f1807e084fe4ff5057040d68435f3d8a2;hp=7cba51ff83726f193e0ce01909004a47eef615ef;hpb=d387240a63cfb5562d2fd7c6273bbc62f4383284;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/bfdio.c b/bfd/bfdio.c index 7cba51ff83..792ccdab92 100644 --- a/bfd/bfdio.c +++ b/bfd/bfdio.c @@ -1,8 +1,6 @@ /* Low-level I/O routines for BFDs. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 - Free Software Foundation, Inc. + Copyright (C) 1990-2017 Free Software Foundation, Inc. Written by Cygnus Support. @@ -43,7 +41,7 @@ #endif file_ptr -real_ftell (FILE *file) +_bfd_real_ftell (FILE *file) { #if defined (HAVE_FTELLO64) return ftello64 (file); @@ -55,7 +53,7 @@ real_ftell (FILE *file) } int -real_fseek (FILE *file, file_ptr offset, int whence) +_bfd_real_fseek (FILE *file, file_ptr offset, int whence) { #if defined (HAVE_FSEEKO64) return fseeko64 (file, offset, whence); @@ -84,13 +82,12 @@ close_on_exec (FILE *file) } FILE * -real_fopen (const char *filename, const char *modes) +_bfd_real_fopen (const char *filename, const char *modes) { #ifdef VMS - char vms_modes[4]; char *vms_attr; - /* On VMS, fopen allows file attributes as optionnal arguments. + /* On VMS, fopen allows file attributes as optional arguments. We need to use them but we'd better to use the common prototype. In fopen-vms.h, they are separated from the mode with a comma. Split here. */ @@ -102,13 +99,21 @@ real_fopen (const char *filename, const char *modes) } else { - /* Attribute found - rebuild modes. */ - size_t modes_len = vms_attr - modes; - - BFD_ASSERT (modes_len < sizeof (vms_modes)); - memcpy (vms_modes, modes, modes_len); - vms_modes[modes_len] = 0; - return close_on_exec (fopen (filename, vms_modes, vms_attr + 1)); + /* Attributes found. Split. */ + size_t modes_len = strlen (modes) + 1; + char attrs[modes_len + 1]; + char *at[3]; + int i; + + memcpy (attrs, modes, modes_len); + at[0] = attrs; + for (i = 0; i < 2; i++) + { + at[i + 1] = strchr (at[i], ','); + BFD_ASSERT (at[i + 1] != NULL); + *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it. */ + } + return close_on_exec (fopen (filename, at[0], at[1], at[2])); } #else /* !VMS */ #if defined (HAVE_FOPEN64) @@ -150,8 +155,19 @@ DESCRIPTION . int (*bclose) (struct bfd *abfd); . int (*bflush) (struct bfd *abfd); . int (*bstat) (struct bfd *abfd, struct stat *sb); +. {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual +. mmap parameter, except that LEN and OFFSET do not need to be page +. aligned. Returns (void *)-1 on failure, mmapped address on success. +. Also write in MAP_ADDR the address of the page aligned buffer and in +. MAP_LEN the size mapped (a page multiple). Use unmap with MAP_ADDR and +. MAP_LEN to unmap. *} +. void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len, +. int prot, int flags, file_ptr offset, +. void **map_addr, bfd_size_type *map_len); .}; +.extern const struct bfd_iovec _bfd_memory_iovec; + */ @@ -166,29 +182,14 @@ bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) this element. */ if (abfd->arelt_data != NULL) { - size_t maxbytes = ((struct areltdata *) abfd->arelt_data)->parsed_size; - if (size > maxbytes) - size = maxbytes; - } - - if ((abfd->flags & BFD_IN_MEMORY) != 0) - { - struct bfd_in_memory *bim; - bfd_size_type get; - - bim = abfd->iostream; - get = size; - if (abfd->where + get > bim->size) - { - if (bim->size < (bfd_size_type) abfd->where) - get = 0; - else - get = bim->size - abfd->where; - bfd_set_error (bfd_error_file_truncated); - } - memcpy (ptr, bim->buffer + abfd->where, (size_t) get); - abfd->where += get; - return get; + bfd_size_type maxbytes = arelt_size (abfd); + + if (abfd->where + size > maxbytes) + { + if (abfd->where >= maxbytes) + return 0; + size = maxbytes - abfd->where; + } } if (abfd->iovec) @@ -206,34 +207,6 @@ bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) { size_t nwrote; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - { - struct bfd_in_memory *bim = abfd->iostream; - - size = (size_t) size; - if (abfd->where + size > bim->size) - { - bfd_size_type newsize, oldsize; - - oldsize = (bim->size + 127) & ~(bfd_size_type) 127; - bim->size = abfd->where + size; - /* Round up to cut down on memory fragmentation */ - newsize = (bim->size + 127) & ~(bfd_size_type) 127; - if (newsize > oldsize) - { - bim->buffer = bfd_realloc_or_free (bim->buffer, newsize); - if (bim->buffer == NULL) - { - bim->size = 0; - return 0; - } - } - } - memcpy (bim->buffer + abfd->where, ptr, (size_t) size); - abfd->where += size; - return size; - } - if (abfd->iovec) nwrote = abfd->iovec->bwrite (abfd, ptr, size); else @@ -256,15 +229,17 @@ bfd_tell (bfd *abfd) { file_ptr ptr; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - return abfd->where; - if (abfd->iovec) { + bfd *parent_bfd = abfd; ptr = abfd->iovec->btell (abfd); - if (abfd->my_archive) - ptr -= abfd->origin; + while (parent_bfd->my_archive != NULL + && !bfd_is_thin_archive (parent_bfd->my_archive)) + { + ptr -= parent_bfd->origin; + parent_bfd = parent_bfd->my_archive; + } } else ptr = 0; @@ -276,9 +251,6 @@ bfd_tell (bfd *abfd) int bfd_flush (bfd *abfd) { - if ((abfd->flags & BFD_IN_MEMORY) != 0) - return 0; - if (abfd->iovec) return abfd->iovec->bflush (abfd); return 0; @@ -291,9 +263,6 @@ bfd_stat (bfd *abfd, struct stat *statbuf) { int result; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - abort (); - if (abfd->iovec) result = abfd->iovec->bstat (abfd, statbuf); else @@ -321,49 +290,7 @@ bfd_seek (bfd *abfd, file_ptr position, int direction) if (direction == SEEK_CUR && position == 0) return 0; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - { - struct bfd_in_memory *bim; - - bim = abfd->iostream; - - if (direction == SEEK_SET) - abfd->where = position; - else - abfd->where += position; - - if (abfd->where > bim->size) - { - if ((abfd->direction == write_direction) || - (abfd->direction == both_direction)) - { - bfd_size_type newsize, oldsize; - - oldsize = (bim->size + 127) & ~(bfd_size_type) 127; - bim->size = abfd->where; - /* Round up to cut down on memory fragmentation */ - newsize = (bim->size + 127) & ~(bfd_size_type) 127; - if (newsize > oldsize) - { - bim->buffer = bfd_realloc_or_free (bim->buffer, newsize); - if (bim->buffer == NULL) - { - bim->size = 0; - return -1; - } - } - } - else - { - abfd->where = bim->size; - bfd_set_error (bfd_error_file_truncated); - return -1; - } - } - return 0; - } - - if (abfd->format != bfd_archive && abfd->my_archive == 0) + if (abfd->my_archive == NULL || bfd_is_thin_archive (abfd->my_archive)) { if (direction == SEEK_SET && (bfd_vma) position == abfd->where) return 0; @@ -384,8 +311,17 @@ bfd_seek (bfd *abfd, file_ptr position, int direction) } file_position = position; - if (direction == SEEK_SET && abfd->my_archive != NULL) - file_position += abfd->origin; + if (direction == SEEK_SET) + { + bfd *parent_bfd = abfd; + + while (parent_bfd->my_archive != NULL + && !bfd_is_thin_archive (parent_bfd->my_archive)) + { + file_position += parent_bfd->origin; + parent_bfd = parent_bfd->my_archive; + } + } if (abfd->iovec) result = abfd->iovec->bseek (abfd, file_position, direction); @@ -489,9 +425,6 @@ bfd_get_size (bfd *abfd) { struct stat buf; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - return ((struct bfd_in_memory *) abfd->iostream)->size; - if (abfd->iovec == NULL) return 0; @@ -500,3 +433,191 @@ bfd_get_size (bfd *abfd) return buf.st_size; } + + +/* +FUNCTION + bfd_mmap + +SYNOPSIS + void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, + int prot, int flags, file_ptr offset, + void **map_addr, bfd_size_type *map_len); + +DESCRIPTION + Return mmap()ed region of the file, if possible and implemented. + LEN and OFFSET do not need to be page aligned. The page aligned + address and length are written to MAP_ADDR and MAP_LEN. + +*/ + +void * +bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, + int prot, int flags, file_ptr offset, + void **map_addr, bfd_size_type *map_len) +{ + void *ret = (void *)-1; + + if (abfd->iovec == NULL) + return ret; + + return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset, + map_addr, map_len); +} + +/* Memory file I/O operations. */ + +static file_ptr +memory_bread (bfd *abfd, void *ptr, file_ptr size) +{ + struct bfd_in_memory *bim; + bfd_size_type get; + + bim = (struct bfd_in_memory *) abfd->iostream; + get = size; + if (abfd->where + get > bim->size) + { + if (bim->size < (bfd_size_type) abfd->where) + get = 0; + else + get = bim->size - abfd->where; + bfd_set_error (bfd_error_file_truncated); + } + memcpy (ptr, bim->buffer + abfd->where, (size_t) get); + return get; +} + +static file_ptr +memory_bwrite (bfd *abfd, const void *ptr, file_ptr size) +{ + struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; + + if (abfd->where + size > bim->size) + { + bfd_size_type newsize, oldsize; + + oldsize = (bim->size + 127) & ~(bfd_size_type) 127; + bim->size = abfd->where + size; + /* Round up to cut down on memory fragmentation */ + newsize = (bim->size + 127) & ~(bfd_size_type) 127; + if (newsize > oldsize) + { + bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize); + if (bim->buffer == NULL) + { + bim->size = 0; + return 0; + } + if (newsize > bim->size) + memset (bim->buffer + bim->size, 0, newsize - bim->size); + } + } + memcpy (bim->buffer + abfd->where, ptr, (size_t) size); + return size; +} + +static file_ptr +memory_btell (bfd *abfd) +{ + return abfd->where; +} + +static int +memory_bseek (bfd *abfd, file_ptr position, int direction) +{ + file_ptr nwhere; + struct bfd_in_memory *bim; + + bim = (struct bfd_in_memory *) abfd->iostream; + + if (direction == SEEK_SET) + nwhere = position; + else + nwhere = abfd->where + position; + + if (nwhere < 0) + { + abfd->where = 0; + errno = EINVAL; + return -1; + } + + if ((bfd_size_type)nwhere > bim->size) + { + if (abfd->direction == write_direction + || abfd->direction == both_direction) + { + bfd_size_type newsize, oldsize; + + oldsize = (bim->size + 127) & ~(bfd_size_type) 127; + bim->size = nwhere; + /* Round up to cut down on memory fragmentation */ + newsize = (bim->size + 127) & ~(bfd_size_type) 127; + if (newsize > oldsize) + { + bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize); + if (bim->buffer == NULL) + { + errno = EINVAL; + bim->size = 0; + return -1; + } + memset (bim->buffer + oldsize, 0, newsize - oldsize); + } + } + else + { + abfd->where = bim->size; + errno = EINVAL; + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } + return 0; +} + +static int +memory_bclose (struct bfd *abfd) +{ + struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; + + if (bim->buffer != NULL) + free (bim->buffer); + free (bim); + abfd->iostream = NULL; + + return 0; +} + +static int +memory_bflush (bfd *abfd ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +memory_bstat (bfd *abfd, struct stat *statbuf) +{ + struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; + + memset (statbuf, 0, sizeof (*statbuf)); + statbuf->st_size = bim->size; + + return 0; +} + +static void * +memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED, + bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED, + void **map_addr ATTRIBUTE_UNUSED, + bfd_size_type *map_len ATTRIBUTE_UNUSED) +{ + return (void *)-1; +} + +const struct bfd_iovec _bfd_memory_iovec = +{ + &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek, + &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap +};