aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog23
-rw-r--r--gold/dwarf_reader.cc33
-rw-r--r--gold/dwarf_reader.h11
-rw-r--r--gold/merge.cc51
-rw-r--r--gold/object.cc130
-rw-r--r--gold/object.h62
-rw-r--r--gold/readsyms.cc2
7 files changed, 246 insertions, 66 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 47ec2ec..08a69c0 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,26 @@
+2012-02-29 Cary Coutant <ccoutant@google.com>
+
+ * 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 <ccoutant@google.com>
* testsuite/Makefile.am (initpri2): Add --ctors-in-init-array option.
diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc
index 2b47a28..73f84b0 100644
--- a/gold/dwarf_reader.cc
+++ b/gold/dwarf_reader.cc
@@ -62,12 +62,14 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt)
}
template<int size, bool big_endian>
-Sized_dwarf_line_info<size, big_endian>::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<size, big_endian>::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<size, big_endian>::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<size, big_endian>::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 3f92dd3..722ee64 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<size, big_endian> track_relocs_;
diff --git a/gold/merge.cc b/gold/merge.cc
index 093b6fc..dde43e9 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<Char_type>::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<const Char_type*>(pdata);
const Char_type* pend = p + len / sizeof(Char_type);
@@ -540,8 +519,8 @@ Output_merge_string<Char_type>::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<Char_type>::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 bbeb9af..f30354e 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -550,8 +550,22 @@ Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
Compressed_section_map*
@@ -562,9 +576,10 @@ build_compressed_section_map(
section_size_type names_size,
Sized_relobj_file<size, big_endian>* 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<size>::shdr_size;
const unsigned char* p = pshdrs + shdr_size;
+
for (unsigned int i = 1; i < shnum; ++i, p += shdr_size)
{
typename elfcpp::Shdr<size, big_endian> 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<size, big_endian>::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<int size, bool big_endian>
+const unsigned char*
+Sized_relobj_file<size, big_endian>::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<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::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 48aff5a..9d3e1d7 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<Symbol*> vec_;
};
-// Type for mapping section index to uncompressed size.
+// Type for mapping section index to uncompressed size and contents.
-typedef std::map<unsigned int, section_size_type> Compressed_section_map;
+struct Compressed_section_info
+{
+ section_size_type size;
+ const unsigned char* contents;
+};
+typedef std::map<unsigned int, Compressed_section_info> 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<size, big_endian>
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<size, big_endian> This;
@@ -2609,7 +2662,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
std::vector<Deferred_layout> deferred_layout_;
// The list of relocation sections whose layout was deferred.
std::vector<Deferred_layout> 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 9974722..8e52ccb 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();