From 4bf44c1cf1abad13fcda09e20983757f175c6dca Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 18 Jul 2012 19:57:21 +0000 Subject: [PATCH] * dwarf2read.c: Don't include zlib.h or sys/mman.h. (pagesize): Remove. (struct dwarf2_section_info) : 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. --- gdb/ChangeLog | 18 ++++ gdb/dwarf2read.c | 200 +++---------------------------------- gdb/gdb_bfd.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++ gdb/gdb_bfd.h | 14 ++- 4 files changed, 294 insertions(+), 190 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a200927a62e..10dacd665cd 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2012-07-18 Tom Tromey + + * dwarf2read.c: Don't include zlib.h or sys/mman.h. + (pagesize): Remove. + (struct dwarf2_section_info) : 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. + 2012-07-18 Tom Tromey * dwarf2read.c (try_open_dwo_file): use gdb_bfd_open. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 023447f78ef..da23cc44122 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -70,15 +70,6 @@ #include "gdb_string.h" #include "gdb_assert.h" #include -#ifdef HAVE_ZLIB_H -#include -#endif -#ifdef HAVE_MMAP -#include -#ifndef MAP_FAILED -#define MAP_FAILED ((void *) -1) -#endif -#endif typedef struct symbol *symbolp; DEF_VEC_P (symbolp); @@ -96,8 +87,6 @@ static int check_physname = 0; /* When non-zero, do not reject deprecated .gdb_index sections. */ int use_deprecated_index_sections = 0; -static int pagesize; - /* When set, the file that we're processing is known to have debugging info for C++ namespaces. GCC 3.3.x did not produce this information, but later versions do. */ @@ -111,10 +100,6 @@ struct dwarf2_section_info asection *asection; gdb_byte *buffer; bfd_size_type size; - /* Not NULL if the section was actually mmapped. */ - void *map_addr; - /* Page aligned size of mmapped area. */ - bfd_size_type map_len; /* True if we have tried to read this section. */ int readin; }; @@ -1609,8 +1594,6 @@ static struct dwo_unit *lookup_dwo_type_unit static void free_dwo_file_cleanup (void *); -static void munmap_section_buffer (struct dwarf2_section_info *); - static void process_cu_includes (void); #if WORDS_BIGENDIAN @@ -1780,85 +1763,6 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) dwarf2_per_objfile->has_section_at_zero = 1; } -/* Decompress a section that was compressed using zlib. Store the - decompressed buffer, and its size, in OUTBUF and OUTSIZE. */ - -static void -zlib_decompress_section (struct objfile *objfile, asection *sectp, - gdb_byte **outbuf, bfd_size_type *outsize) -{ - bfd *abfd = sectp->owner; -#ifndef HAVE_ZLIB_H - error (_("Support for zlib-compressed DWARF data (from '%s') " - "is disabled in this copy of GDB"), - bfd_get_filename (abfd)); -#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); - bfd_size_type uncompressed_size; - gdb_byte *uncompressed_buffer; - z_stream strm; - int rc; - int header_size = 12; - - if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 - || bfd_bread (compressed_buffer, - compressed_size, abfd) != compressed_size) - error (_("Dwarf Error: Can't read DWARF data from '%s'"), - bfd_get_filename (abfd)); - - /* 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 (_("Dwarf Error: Corrupt DWARF ZLIB header from '%s'"), - bfd_get_filename (abfd)); - 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 = obstack_alloc (&objfile->objfile_obstack, - uncompressed_size); - rc = inflateInit (&strm); - while (strm.avail_in > 0) - { - if (rc != Z_OK) - error (_("Dwarf Error: setting up DWARF uncompression in '%s': %d"), - bfd_get_filename (abfd), rc); - strm.next_out = ((Bytef*) uncompressed_buffer - + (uncompressed_size - strm.avail_out)); - rc = inflate (&strm, Z_FINISH); - if (rc != Z_STREAM_END) - error (_("Dwarf Error: zlib error uncompressing from '%s': %d"), - bfd_get_filename (abfd), rc); - rc = inflateReset (&strm); - } - rc = inflateEnd (&strm); - if (rc != Z_OK - || strm.avail_out != 0) - error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"), - bfd_get_filename (abfd), rc); - - do_cleanups (cleanup); - *outbuf = uncompressed_buffer; - *outsize = uncompressed_size; -#endif -} - /* A helper function that decides whether a section is empty, or not present. */ @@ -1885,56 +1789,27 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) if (info->readin) return; info->buffer = NULL; - info->map_addr = NULL; info->readin = 1; if (dwarf2_section_empty_p (info)) return; - /* Note that ABFD may not be from OBJFILE, e.g. a DWO section. */ abfd = sectp->owner; - /* Check if the file has a 4-byte header indicating compression. */ - if (info->size > 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 (objfile, sectp, &info->buffer, - &info->size); - return; - } - } - -#ifdef HAVE_MMAP - if (pagesize == 0) - pagesize = getpagesize (); - - /* Only try to mmap sections which are large enough: we don't want to - waste space due to fragmentation. Also, only try mmap for sections - without relocations. */ - - if (info->size > 4 * pagesize && (sectp->flags & SEC_RELOC) == 0) + /* If the section has relocations, we must read it ourselves. + Otherwise we attach it to the BFD. */ + if ((sectp->flags & SEC_RELOC) == 0) { - info->buffer = bfd_mmap (abfd, 0, info->size, PROT_READ, - MAP_PRIVATE, sectp->filepos, - &info->map_addr, &info->map_len); + const gdb_byte *bytes = gdb_bfd_map_section (sectp, &info->size); - if ((caddr_t)info->buffer != MAP_FAILED) - { -#if HAVE_POSIX_MADVISE - posix_madvise (info->map_addr, info->map_len, POSIX_MADV_WILLNEED); -#endif - return; - } + /* We have to cast away const here for historical reasons. + Fixing dwarf2read to be const-correct would be quite nice. */ + info->buffer = (gdb_byte *) bytes; + return; } -#endif - /* If we get here, we are a normal, not-compressed section. */ - info->buffer = buf - = obstack_alloc (&objfile->objfile_obstack, info->size); + buf = obstack_alloc (&objfile->objfile_obstack, info->size); + info->buffer = buf; /* When debugging .o files, we may need to apply relocations; see http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . @@ -8324,19 +8199,6 @@ free_dwo_file (struct dwo_file *dwo_file, struct objfile *objfile) gdb_assert (dwo_file->dwo_bfd != objfile->obfd); gdb_bfd_unref (dwo_file->dwo_bfd); - munmap_section_buffer (&dwo_file->sections.abbrev); - munmap_section_buffer (&dwo_file->sections.info); - munmap_section_buffer (&dwo_file->sections.line); - munmap_section_buffer (&dwo_file->sections.loc); - munmap_section_buffer (&dwo_file->sections.str); - munmap_section_buffer (&dwo_file->sections.str_offsets); - - for (ix = 0; - VEC_iterate (dwarf2_section_info_def, dwo_file->sections.types, - ix, section); - ++ix) - munmap_section_buffer (section); - VEC_free (dwarf2_section_info_def, dwo_file->sections.types); } @@ -18338,53 +18200,13 @@ show_dwarf2_cmd (char *args, int from_tty) cmd_show_list (show_dwarf2_cmdlist, from_tty, ""); } -/* If section described by INFO was mmapped, munmap it now. */ - -static void -munmap_section_buffer (struct dwarf2_section_info *info) -{ - if (info->map_addr != NULL) - { -#ifdef HAVE_MMAP - int res; - - res = munmap (info->map_addr, info->map_len); - gdb_assert (res == 0); -#else - /* Without HAVE_MMAP, we should never be here to begin with. */ - gdb_assert_not_reached ("no mmap support"); -#endif - } -} - -/* munmap debug sections for OBJFILE, if necessary. */ +/* Free data associated with OBJFILE, if necessary. */ static void dwarf2_per_objfile_free (struct objfile *objfile, void *d) { struct dwarf2_per_objfile *data = d; int ix; - struct dwarf2_section_info *section; - - /* This is sorted according to the order they're defined in to make it easier - to keep in sync. */ - munmap_section_buffer (&data->info); - munmap_section_buffer (&data->abbrev); - munmap_section_buffer (&data->line); - munmap_section_buffer (&data->loc); - munmap_section_buffer (&data->macinfo); - munmap_section_buffer (&data->macro); - munmap_section_buffer (&data->str); - munmap_section_buffer (&data->ranges); - munmap_section_buffer (&data->addr); - munmap_section_buffer (&data->frame); - munmap_section_buffer (&data->eh_frame); - munmap_section_buffer (&data->gdb_index); - - for (ix = 0; - VEC_iterate (dwarf2_section_info_def, data->types, ix, section); - ++ix) - munmap_section_buffer (section); for (ix = 0; ix < dwarf2_per_objfile->n_comp_units; ++ix) VEC_free (dwarf2_per_cu_ptr, 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 +#endif +#ifdef HAVE_MMAP +#include +#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; +} diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h index 78d303b3a67..1dd82c319de 100644 --- a/gdb/gdb_bfd.h +++ b/gdb/gdb_bfd.h @@ -1,6 +1,6 @@ /* Definitions for BFD wrappers used by GDB. - Copyright (C) 2011 + Copyright (C) 2011, 2012 Free Software Foundation, Inc. This file is part of GDB. @@ -46,4 +46,16 @@ struct bfd *gdb_bfd_ref (struct bfd *abfd); void gdb_bfd_unref (struct bfd *abfd); +/* Try to read or map the contents of the section SECT. If + successful, the section data is returned and *SIZE is set to the + size of the section data; this may not be the same as the size + according to bfd_get_section_size if the section was compressed. + The returned section data is associated with the BFD and will be + destroyed when the BFD is destroyed. There is no other way to free + it; for temporary uses of section data, see + bfd_malloc_and_get_section. SECT may not have relocations. This + function will throw on error. */ + +const gdb_byte *gdb_bfd_map_section (asection *section, bfd_size_type *size); + #endif /* GDB_BFD_H */ -- 2.30.2