* dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info):
authorCary Coutant <ccoutant@google.com>
Wed, 29 Feb 2012 21:22:29 +0000 (21:22 +0000)
committerCary Coutant <ccoutant@google.com>
Wed, 29 Feb 2012 21:22:29 +0000 (21:22 +0000)
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
gold/dwarf_reader.cc
gold/dwarf_reader.h
gold/merge.cc
gold/object.cc
gold/object.h
gold/readsyms.cc

index 47ec2ec0fe9203553f3d49b64265a6176ee3fa21..08a69c0d53a991f16f5715ea4bcc06c08aabeea0 100644 (file)
@@ -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.
index 2b47a28b1762f0d7de0504474ea08b2821d32707..73f84b0d420fcfd84db282714a762c77ea827a7f 100644 (file)
@@ -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;
index 3f92dd3eea2dcd7ede989e79e66a6b33f86fa94c..722ee647afd7b13d7896515653f403587b30f40f 100644 (file)
@@ -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_;
index 093b6fc692f5e495574aca5226a7630d8836c036..dde43e9b124d1cc2566031adefab687f86144ad5 100644 (file)
@@ -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;
 }
index bbeb9af9b92fd29d8d828785b43acbcbf30cce0d..f30354e87305e108f8def9fb9855140d23e13c6d 100644 (file)
@@ -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
index 48aff5a422a3d95e8c26aa01c6e0471049802f4f..9d3e1d736a91ae1f1cd0ba48d07006c90e71debe 100644 (file)
@@ -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_;
 };
 
index 997472284ae5c2730ea73d1dfb0a20707be08bf3..8e52ccb7f9f21e457d6668df44e73eb5d4d1c7ce 100644 (file)
@@ -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();