summaryrefslogtreecommitdiff
path: root/gdb/gdb_bfd.c
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2012-07-18 19:57:20 +0000
committerTom Tromey <tromey@redhat.com>2012-07-18 19:57:20 +0000
commit4ee2aab930752a33e71dfd11865fde112bc03003 (patch)
tree1383c6dc1e58a6a8466856ce24988c8308d39e29 /gdb/gdb_bfd.c
parent17642581262f80256311ad4a8707c3aa462e0b2a (diff)
downloadgdb-4ee2aab930752a33e71dfd11865fde112bc03003.tar.gz
* 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.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 5ad987887a8..10489ace8f2 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;
+}