diff options
author | Tom Tromey <tromey@redhat.com> | 2012-07-18 19:57:21 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2012-07-18 19:57:21 +0000 |
commit | 4bf44c1cf1abad13fcda09e20983757f175c6dca (patch) | |
tree | cdf42085d3145af5f039d7783b63f6ce4d622a32 /gdb/gdb_bfd.c | |
parent | bb39779773bd297e43c409d2643e787aaeb6c3e1 (diff) | |
download | gdb-4bf44c1cf1abad13fcda09e20983757f175c6dca.zip gdb-4bf44c1cf1abad13fcda09e20983757f175c6dca.tar.gz gdb-4bf44c1cf1abad13fcda09e20983757f175c6dca.tar.bz2 |
* dwarf2read.c: Don't include zlib.h or sys/mman.h.
(pagesize): Remove.
(struct dwarf2_section_info) <map_addr, map_len>: Remove.
(zlib_decompress_section): Remove.
(dwarf2_read_section): Use gdb_bfd_map_section.
(munmap_section_buffer): Remove.
(free_dwo_file, dwarf2_per_objfile_free): Don't use
munmap_section_buffer.
* gdb_bfd.c: Include zlib.h, sys/mman.h.
(struct gdb_bfd_section_data): New.
(free_one_bfd_section): New function.
(gdb_bfd_close_or_warn): Use free_one_bfd_section.
(get_section_descriptor, zlib_decompress_section)
(gdb_bfd_map_section): New functions.
* gdb_bfd.h (gdb_bfd_map_section): Declare.
Diffstat (limited to 'gdb/gdb_bfd.c')
-rw-r--r-- | gdb/gdb_bfd.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c index 5ad9878..10489ac 100644 --- a/gdb/gdb_bfd.c +++ b/gdb/gdb_bfd.c @@ -23,6 +23,30 @@ #include "gdb_assert.h" #include "gdb_string.h" #include "hashtab.h" +#ifdef HAVE_ZLIB_H +#include <zlib.h> +#endif +#ifdef HAVE_MMAP +#include <sys/mman.h> +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif +#endif + +/* An object of this type is stored in the section's user data when + mapping a section. */ + +struct gdb_bfd_section_data +{ + /* Size of the data. */ + bfd_size_type size; + /* If the data was mmapped, this is the length of the map. */ + bfd_size_type map_len; + /* The data. If NULL, the section data has not been read. */ + void *data; + /* If the data was mmapped, this is the map address. */ + void *map_addr; +}; /* See gdb_bfd.h. */ @@ -149,6 +173,30 @@ gdb_bfd_open (const char *name, const char *target, int fd) return gdb_bfd_ref (abfd); } +/* A helper function that releases any section data attached to the + BFD. */ + +static void +free_one_bfd_section (bfd *abfd, asection *sectp, void *ignore) +{ + struct gdb_bfd_section_data *sect = bfd_get_section_userdata (abfd, sectp); + + if (sect != NULL && sect->data != NULL) + { +#ifdef HAVE_MMAP + if (sect->map_addr != NULL) + { + int res; + + res = munmap (sect->map_addr, sect->map_len); + gdb_assert (res == 0); + } + else +#endif + xfree (sect->data); + } +} + /* Close ABFD, and warn if that fails. */ static int @@ -157,6 +205,8 @@ gdb_bfd_close_or_warn (struct bfd *abfd) int ret; char *name = bfd_get_filename (abfd); + bfd_map_over_sections (abfd, free_one_bfd_section, NULL); + ret = bfd_close (abfd); if (!ret) @@ -229,3 +279,205 @@ gdb_bfd_unref (struct bfd *abfd) gdb_bfd_close_or_warn (abfd); } + +/* A helper function that returns the section data descriptor + associated with SECTION. If no such descriptor exists, a new one + is allocated and cleared. */ + +static struct gdb_bfd_section_data * +get_section_descriptor (asection *section) +{ + struct gdb_bfd_section_data *result; + + result = bfd_get_section_userdata (section->owner, section); + + if (result == NULL) + { + result = bfd_zalloc (section->owner, sizeof (*result)); + bfd_set_section_userdata (section->owner, section, result); + } + + return result; +} + +/* Decompress a section that was compressed using zlib. Store the + decompressed buffer, and its size, in DESCRIPTOR. */ + +static void +zlib_decompress_section (asection *sectp, + struct gdb_bfd_section_data *descriptor) +{ + bfd *abfd = sectp->owner; +#ifndef HAVE_ZLIB_H + error (_("Support for zlib-compressed data (from '%s', section '%s') " + "is disabled in this copy of GDB"), + bfd_get_filename (abfd), + bfd_get_section_name (sectp)); +#else + bfd_size_type compressed_size = bfd_get_section_size (sectp); + gdb_byte *compressed_buffer = xmalloc (compressed_size); + struct cleanup *cleanup = make_cleanup (xfree, compressed_buffer); + struct cleanup *inner_cleanup; + bfd_size_type uncompressed_size; + gdb_byte *uncompressed_buffer; + z_stream strm; + int rc; + int header_size = 12; + struct dwarf2_per_bfd_section *section_data; + + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 + || bfd_bread (compressed_buffer, + compressed_size, abfd) != compressed_size) + error (_("can't read data from '%s', section '%s'"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp)); + + /* Read the zlib header. In this case, it should be "ZLIB" followed + by the uncompressed section size, 8 bytes in big-endian order. */ + if (compressed_size < header_size + || strncmp (compressed_buffer, "ZLIB", 4) != 0) + error (_("corrupt ZLIB header from '%s', section '%s'"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp)); + uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[11]; + + /* It is possible the section consists of several compressed + buffers concatenated together, so we uncompress in a loop. */ + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + strm.avail_in = compressed_size - header_size; + strm.next_in = (Bytef*) compressed_buffer + header_size; + strm.avail_out = uncompressed_size; + uncompressed_buffer = xmalloc (uncompressed_size); + inner_cleanup = make_cleanup (xfree, uncompressed_buffer); + rc = inflateInit (&strm); + while (strm.avail_in > 0) + { + if (rc != Z_OK) + error (_("setting up uncompression in '%s', section '%s': %d"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp), + rc); + strm.next_out = ((Bytef*) uncompressed_buffer + + (uncompressed_size - strm.avail_out)); + rc = inflate (&strm, Z_FINISH); + if (rc != Z_STREAM_END) + error (_("zlib error uncompressing from '%s', section '%s': %d"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp), + rc); + rc = inflateReset (&strm); + } + rc = inflateEnd (&strm); + if (rc != Z_OK + || strm.avail_out != 0) + error (_("concluding uncompression in '%s', section '%s': %d"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp), + rc); + + discard_cleanups (inner_cleanup); + do_cleanups (cleanup); + + /* Attach the data to the BFD section. */ + descriptor->data = uncompressed_buffer; + descriptor->size = uncompressed_size; +#endif +} + +/* See gdb_bfd.h. */ + +const gdb_byte * +gdb_bfd_map_section (asection *sectp, bfd_size_type *size) +{ + bfd *abfd; + gdb_byte *buf, *retbuf; + unsigned char header[4]; + struct gdb_bfd_section_data *descriptor; + + gdb_assert ((sectp->flags & SEC_RELOC) == 0); + gdb_assert (size != NULL); + + abfd = sectp->owner; + + descriptor = get_section_descriptor (sectp); + + /* If the data was already read for this BFD, just reuse it. */ + if (descriptor->data != NULL) + goto done; + + /* Check if the file has a 4-byte header indicating compression. */ + if (bfd_get_section_size (sectp) > sizeof (header) + && bfd_seek (abfd, sectp->filepos, SEEK_SET) == 0 + && bfd_bread (header, sizeof (header), abfd) == sizeof (header)) + { + /* Upon decompression, update the buffer and its size. */ + if (strncmp (header, "ZLIB", sizeof (header)) == 0) + { + zlib_decompress_section (sectp, descriptor); + goto done; + } + } + +#ifdef HAVE_MMAP + { + /* The page size, used when mmapping. */ + static int pagesize; + + if (pagesize == 0) + pagesize = getpagesize (); + + /* Only try to mmap sections which are large enough: we don't want + to waste space due to fragmentation. */ + + if (bfd_get_section_size (sectp) > 4 * pagesize) + { + descriptor->size = bfd_get_section_size (sectp); + descriptor->data = bfd_mmap (abfd, 0, descriptor->size, PROT_READ, + MAP_PRIVATE, sectp->filepos, + &descriptor->map_addr, + &descriptor->map_len); + + if ((caddr_t)descriptor->data != MAP_FAILED) + { +#if HAVE_POSIX_MADVISE + posix_madvise (descriptor->map_addr, descriptor->map_len, + POSIX_MADV_WILLNEED); +#endif + goto done; + } + + /* On failure, clear out the section data and try again. */ + memset (descriptor, 0, sizeof (*descriptor)); + } + } +#endif /* HAVE_MMAP */ + + /* If we get here, we are a normal, not-compressed section. */ + + descriptor->size = bfd_get_section_size (sectp); + descriptor->data = xmalloc (descriptor->size); + + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 + || bfd_bread (descriptor->data, bfd_get_section_size (sectp), + abfd) != bfd_get_section_size (sectp)) + { + xfree (descriptor->data); + descriptor->data = NULL; + error (_("Can't read data for section '%s'"), + bfd_get_filename (abfd)); + } + + done: + gdb_assert (descriptor->data != NULL); + *size = descriptor->size; + return descriptor->data; +} |