From 5dd8762ad1a47548394c76ead1b56fc5dab64628 Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Wed, 29 Feb 2012 21:22:29 +0000 Subject: [PATCH] * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info): Call Object::decompressed_section_contents. * dwarf_reader.h (Sized_dwarf_line_info::~Sized_dwarf_line_info): New dtor. (Sized_dwarf_line_info::buffer_start_): New data member. * merge.cc (Output_merge_data::do_add_input_section): Call Object::decompressed_section_contents. (Output_merge_string::do_add_input_section): Likewise. * object.cc (need_decompressed_section): New function. (build_compressed_section_map): Decompress sections needed later. (Sized_relobj_file::do_decompressed_section_contents): New function. (Sized_relobj_file::do_discard_decompressed_sections): New function. * object.h (Object::decompressed_section_contents): New function. (Object::discard_decompressed_sections): New function. (Object::do_decompressed_section_contents): New function. (Object::do_discard_decompressed_sections): New function. (Compressed_section_info): New type. (Compressed_section_map): Include decompressed section contents. (Sized_relobj_file::do_decompressed_section_contents): New function. (Sized_relobj_file::do_discard_decompressed_sections): New function. --- gold/ChangeLog | 23 ++++++++ gold/dwarf_reader.cc | 33 ++++------- gold/dwarf_reader.h | 11 ++++ gold/merge.cc | 51 +++++------------ gold/object.cc | 130 +++++++++++++++++++++++++++++++++++++++++-- gold/object.h | 62 +++++++++++++++++++-- gold/readsyms.cc | 2 + 7 files changed, 246 insertions(+), 66 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 47ec2ec0fe..08a69c0d53 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,26 @@ +2012-02-29 Cary Coutant + + * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info): + Call Object::decompressed_section_contents. + * dwarf_reader.h (Sized_dwarf_line_info::~Sized_dwarf_line_info): + New dtor. + (Sized_dwarf_line_info::buffer_start_): New data member. + * merge.cc (Output_merge_data::do_add_input_section): Call + Object::decompressed_section_contents. + (Output_merge_string::do_add_input_section): Likewise. + * object.cc (need_decompressed_section): New function. + (build_compressed_section_map): Decompress sections needed later. + (Sized_relobj_file::do_decompressed_section_contents): New function. + (Sized_relobj_file::do_discard_decompressed_sections): New function. + * object.h (Object::decompressed_section_contents): New function. + (Object::discard_decompressed_sections): New function. + (Object::do_decompressed_section_contents): New function. + (Object::do_discard_decompressed_sections): New function. + (Compressed_section_info): New type. + (Compressed_section_map): Include decompressed section contents. + (Sized_relobj_file::do_decompressed_section_contents): New function. + (Sized_relobj_file::do_discard_decompressed_sections): New function. + 2012-02-16 Cary Coutant * testsuite/Makefile.am (initpri2): Add --ctors-in-init-array option. diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc index 2b47a28b17..73f84b0d42 100644 --- a/gold/dwarf_reader.cc +++ b/gold/dwarf_reader.cc @@ -62,12 +62,14 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt) } template -Sized_dwarf_line_info::Sized_dwarf_line_info(Object* object, - unsigned int read_shndx) - : data_valid_(false), buffer_(NULL), symtab_buffer_(NULL), - directories_(), files_(), current_header_index_(-1) +Sized_dwarf_line_info::Sized_dwarf_line_info( + Object* object, + unsigned int read_shndx) + : data_valid_(false), buffer_(NULL), buffer_start_(NULL), + symtab_buffer_(NULL), directories_(), files_(), current_header_index_(-1) { unsigned int debug_shndx; + for (debug_shndx = 1; debug_shndx < object->shnum(); ++debug_shndx) { // FIXME: do this more efficiently: section_name() isn't super-fast @@ -75,8 +77,12 @@ Sized_dwarf_line_info::Sized_dwarf_line_info(Object* object, if (name == ".debug_line" || name == ".zdebug_line") { section_size_type buffer_size; - this->buffer_ = object->section_contents(debug_shndx, &buffer_size, - false); + bool is_new = false; + this->buffer_ = object->decompressed_section_contents(debug_shndx, + &buffer_size, + &is_new); + if (is_new) + this->buffer_start_ = this->buffer_; this->buffer_end_ = this->buffer_ + buffer_size; break; } @@ -84,21 +90,6 @@ Sized_dwarf_line_info::Sized_dwarf_line_info(Object* object, if (this->buffer_ == NULL) return; - section_size_type uncompressed_size = 0; - unsigned char* uncompressed_data = NULL; - if (object->section_is_compressed(debug_shndx, &uncompressed_size)) - { - uncompressed_data = new unsigned char[uncompressed_size]; - if (!decompress_input_section(this->buffer_, - this->buffer_end_ - this->buffer_, - uncompressed_data, - uncompressed_size)) - object->error(_("could not decompress section %s"), - object->section_name(debug_shndx).c_str()); - this->buffer_ = uncompressed_data; - this->buffer_end_ = this->buffer_ + uncompressed_size; - } - // Find the relocation section for ".debug_line". // We expect these for relobjs (.o's) but not dynobjs (.so's). bool got_relocs = false; diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h index 3f92dd3eea..722ee647af 100644 --- a/gold/dwarf_reader.h +++ b/gold/dwarf_reader.h @@ -120,6 +120,13 @@ class Sized_dwarf_line_info : public Dwarf_line_info // information that pertains to the specified section. Sized_dwarf_line_info(Object* object, unsigned int read_shndx = -1U); + virtual + ~Sized_dwarf_line_info() + { + if (this->buffer_start_ != NULL) + delete[] this->buffer_start_; + } + private: std::string do_addr2line(unsigned int shndx, off_t offset, @@ -199,6 +206,10 @@ class Sized_dwarf_line_info : public Dwarf_line_info // the line info to read is. const unsigned char* buffer_; const unsigned char* buffer_end_; + // If the buffer was allocated temporarily, and therefore must be + // deallocated in the dtor, this contains a pointer to the start + // of the buffer. + const unsigned char* buffer_start_; // This has relocations that point into buffer. Track_relocs track_relocs_; diff --git a/gold/merge.cc b/gold/merge.cc index 093b6fc692..dde43e9b12 100644 --- a/gold/merge.cc +++ b/gold/merge.cc @@ -406,27 +406,16 @@ bool Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) { section_size_type len; - section_size_type uncompressed_size = 0; - unsigned char* uncompressed_data = NULL; - const unsigned char* p = object->section_contents(shndx, &len, false); - - if (object->section_is_compressed(shndx, &uncompressed_size)) - { - uncompressed_data = new unsigned char[uncompressed_size]; - if (!decompress_input_section(p, len, uncompressed_data, - uncompressed_size)) - object->error(_("could not decompress section %s"), - object->section_name(shndx).c_str()); - p = uncompressed_data; - len = uncompressed_size; - } + bool is_new; + const unsigned char* p = object->decompressed_section_contents(shndx, &len, + &is_new); section_size_type entsize = convert_to_section_size_type(this->entsize()); if (len % entsize != 0) { - if (uncompressed_data != NULL) - delete[] uncompressed_data; + if (is_new) + delete[] p; return false; } @@ -457,8 +446,8 @@ Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) if (this->keeps_input_sections()) record_input_section(object, shndx); - if (uncompressed_data != NULL) - delete[] uncompressed_data; + if (is_new) + delete[] p; return true; } @@ -517,20 +506,10 @@ Output_merge_string::do_add_input_section(Relobj* object, unsigned int shndx) { section_size_type len; - section_size_type uncompressed_size = 0; - unsigned char* uncompressed_data = NULL; - const unsigned char* pdata = object->section_contents(shndx, &len, false); - - if (object->section_is_compressed(shndx, &uncompressed_size)) - { - uncompressed_data = new unsigned char[uncompressed_size]; - if (!decompress_input_section(pdata, len, uncompressed_data, - uncompressed_size)) - object->error(_("could not decompress section %s"), - object->section_name(shndx).c_str()); - pdata = uncompressed_data; - len = uncompressed_size; - } + bool is_new; + const unsigned char* pdata = object->decompressed_section_contents(shndx, + &len, + &is_new); const Char_type* p = reinterpret_cast(pdata); const Char_type* pend = p + len / sizeof(Char_type); @@ -540,8 +519,8 @@ Output_merge_string::do_add_input_section(Relobj* object, { object->error(_("mergeable string section length not multiple of " "character size")); - if (uncompressed_data != NULL) - delete[] uncompressed_data; + if (is_new) + delete[] pdata; return false; } @@ -606,8 +585,8 @@ Output_merge_string::do_add_input_section(Relobj* object, if (this->keeps_input_sections()) record_input_section(object, shndx); - if (uncompressed_data != NULL) - delete[] uncompressed_data; + if (is_new) + delete[] pdata; return true; } diff --git a/gold/object.cc b/gold/object.cc index bbeb9af9b9..f30354e873 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -550,8 +550,22 @@ Sized_relobj_file::find_eh_frame( return false; } +// Return TRUE if this is a section whose contents will be needed in the +// Add_symbols task. + +static bool +need_decompressed_section(const char* name) +{ + // We will need .zdebug_str if this is not an incremental link + // (i.e., we are processing string merge sections). + if (!parameters->incremental() && strcmp(name, ".zdebug_str") == 0) + return true; + + return false; +} + // Build a table for any compressed debug sections, mapping each section index -// to the uncompressed size. +// to the uncompressed size and (if needed) the decompressed contents. template Compressed_section_map* @@ -562,9 +576,10 @@ build_compressed_section_map( section_size_type names_size, Sized_relobj_file* obj) { - Compressed_section_map* uncompressed_sizes = new Compressed_section_map(); + Compressed_section_map* uncompressed_map = new Compressed_section_map(); const unsigned int shdr_size = elfcpp::Elf_sizes::shdr_size; const unsigned char* p = pshdrs + shdr_size; + for (unsigned int i = 1; i < shnum; ++i, p += shdr_size) { typename elfcpp::Shdr shdr(p); @@ -586,12 +601,38 @@ build_compressed_section_map( obj->section_contents(i, &len, false); uint64_t uncompressed_size = get_uncompressed_size(contents, len); if (uncompressed_size != -1ULL) - (*uncompressed_sizes)[i] = - convert_to_section_size_type(uncompressed_size); + { + Compressed_section_info info; + info.size = convert_to_section_size_type(uncompressed_size); + info.contents = NULL; + +#ifdef ENABLE_THREADS + // If we're multi-threaded, it will help to decompress + // any sections that will be needed during the Add_symbols + // task, so that several decompressions can run in + // parallel. + if (parameters->options().threads()) + { + unsigned char* uncompressed_data = NULL; + if (need_decompressed_section(name)) + { + uncompressed_data = new unsigned char[uncompressed_size]; + if (decompress_input_section(contents, len, + uncompressed_data, + uncompressed_size)) + info.contents = uncompressed_data; + else + delete[] uncompressed_data; + } + } +#endif + + (*uncompressed_map)[i] = info; + } } } } - return uncompressed_sizes; + return uncompressed_map; } // Read the sections and symbols from an object file. @@ -2557,6 +2598,85 @@ Sized_relobj_file::do_get_global_symbol_counts( *used = count; } +// Return a view of the decompressed contents of a section. Set *PLEN +// to the size. Set *IS_NEW to true if the contents need to be freed +// by the caller. + +template +const unsigned char* +Sized_relobj_file::do_decompressed_section_contents( + unsigned int shndx, + section_size_type* plen, + bool* is_new) +{ + section_size_type buffer_size; + const unsigned char* buffer = this->section_contents(shndx, &buffer_size, + false); + + if (this->compressed_sections_ == NULL) + { + *plen = buffer_size; + *is_new = false; + return buffer; + } + + Compressed_section_map::const_iterator p = + this->compressed_sections_->find(shndx); + if (p == this->compressed_sections_->end()) + { + *plen = buffer_size; + *is_new = false; + return buffer; + } + + section_size_type uncompressed_size = p->second.size; + if (p->second.contents != NULL) + { + *plen = uncompressed_size; + *is_new = false; + return p->second.contents; + } + + unsigned char* uncompressed_data = new unsigned char[uncompressed_size]; + if (!decompress_input_section(buffer, + buffer_size, + uncompressed_data, + uncompressed_size)) + this->error(_("could not decompress section %s"), + this->do_section_name(shndx).c_str()); + + // We could cache the results in p->second.contents and store + // false in *IS_NEW, but build_compressed_section_map() would + // have done so if it had expected it to be profitable. If + // we reach this point, we expect to need the contents only + // once in this pass. + *plen = uncompressed_size; + *is_new = true; + return uncompressed_data; +} + +// Discard any buffers of uncompressed sections. This is done +// at the end of the Add_symbols task. + +template +void +Sized_relobj_file::do_discard_decompressed_sections() +{ + if (this->compressed_sections_ == NULL) + return; + + for (Compressed_section_map::iterator p = this->compressed_sections_->begin(); + p != this->compressed_sections_->end(); + ++p) + { + if (p->second.contents != NULL) + { + delete[] p->second.contents; + p->second.contents = NULL; + } + } +} + // Input_objects methods. // Add a regular relocatable object to the list. Return false if this diff --git a/gold/object.h b/gold/object.h index 48aff5a422..9d3e1d736a 100644 --- a/gold/object.h +++ b/gold/object.h @@ -725,6 +725,20 @@ class Object section_size_type* uncompressed_size) const { return this->do_section_is_compressed(shndx, uncompressed_size); } + // Return a view of the uncompressed contents of a section. Set *PLEN + // to the size. Set *IS_NEW to true if the contents need to be freed + // by the caller. + const unsigned char* + decompressed_section_contents(unsigned int shndx, section_size_type* plen, + bool* is_cached) + { return this->do_decompressed_section_contents(shndx, plen, is_cached); } + + // Discard any buffers of decompressed sections. This is done + // at the end of the Add_symbols task. + void + discard_decompressed_sections() + { this->do_discard_decompressed_sections(); } + // Return the index of the first incremental relocation for symbol SYMNDX. unsigned int get_incremental_reloc_base(unsigned int symndx) const @@ -892,6 +906,27 @@ class Object do_section_is_compressed(unsigned int, section_size_type*) const { return false; } + // Return a view of the decompressed contents of a section. Set *PLEN + // to the size. This default implementation simply returns the + // raw section contents and sets *IS_NEW to false to indicate + // that the contents do not need to be freed by the caller. + // This function must be overridden for any types of object files + // that might contain compressed sections. + virtual const unsigned char* + do_decompressed_section_contents(unsigned int shndx, + section_size_type* plen, + bool* is_new) + { + *is_new = false; + return this->section_contents(shndx, plen, false); + } + + // Discard any buffers of decompressed sections. This is done + // at the end of the Add_symbols task. + virtual void + do_discard_decompressed_sections() + { } + // Return the index of the first incremental relocation for symbol SYMNDX-- // implemented by child class. virtual unsigned int @@ -1775,9 +1810,14 @@ class Reloc_symbol_changes std::vector vec_; }; -// Type for mapping section index to uncompressed size. +// Type for mapping section index to uncompressed size and contents. -typedef std::map Compressed_section_map; +struct Compressed_section_info +{ + section_size_type size; + const unsigned char* contents; +}; +typedef std::map Compressed_section_map; // Abstract base class for a regular object file, either a real object file // or an incremental (unchanged) object. This is size and endian specific. @@ -2319,12 +2359,25 @@ class Sized_relobj_file : public Sized_relobj if (p != this->compressed_sections_->end()) { if (uncompressed_size != NULL) - *uncompressed_size = p->second; + *uncompressed_size = p->second.size; return true; } return false; } + // Return a view of the uncompressed contents of a section. Set *PLEN + // to the size. Set *IS_NEW to true if the contents need to be deleted + // by the caller. + const unsigned char* + do_decompressed_section_contents(unsigned int shndx, + section_size_type* plen, + bool* is_new); + + // Discard any buffers of uncompressed sections. This is done + // at the end of the Add_symbols task. + void + do_discard_decompressed_sections(); + private: // For convenience. typedef Sized_relobj_file This; @@ -2609,7 +2662,8 @@ class Sized_relobj_file : public Sized_relobj std::vector deferred_layout_; // The list of relocation sections whose layout was deferred. std::vector deferred_layout_relocs_; - // For compressed debug sections, map section index to uncompressed size. + // For compressed debug sections, map section index to uncompressed size + // and contents. Compressed_section_map* compressed_sections_; }; diff --git a/gold/readsyms.cc b/gold/readsyms.cc index 997472284a..8e52ccb7f9 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -602,6 +602,7 @@ Add_symbols::run(Workqueue*) if (!this->input_objects_->add_object(this->object_)) { + this->object_->discard_decompressed_sections(); gold_assert(this->sd_ != NULL); delete this->sd_; this->sd_ = NULL; @@ -632,6 +633,7 @@ Add_symbols::run(Workqueue*) } this->object_->layout(this->symtab_, this->layout_, this->sd_); this->object_->add_symbols(this->symtab_, this->sd_, this->layout_); + this->object_->discard_decompressed_sections(); delete this->sd_; this->sd_ = NULL; this->object_->release();