diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 5c42128..bd648ce 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -5821,6 +5821,9 @@ bfd_byte *bfd_simple_get_relocated_section_contents bfd_boolean bfd_uncompress_section_contents (bfd_byte **buffer, bfd_size_type *size); +bfd_boolean bfd_compress_section_contents + (bfd_byte **buffer, bfd_size_type *size); + #ifdef __cplusplus } #endif diff --git a/bfd/compress.c b/bfd/compress.c index 5b6ee0e..7b334a0 100644 --- a/bfd/compress.c +++ b/bfd/compress.c @@ -1,4 +1,4 @@ -/* ELF attributes support (based on ARM EABI attributes). +/* Compressed section support (intended for debug sections). Copyright 2008 Free Software Foundation, Inc. @@ -120,3 +120,73 @@ bfd_uncompress_section_contents (bfd_byte **buffer, bfd_size_type *size) return FALSE; #endif /* HAVE_ZLIB_H */ } + +/* +FUNCTION + bfd_compress_section_contents + +SYNOPSIS + bfd_boolean bfd_compress_section_contents + (bfd_byte **buffer, bfd_size_type *size); + +DESCRIPTION + + Compresses a section using zlib, in place. At the call to this + function, *@var{buffer} and *@var{size} should point to the section + contents to be compressed. At the end of the function, *@var{buffer} + and *@var{size} will point to the compressed contents. This function + assumes *BUFFER was allocated using bfd_malloc() or equivalent. If + zlib is not installed on this machine, the input is unmodified. + + Returns @code{FALSE} if unable to compress successfully; in that case + the input is unmodified. Otherwise, returns @code{TRUE}. +*/ + +bfd_boolean +bfd_compress_section_contents (bfd_byte **buffer, bfd_size_type *size) +{ +#ifndef HAVE_ZLIB_H + /* These are just to quiet gcc. */ + buffer = 0; + size = 0; + return FALSE; +#else + bfd_size_type uncompressed_size = *size; + bfd_byte *uncompressed_buffer = *buffer; + bfd_size_type compressed_size; + bfd_byte *compressed_buffer; + int rc; + bfd_size_type header_size = 12; + + compressed_size = compressBound (uncompressed_size) + header_size; + compressed_buffer = (bfd_byte *) bfd_malloc (compressed_size); + + rc = compress ((Bytef*) compressed_buffer + header_size, + &compressed_size, + (const Bytef*) uncompressed_buffer, + uncompressed_size); + if (rc != Z_OK) + { + free (compressed_buffer); + return FALSE; + } + + /* Write the zlib header. In this case, it should be "ZLIB" followed + by the uncompressed section size, 8 bytes in big-endian order. */ + memcpy (compressed_buffer, "ZLIB", 4); + compressed_buffer[4] = uncompressed_size >> 56; + compressed_buffer[5] = uncompressed_size >> 48; + compressed_buffer[6] = uncompressed_size >> 40; + compressed_buffer[7] = uncompressed_size >> 32; + compressed_buffer[8] = uncompressed_size >> 24; + compressed_buffer[9] = uncompressed_size >> 16; + compressed_buffer[10] = uncompressed_size >> 8; + compressed_buffer[11] = uncompressed_size; + compressed_size += header_size; + + free (uncompressed_buffer); + *buffer = compressed_buffer; + *size = compressed_size; + return TRUE; +#endif /* HAVE_ZLIB_H */ +} diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index 9b194aa..ffe1108 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -405,6 +405,54 @@ lookup_info_hash_table (struct info_hash_table *hash_table, const char *key) return entry ? entry->head : NULL; } +/* Read a section, uncompress it if necessary, and relocate it. */ + +static bfd_boolean +read_and_uncompress_section (bfd * abfd, + asection * msec, + bfd_boolean section_is_compressed, + asymbol ** syms, + bfd_byte ** section_buffer, + bfd_size_type * section_size) +{ + /* Get the unrelocated contents of the section. */ + *section_buffer = (bfd_byte *) bfd_malloc (*section_size); + if (! *section_buffer) + return FALSE; + if (! bfd_get_section_contents (abfd, msec, *section_buffer, + 0, *section_size)) + return FALSE; + + if (section_is_compressed) + { + if (! bfd_uncompress_section_contents (section_buffer, section_size)) + { + (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."), + bfd_get_section_name (abfd, msec)); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + } + + if (syms) + { + /* We want to relocate the data we've already read (and + decompressed), so we store a pointer to the data in + the bfd_section, and tell it that the contents are + already in memory. */ + BFD_ASSERT (msec->contents == NULL && (msec->flags & SEC_IN_MEMORY) == 0); + msec->contents = *section_buffer; + msec->flags |= SEC_IN_MEMORY; + msec->size = *section_size; + *section_buffer + = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms); + if (! *section_buffer) + return FALSE; + } + + return TRUE; +} + /* Read a section into its appropriate place in the dwarf2_debug struct (indicated by SECTION_BUFFER and SECTION_SIZE). If SYMS is not NULL, use bfd_simple_get_relocated_section_contents to read the @@ -440,32 +488,10 @@ read_section (bfd * abfd, } *section_size = msec->rawsize ? msec->rawsize : msec->size; - if (syms) - { - *section_buffer - = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms); - if (! *section_buffer) - return FALSE; - } - else - { - *section_buffer = (bfd_byte *) bfd_malloc (*section_size); - if (! *section_buffer) - return FALSE; - if (! bfd_get_section_contents (abfd, msec, *section_buffer, - 0, *section_size)) - return FALSE; - } - if (section_is_compressed) - { - if (! bfd_uncompress_section_contents (section_buffer, section_size)) - { - (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."), compressed_section_name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } + if (! read_and_uncompress_section (abfd, msec, section_is_compressed, + syms, section_buffer, section_size)) + return FALSE; } /* It is possible to get a bad value for the offset into the section @@ -3242,23 +3268,17 @@ find_line (bfd *abfd, { bfd_size_type size = msec->size; bfd_byte *buffer, *tmp; + bfd_boolean is_compressed = + strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0; if (size == 0) continue; - buffer = (bfd_simple_get_relocated_section_contents - (debug_bfd, msec, NULL, symbols)); - if (! buffer) + if (! read_and_uncompress_section (debug_bfd, msec, + is_compressed, symbols, + &buffer, &size)) goto done; - if (strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0) - { - if (! bfd_uncompress_section_contents (&buffer, &size)) - { - free (buffer); - goto done; - } - } tmp = (bfd_byte *) bfd_realloc (stash->info_ptr_memory, total_size + size); if (tmp == NULL) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 233891c..3da79d9 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2243,12 +2243,12 @@ bfd_boolean bfd_generic_merge_sections (bfd *, struct bfd_link_info *); bfd_byte *bfd_generic_get_relocated_section_contents - (bfd *, - struct bfd_link_info *, - struct bfd_link_order *, - bfd_byte *, - bfd_boolean, - asymbol **); + (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols); /* Extracted from archures.c. */ extern const bfd_arch_info_type bfd_default_arch_struct; diff --git a/binutils/objdump.c b/binutils/objdump.c index 2a419b7..f94dee9 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -2205,14 +2205,8 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, section->size = bfd_get_section_size (sec); section->start = (unsigned char *) xmalloc (section->size); - if (is_relocatable && debug_displays [debug].relocate) - ret = bfd_simple_get_relocated_section_contents (abfd, - sec, - section->start, - syms) != NULL; - else - ret = bfd_get_section_contents (abfd, sec, section->start, 0, - section->size); + ret = bfd_get_section_contents (abfd, sec, section->start, 0, + section->size); if (! ret) { @@ -2234,6 +2228,30 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, section->size = size; } + if (is_relocatable && debug_displays [debug].relocate) + { + /* We want to relocate the data we've already read (and + decompressed), so we store a pointer to the data in + the bfd_section, and tell it that the contents are + already in memory. */ + sec->contents = section->start; + sec->flags |= SEC_IN_MEMORY; + sec->size = section->size; + + ret = bfd_simple_get_relocated_section_contents (abfd, + sec, + section->start, + syms) != NULL; + + if (! ret) + { + free_debug_section (debug); + printf (_("\nCan't get contents for section '%s'.\n"), + section->name); + return 0; + } + } + return 1; } diff --git a/binutils/readelf.c b/binutils/readelf.c index d4f47ca..1c3cb8b 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -9962,8 +9962,11 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, return 0; if (section_is_compressed) - if (! uncompress_section_contents (§ion->start, §ion->size)) - return 0; + { + if (! uncompress_section_contents (§ion->start, §ion->size)) + return 0; + sec->sh_size = section->size; + } if (debug_displays [debug].relocate) apply_relocations ((FILE *) file, sec, section->start); diff --git a/gas/as.c b/gas/as.c index d617b33..e494fa5 100644 --- a/gas/as.c +++ b/gas/as.c @@ -437,7 +437,9 @@ parse_args (int * pargc, char *** pargv) OPTION_AL, OPTION_HASH_TABLE_SIZE, OPTION_REDUCE_MEMORY_OVERHEADS, - OPTION_WARN_FATAL + OPTION_WARN_FATAL, + OPTION_COMPRESS_DEBUG, + OPTION_NOCOMPRESS_DEBUG /* When you add options here, check that they do not collide with OPTION_MD_BASE. See as.h. */ }; @@ -455,6 +457,8 @@ parse_args (int * pargc, char *** pargv) ,{"a", optional_argument, NULL, 'a'} /* Handle -al=. */ ,{"al", optional_argument, NULL, OPTION_AL} + ,{"compress-debug-sections", no_argument, NULL, OPTION_COMPRESS_DEBUG} + ,{"nocompress-debug-sections", no_argument, NULL, OPTION_NOCOMPRESS_DEBUG} ,{"debug-prefix-map", required_argument, NULL, OPTION_DEBUG_PREFIX_MAP} ,{"defsym", required_argument, NULL, OPTION_DEFSYM} ,{"dump-config", no_argument, NULL, OPTION_DUMPCONFIG} @@ -634,6 +638,14 @@ This program has absolutely no warranty.\n")); #endif exit (EXIT_SUCCESS); + case OPTION_COMPRESS_DEBUG: + flag_compress_debug = 1; + break; + + case OPTION_NOCOMPRESS_DEBUG: + flag_compress_debug = 0; + break; + case OPTION_DEBUG_PREFIX_MAP: add_debug_prefix_map (optarg); break; diff --git a/gas/as.h b/gas/as.h index 2b2562e..7c16382 100644 --- a/gas/as.h +++ b/gas/as.h @@ -365,6 +365,9 @@ COMMON int flag_strip_local_absolute; /* True if we should generate a traditional format object file. */ COMMON int flag_traditional_format; +/* TRUE if debug sections should be compressed. */ +COMMON int flag_compress_debug; + /* TRUE if .note.GNU-stack section with SEC_CODE should be created */ COMMON int flag_execstack; diff --git a/gas/write.c b/gas/write.c index a148b24..4fc27fc 100644 --- a/gas/write.c +++ b/gas/write.c @@ -1289,6 +1289,77 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) } static void +compress_debug (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, + void *xxx ATTRIBUTE_UNUSED) +{ + segment_info_type *seginfo = seg_info (sec); + addressT offset = 0; + fragS *f; + bfd_size_type section_size = (bfd_size_type) sec->size; + bfd_byte *contents; + const char *section_name; + char *compressed_name; + int x; + + if (seginfo == NULL + || !(bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS) + || (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)) + return; + + section_name = bfd_get_section_name (stdoutput, sec); + if (strncmp (section_name, ".debug_", 7) != 0) + return; + + /* Gather the frags into a contiguous buffer. */ + contents = (bfd_byte *) xmalloc (section_size); + for (f = seginfo->frchainP->frch_root; + f; + f = f->fr_next) + { + addressT fill_size; + char *fill_literal; + offsetT count; + + gas_assert (f->fr_type == rs_fill); + if (f->fr_fix) + { + memcpy (contents + offset, f->fr_literal, (size_t) f->fr_fix); + offset += f->fr_fix; + } + fill_literal = f->fr_literal + f->fr_fix; + fill_size = f->fr_var; + count = f->fr_offset; + gas_assert (count >= 0); + if (fill_size && count) + { + while (count--) + { + memcpy (contents + offset, fill_literal, (size_t) fill_size); + offset += fill_size; + } + } + } + + /* Compress the buffer. */ + if (!bfd_compress_section_contents (&contents, §ion_size)) + return; + + /* Store the compressed contents in the section. */ + sec->contents = contents; + sec->flags |= SEC_IN_MEMORY; + x = bfd_set_section_size (abfd, sec, section_size); + gas_assert (x); + + /* Change the section name. */ + compressed_name = (char *) xmalloc (strlen (section_name) + 2); + compressed_name[0] = '.'; + compressed_name[1] = 'z'; + strcpy (compressed_name + 2, section_name + 1); + bfd_section_name (stdoutput, sec) = compressed_name; +} + +static void write_contents (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *xxx ATTRIBUTE_UNUSED) @@ -1297,6 +1368,20 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED, addressT offset = 0; fragS *f; + if (bfd_get_section_flags (abfd, sec) & SEC_IN_MEMORY) + { + /* We already gathered the frags and compressed the data. */ + int x; + + x = bfd_set_section_contents (stdoutput, sec, sec->contents, + (file_ptr) offset, + (bfd_size_type) sec->size); + if (!x) + as_fatal (_("can't write %s: %s"), stdoutput->filename, + bfd_errmsg (bfd_get_error ())); + return; + } + /* Write out the frags. */ if (seginfo == NULL || !(bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)) @@ -1912,6 +1997,13 @@ write_object_file (void) obj_frob_file_after_relocs (); #endif + /* Once all relocations have been written, we can compress the + contents of the debug sections. This needs to be done before + we start writing any sections, because it will affect the file + layout, which is fixed once we start writing contents. */ + if (flag_compress_debug) + bfd_map_over_sections (stdoutput, compress_debug, (char *) 0); + bfd_map_over_sections (stdoutput, write_contents, (char *) 0); }