public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [gold patch] Add incremental link support for debug sections
@ 2011-08-15 22:49 Cary Coutant
  2011-08-18 21:58 ` Cary Coutant
  0 siblings, 1 reply; 5+ messages in thread
From: Cary Coutant @ 2011-08-15 22:49 UTC (permalink / raw)
  To: Ian Lance Taylor, Binutils

[-- Attachment #1: Type: text/plain, Size: 2876 bytes --]

Debug sections are a problem for incremental linking because the
debugger and other consumers expect the .debug_info, .debug_types, and
.debug_line sections to contain a sequence of compile units, one after
the other. When adding patch space or leaving unused space in the
middle of a section during an incremental update, the resulting hole
makes the debug info unreadable. This patch fixes this by synthesizing
dummy compile unit headers in each hole. In order to guarantee that
any particular hole is large enough to hold a dummy header, I changed
the allocation method so that any chunk of free space left from an
allocation had to be a minimum size. (That, in turn, necessitated
adding some extra patch space to most of the incremental test cases.)

The dummy compile units for .debug_info and .debug_types work for
readelf/objdump, but not for gdb -- gdb insists on a
DW_TAG_compile_unit (or type_unit) DIE after each header, and I'm
generating a completely empty DIE tree. I'll submit a patch for gdb to
deal with that. (I prefer the empty DIE tree so that I don't have to
synthesize a fake debug abbrev table, too.) The dummy compile units
for .debug_line are filled with DW_LNS_set_basic_block opcodes --
basically no-ops as long as no row-creating opcodes are used.
(Technically, no consumer is supposed to read a .debug_line section
serially, but many do anyway -- they should instead follow the
DW_AT_stmt_list attribute from a compile_unit DIE.)

OK?

-cary

	* gold/layout.cc (Free_list::allocate): Provide guarantee of minimum
	remaining hole size when allocating.
	(Layout::make_output_section): Set fill methods for debug sections.
	* gold/layout.h (Free_list::Free_list_node): Move from private to
	public.
	(Free_list::set_min_hole_size): New function.
	(Free_list::begin, Free_list::end): New functions.
	(Free_list::min_hole_): New data member.
	* gold/output.cc: Include dwarf.h.
	(Output_fill_debug_info::do_minimum_hole_size): New function.
	(Output_fill_debug_info::do_write): New function.
	(Output_fill_debug_line::do_minimum_hole_size): New function.
	(Output_fill_debug_line::do_write): New function.
	(Output_section::Output_section): Initialize new data member.
	(Output_section::set_final_data_size): Ensure patch space is larger
	than minimum hole size.
	(Output_section::do_write): Fill holes in debug sections.
	* gold/output.h (Output_fill): New class.
	(Output_fill_debug_info): New class.
	(Output_fill_debug_line): New class.
	(Output_section::set_free_space_fill): New function.
	(Output_section::free_space_fill_): New data member.
	* gold/testsuite/Makefile.am (incremental_test_3): Add
	--incremental-patch option.
	(incremental_test_4): Likewise.
	(incremental_test_5): Likewise.
	(incremental_test_6): Likewise.
	(incremental_copy_test): Likewise.
	(incremental_common_test_1): Likewise.
	* gold/testsuite/Makefile.in: Regenerate.

[-- Attachment #2: incr-debug-patch.txt --]
[-- Type: text/plain, Size: 26659 bytes --]

2011-08-15  Cary Coutant  <ccoutant@google.com>

	* gold/layout.cc (Free_list::allocate): Provide guarantee of minimum
	remaining hole size when allocating.
	(Layout::make_output_section): Set fill methods for debug sections.
	* gold/layout.h (Free_list::Free_list_node): Move from private to
	public.
	(Free_list::set_min_hole_size): New function.
	(Free_list::begin, Free_list::end): New functions.
	(Free_list::min_hole_): New data member.
	* gold/output.cc: Include dwarf.h.
	(Output_fill_debug_info::do_minimum_hole_size): New function.
	(Output_fill_debug_info::do_write): New function.
	(Output_fill_debug_line::do_minimum_hole_size): New function.
	(Output_fill_debug_line::do_write): New function.
	(Output_section::Output_section): Initialize new data member.
	(Output_section::set_final_data_size): Ensure patch space is larger
	than minimum hole size.
	(Output_section::do_write): Fill holes in debug sections.
	* gold/output.h (Output_fill): New class.
	(Output_fill_debug_info): New class.
	(Output_fill_debug_line): New class.
	(Output_section::set_free_space_fill): New function.
	(Output_section::free_space_fill_): New data member.
	* gold/testsuite/Makefile.am (incremental_test_3): Add
	--incremental-patch option.
	(incremental_test_4): Likewise.
	(incremental_test_5): Likewise.
	(incremental_test_6): Likewise.
	(incremental_copy_test): Likewise.
	(incremental_common_test_1): Likewise.
	* gold/testsuite/Makefile.in: Regenerate.


diff --git a/gold/layout.cc b/gold/layout.cc
index 44c2e18..afb5b6a 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -162,6 +162,11 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
 
   ++Free_list::num_allocates;
 
+  // We usually want to drop free chunks smaller than 4 bytes.
+  // If we need to guarantee a minimum hole size, though, we need
+  // to keep track of all free chunks.
+  const int fuzz = this->min_hole_ > 0 ? 0 : 3;
+
   for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p)
     {
       ++Free_list::num_allocate_visits;
@@ -173,13 +178,13 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
 	  this->length_ = end;
 	  p->end_ = end;
 	}
-      if (end <= p->end_)
+      if (end == p->end_ || (end <= p->end_ - this->min_hole_))
 	{
-	  if (p->start_ + 3 >= start && p->end_ <= end + 3)
+	  if (p->start_ + fuzz >= start && p->end_ <= end + fuzz)
 	    this->list_.erase(p);
-	  else if (p->start_ + 3 >= start)
+	  else if (p->start_ + fuzz >= start)
 	    p->start_ = end;
-	  else if (p->end_ <= end + 3)
+	  else if (p->end_ <= end + fuzz)
 	    p->end_ = start;
 	  else
 	    {
@@ -1440,7 +1445,20 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
       && strcmp(name, ".ctors") != 0
       && strcmp(name, ".dtors") != 0
       && strcmp(name, ".jcr") != 0)
-    os->set_is_patch_space_allowed();
+    {
+      os->set_is_patch_space_allowed();
+
+      // Certain sections require "holes" to be filled with
+      // specific fill patterns.  These fill patterns may have
+      // a minimum size, so we must prevent allocations from the
+      // free list that leave a hole smaller than the minimum.
+      if (strcmp(name, ".debug_info") == 0)
+        os->set_free_space_fill(new Output_fill_debug_info(false));
+      else if (strcmp(name, ".debug_types") == 0)
+        os->set_free_space_fill(new Output_fill_debug_info(true));
+      else if (strcmp(name, ".debug_line") == 0)
+        os->set_free_space_fill(new Output_fill_debug_line());
+    }
 
   // If we have already attached the sections to segments, then we
   // need to attach this one now.  This happens for sections created
diff --git a/gold/layout.h b/gold/layout.h
index 1497f12..05cb50f 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -71,34 +71,60 @@ is_compressed_debug_section(const char* secname);
 class Free_list
 {
  public:
+  struct Free_list_node
+  {
+    Free_list_node(off_t start, off_t end)
+      : start_(start), end_(end)
+    { }
+    off_t start_;
+    off_t end_;
+  };
+  typedef std::list<Free_list_node>::const_iterator Const_iterator;
+
   Free_list()
-    : list_(), last_remove_(list_.begin()), extend_(false), length_(0)
+    : list_(), last_remove_(list_.begin()), extend_(false), length_(0),
+      min_hole_(0)
   { }
 
+  // Initialize the free list for a section of length LEN.
+  // If EXTEND is true, free space may be allocated past the end.
   void
   init(off_t len, bool extend);
 
+  // Set the minimum hole size that is allowed when allocating
+  // from the free list.
+  void
+  set_min_hole_size(off_t min_hole)
+  { this->min_hole_ = min_hole; }
+
+  // Remove a chunk from the free list.
   void
   remove(off_t start, off_t end);
 
+  // Allocate a chunk of space from the free list of length LEN,
+  // with alignment ALIGN, and minimum offset MINOFF.
   off_t
   allocate(off_t len, uint64_t align, off_t minoff);
 
+  // Return an iterator for the beginning of the free list.
+  Const_iterator
+  begin() const
+  { return this->list_.begin(); }
+
+  // Return an iterator for the end of the free list.
+  Const_iterator
+  end() const
+  { return this->list_.end(); }
+
+  // Dump the free list (for debugging).
   void
   dump();
 
+  // Print usage statistics.
   static void
   print_stats();
 
  private:
-  struct Free_list_node
-  {
-    Free_list_node(off_t start, off_t end)
-      : start_(start), end_(end)
-    { }
-    off_t start_;
-    off_t end_;
-  };
   typedef std::list<Free_list_node>::iterator Iterator;
 
   // The free list.
@@ -113,6 +139,10 @@ class Free_list
   // The total length of the section, segment, or file.
   off_t length_;
 
+  // The minimum hole size allowed.  When allocating from the free list,
+  // we must not leave a hole smaller than this.
+  off_t min_hole_;
+
   // Statistics:
   // The total number of free lists used.
   static unsigned int num_lists;
diff --git a/gold/output.cc b/gold/output.cc
index affc6f7..470290c 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -36,6 +36,7 @@
 
 #include "libiberty.h"
 
+#include "dwarf.h"
 #include "parameters.h"
 #include "object.h"
 #include "symtab.h"
@@ -1926,6 +1927,124 @@ Output_symtab_xindex::endian_do_write(unsigned char* const oview)
     }
 }
 
+// Output_fill_debug_info methods.
+
+size_t
+Output_fill_debug_info::do_minimum_hole_size() const
+{
+  // Compile unit header fields: unit_length, version, debug_abbrev_offset,
+  // address_size.
+  const size_t len = 4 + 2 + 4 + 1;
+  // For type units, add type_signature, type_offset.
+  if (this->is_debug_types_)
+    return len + 8 + 4;
+  return len;
+}
+
+void
+Output_fill_debug_info::do_write(Output_file* of, off_t off, size_t len) const
+{
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_info(%08lx, %08lx)", off, len);
+
+  gold_assert(len >= this->do_minimum_hole_size());
+
+  unsigned char* const oview = of->get_output_view(off, len);
+  unsigned char* pov = oview;
+
+  // Write header fields: unit_length, version, debug_abbrev_offset,
+  // address_size.
+  if (this->is_big_endian())
+    {
+      elfcpp::Swap<32, true>::writeval(pov, len - 4);
+      elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, true>::writeval(pov + 6, 0);
+    }
+  else
+    {
+      elfcpp::Swap<32, false>::writeval(pov, len - 4);
+      elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, false>::writeval(pov + 6, 0);
+    }
+  pov += 4 + 2 + 4;
+  *pov++ = 4;
+
+  // For type units, the additional header fields -- type_signature,
+  // type_offset -- can be filled with zeroes.
+
+  // Fill the remainder of the free space with zeroes.
+  if (pov < oview + len)
+    memset(pov, 0, oview + len - pov);
+
+  of->write_output_view(off, len, oview);
+}
+
+// Output_fill_debug_line methods.
+
+size_t
+Output_fill_debug_line::do_minimum_hole_size() const
+{
+  // Line number program header fields: unit_length, version, header_length,
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  const size_t len = 4 + 2 + 4 + this->header_length;
+  return len;
+}
+
+void
+Output_fill_debug_line::do_write(Output_file* of, off_t off, size_t len) const
+{
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_line(%08lx, %08lx)", off, len);
+
+  gold_assert(len >= this->do_minimum_hole_size());
+
+  unsigned char* const oview = of->get_output_view(off, len);
+  unsigned char* pov = oview;
+
+  // Write header fields: unit_length, version, header_length,
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  if (this->is_big_endian())
+    {
+      elfcpp::Swap<32, true>::writeval(pov, len - 4);
+      elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, true>::writeval(pov + 6, this->header_length);
+    }
+  else
+    {
+      elfcpp::Swap<32, false>::writeval(pov, len - 4);
+      elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, false>::writeval(pov + 6, this->header_length);
+    }
+  pov += 4 + 2 + 4;
+  *pov++ = 1;	// minimum_instruction_length
+  *pov++ = 0;	// default_is_stmt
+  *pov++ = 0;	// line_base
+  *pov++ = 5;	// line_range
+  *pov++ = 13;	// opcode_base
+  *pov++ = 0;	// standard_opcode_lengths[1]
+  *pov++ = 1;	// standard_opcode_lengths[2]
+  *pov++ = 1;	// standard_opcode_lengths[3]
+  *pov++ = 1;	// standard_opcode_lengths[4]
+  *pov++ = 1;	// standard_opcode_lengths[5]
+  *pov++ = 0;	// standard_opcode_lengths[6]
+  *pov++ = 0;	// standard_opcode_lengths[7]
+  *pov++ = 0;	// standard_opcode_lengths[8]
+  *pov++ = 1;	// standard_opcode_lengths[9]
+  *pov++ = 0;	// standard_opcode_lengths[10]
+  *pov++ = 0;	// standard_opcode_lengths[11]
+  *pov++ = 1;	// standard_opcode_lengths[12]
+  *pov++ = 0;	// include_directories (empty)
+  *pov++ = 0;	// filenames (empty)
+
+  // Fill the remainder of the free space with DW_LNS_set_basic_block
+  // opcodes.  These are effectively no-ops: the resulting line table
+  // program will not create any rows.
+  if (pov < oview + len)
+    memset(pov, elfcpp::DW_LNS_set_basic_block, oview + len - pov);
+
+  of->write_output_view(off, len, oview);
+}
+
 // Output_section::Input_section methods.
 
 // Return the current data size.  For an input section we store the size here.
@@ -2158,6 +2277,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
     free_list_(),
+    free_space_fill_(NULL),
     patch_space_(0)
 {
   // An unallocated section has no address.  Forcing this means that
@@ -2981,7 +3101,10 @@ Output_section::set_final_data_size()
   if (this->is_patch_space_allowed_ && parameters->incremental_full())
     {
       double pct = parameters->options().incremental_patch();
-      off_t extra = static_cast<off_t>(data_size * pct);
+      size_t extra = static_cast<size_t>(data_size * pct);
+      if (this->free_space_fill_ != NULL
+          && this->free_space_fill_->minimum_hole_size() > extra)
+	extra = this->free_space_fill_->minimum_hole_size();
       off_t new_size = align_address(data_size + extra, this->addralign());
       this->patch_space_ = new_size - data_size;
       gold_debug(DEBUG_INCREMENTAL,
@@ -3515,6 +3638,26 @@ Output_section::do_write(Output_file* of)
       p->write(of);
       off = aligned_off + p->data_size();
     }
+
+  // For incremental links, fill in unused chunks in debug sections
+  // with dummy compilation unit headers.
+  if (this->free_space_fill_ != NULL)
+    {
+      for (Free_list::Const_iterator p = this->free_list_.begin();
+	   p != this->free_list_.end();
+	   ++p)
+	{
+	  off_t off = p->start_;
+	  size_t len = p->end_ - off;
+	  this->free_space_fill_->write(of, this->offset() + off, len);
+	}
+      if (this->patch_space_ > 0)
+	{
+	  off_t off = this->current_data_size_for_child() - this->patch_space_;
+	  this->free_space_fill_->write(of, this->offset() + off,
+					this->patch_space_);
+	}
+    }
 }
 
 // If a section requires postprocessing, create the buffer to use.
diff --git a/gold/output.h b/gold/output.h
index 20869e6..5c0eb69 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -2615,6 +2615,98 @@ class Output_section_lookup_maps
   Relaxed_input_sections_by_id relaxed_input_sections_by_id_;
 };
 
+// This abstract base class defines the interface for the
+// types of methods used to fill free space left in an output
+// section during an incremental link.  These methods are used
+// to insert dummy compilation units into debug info so that
+// debug info consumers can scan the debug info serially.
+
+class Output_fill
+{
+ public:
+  Output_fill()
+  { this->is_big_endian_ = parameters->target().is_big_endian(); }
+
+  // Return the smallest size chunk of free space that can be
+  // filled with a dummy compilation unit.
+  size_t
+  minimum_hole_size() const
+  { return this->do_minimum_hole_size(); }
+
+  // Write a fill pattern of length LEN at offset OFF in the file.
+  void
+  write(Output_file* of, off_t off, size_t len) const
+  { this->do_write(of, off, len); }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const = 0;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const = 0;
+
+  bool
+  is_big_endian() const
+  { return this->is_big_endian_; }
+
+ private:
+  bool is_big_endian_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_info or .debug_types section.
+
+class Output_fill_debug_info : public Output_fill
+{
+ public:
+  Output_fill_debug_info(bool is_debug_types)
+    : is_debug_types_(is_debug_types)
+  { }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+  // Version of the header.
+  static const int version = 4;
+  // True if this is a .debug_types section.
+  bool is_debug_types_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_line section.
+
+class Output_fill_debug_line : public Output_fill
+{
+ public:
+  Output_fill_debug_line()
+  { }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+  // Version of the header.  We write a DWARF-3 header because it's smaller
+  // and many tools have not yet been updated to understand the DWARF-4 header.
+  static const int version = 3;
+  // Length of the portion of the header that follows the header_length
+  // field.  This includes the following fields:
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  // The standard_opcode_lengths array is 12 bytes long, and the
+  // include_directories and filenames fields each contain only a single
+  // null byte.
+  static const size_t header_length = 19;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -3438,6 +3530,15 @@ class Output_section : public Output_data
   set_is_patch_space_allowed()
   { this->is_patch_space_allowed_ = true; }
 
+  // Set a fill method to use for free space left in the output section
+  // during incremental links.
+  void
+  set_free_space_fill(Output_fill* free_space_fill)
+  {
+    this->free_space_fill_ = free_space_fill;
+    this->free_list_.set_min_hole_size(free_space_fill->minimum_hole_size());
+  }
+
   // Reserve space within the fixed layout for the section.  Used for
   // incremental update links.
   void
@@ -3913,6 +4014,8 @@ class Output_section : public Output_data
   // List of available regions within the section, for incremental
   // update links.
   Free_list free_list_;
+  // Method for filling chunks of free space.
+  Output_fill* free_space_fill_;
   // Amount added as patch space for incremental linking.
   off_t patch_space_;
 };
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 755c055..ca07f87 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -1966,7 +1966,7 @@ MOSTLYCLEANFILES += two_file_test_tmp_3.o
 incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 	@sleep 1
 	cp -f two_file_test_1b.o two_file_test_tmp_3.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
@@ -1976,7 +1976,7 @@ MOSTLYCLEANFILES += incremental_test_4.base two_file_test_tmp_4.o
 incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
 	mv -f incremental_test_4 incremental_test_4.base
 	@sleep 1
 	cp -f two_file_test_2.o two_file_test_tmp_4.o
@@ -1988,7 +1988,7 @@ incremental_test_5: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
 	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
 	@sleep 1
 	cp -f two_file_test_1b.o two_file_test_tmp_5.o
 	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
@@ -2002,7 +2002,7 @@ incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b.o two_file_test_tmp_6.o
 	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
 	@sleep 1
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
 	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
@@ -2011,7 +2011,7 @@ incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 check_PROGRAMS += incremental_copy_test
 incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 	cp -f copy_test_v1.o copy_test_tmp.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 	@sleep 1
 	cp -f copy_test.o copy_test_tmp.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
@@ -2019,7 +2019,7 @@ incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 check_PROGRAMS += incremental_common_test_1
 incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
 	cp -f common_test_1_v1.o common_test_1_tmp.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ common_test_1_tmp.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
 	@sleep 1
 	cp -f common_test_1_v2.o common_test_1_tmp.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index d937b7d..f0339fd 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -4942,14 +4942,14 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_3.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	mv -f incremental_test_4 incremental_test_4.base
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_2.o two_file_test_tmp_4.o
@@ -4958,7 +4958,7 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_5.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
@@ -4967,20 +4967,20 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_6.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_main.o -Wl,--incremental-unchanged two_file_test_6.a -Wl,--incremental-unknown
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f copy_test_v1.o copy_test_tmp.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f copy_test.o copy_test_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f common_test_1_v1.o common_test_1_tmp.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ common_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f common_test_1_v2.o common_test_1_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [gold patch] Add incremental link support for debug sections
  2011-08-15 22:49 [gold patch] Add incremental link support for debug sections Cary Coutant
@ 2011-08-18 21:58 ` Cary Coutant
  2011-08-28  9:16   ` Ian Lance Taylor
  2011-08-29 18:21   ` Jan Kratochvil
  0 siblings, 2 replies; 5+ messages in thread
From: Cary Coutant @ 2011-08-18 21:58 UTC (permalink / raw)
  To: Ian Lance Taylor, Binutils

[-- Attachment #1: Type: text/plain, Size: 2268 bytes --]

>        * gold/layout.cc (Free_list::allocate): Provide guarantee of minimum
>        remaining hole size when allocating.
>        (Layout::make_output_section): Set fill methods for debug sections.
>        * gold/layout.h (Free_list::Free_list_node): Move from private to
>        public.
>        (Free_list::set_min_hole_size): New function.
>        (Free_list::begin, Free_list::end): New functions.
>        (Free_list::min_hole_): New data member.
>        * gold/output.cc: Include dwarf.h.
>        (Output_fill_debug_info::do_minimum_hole_size): New function.
>        (Output_fill_debug_info::do_write): New function.
>        (Output_fill_debug_line::do_minimum_hole_size): New function.
>        (Output_fill_debug_line::do_write): New function.
>        (Output_section::Output_section): Initialize new data member.
>        (Output_section::set_final_data_size): Ensure patch space is larger
>        than minimum hole size.
>        (Output_section::do_write): Fill holes in debug sections.
>        * gold/output.h (Output_fill): New class.
>        (Output_fill_debug_info): New class.
>        (Output_fill_debug_line): New class.
>        (Output_section::set_free_space_fill): New function.
>        (Output_section::free_space_fill_): New data member.
>        * gold/testsuite/Makefile.am (incremental_test_3): Add
>        --incremental-patch option.
>        (incremental_test_4): Likewise.
>        (incremental_test_5): Likewise.
>        (incremental_test_6): Likewise.
>        (incremental_copy_test): Likewise.
>        (incremental_common_test_1): Likewise.
>        * gold/testsuite/Makefile.in: Regenerate.

Here is a slightly revised patch. I've added some missing comments for
the new classes, and changed the fill method for .debug_line to set
the header_length field to claim that the header spans the entire
hole. Consumers that (correctly) use header_length to find the
beginning of the line number program will see an empty line number
program. Consumers that (incorrectly, like readelf/objdump) assume
that the line number program begins immediately following the last
filename entry of the header will have to parse all the
"DW_LNS_set_basic_block" opcodes used as no-ops.

-cary

[-- Attachment #2: incr-debug-patch.txt --]
[-- Type: text/plain, Size: 27360 bytes --]

2011-08-18  Cary Coutant  <ccoutant@google.com>

	* layout.cc (Free_list::allocate): Provide guarantee of minimum
	remaining hole size when allocating.
	(Layout::make_output_section): Set fill methods for debug sections.
	* layout.h (Free_list::Free_list_node): Move from private to
	public.
	(Free_list::set_min_hole_size): New function.
	(Free_list::begin, Free_list::end): New functions.
	(Free_list::min_hole_): New data member.
	* output.cc: Include dwarf.h.
	(Output_fill_debug_info::do_minimum_hole_size): New function.
	(Output_fill_debug_info::do_write): New function.
	(Output_fill_debug_line::do_minimum_hole_size): New function.
	(Output_fill_debug_line::do_write): New function.
	(Output_section::Output_section): Initialize new data member.
	(Output_section::set_final_data_size): Ensure patch space is larger
	than minimum hole size.
	(Output_section::do_write): Fill holes in debug sections.
	* output.h (Output_fill): New class.
	(Output_fill_debug_info): New class.
	(Output_fill_debug_line): New class.
	(Output_section::set_free_space_fill): New function.
	(Output_section::free_space_fill_): New data member.
	* testsuite/Makefile.am (incremental_test_3): Add
	--incremental-patch option.
	(incremental_test_4): Likewise.
	(incremental_test_5): Likewise.
	(incremental_test_6): Likewise.
	(incremental_copy_test): Likewise.
	(incremental_common_test_1): Likewise.
	* testsuite/Makefile.in: Regenerate.


diff --git a/gold/layout.cc b/gold/layout.cc
index 44c2e18..afb5b6a 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -162,6 +162,11 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
 
   ++Free_list::num_allocates;
 
+  // We usually want to drop free chunks smaller than 4 bytes.
+  // If we need to guarantee a minimum hole size, though, we need
+  // to keep track of all free chunks.
+  const int fuzz = this->min_hole_ > 0 ? 0 : 3;
+
   for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p)
     {
       ++Free_list::num_allocate_visits;
@@ -173,13 +178,13 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
 	  this->length_ = end;
 	  p->end_ = end;
 	}
-      if (end <= p->end_)
+      if (end == p->end_ || (end <= p->end_ - this->min_hole_))
 	{
-	  if (p->start_ + 3 >= start && p->end_ <= end + 3)
+	  if (p->start_ + fuzz >= start && p->end_ <= end + fuzz)
 	    this->list_.erase(p);
-	  else if (p->start_ + 3 >= start)
+	  else if (p->start_ + fuzz >= start)
 	    p->start_ = end;
-	  else if (p->end_ <= end + 3)
+	  else if (p->end_ <= end + fuzz)
 	    p->end_ = start;
 	  else
 	    {
@@ -1440,7 +1445,20 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
       && strcmp(name, ".ctors") != 0
       && strcmp(name, ".dtors") != 0
       && strcmp(name, ".jcr") != 0)
-    os->set_is_patch_space_allowed();
+    {
+      os->set_is_patch_space_allowed();
+
+      // Certain sections require "holes" to be filled with
+      // specific fill patterns.  These fill patterns may have
+      // a minimum size, so we must prevent allocations from the
+      // free list that leave a hole smaller than the minimum.
+      if (strcmp(name, ".debug_info") == 0)
+        os->set_free_space_fill(new Output_fill_debug_info(false));
+      else if (strcmp(name, ".debug_types") == 0)
+        os->set_free_space_fill(new Output_fill_debug_info(true));
+      else if (strcmp(name, ".debug_line") == 0)
+        os->set_free_space_fill(new Output_fill_debug_line());
+    }
 
   // If we have already attached the sections to segments, then we
   // need to attach this one now.  This happens for sections created
diff --git a/gold/layout.h b/gold/layout.h
index 1497f12..05cb50f 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -71,34 +71,60 @@ is_compressed_debug_section(const char* secname);
 class Free_list
 {
  public:
+  struct Free_list_node
+  {
+    Free_list_node(off_t start, off_t end)
+      : start_(start), end_(end)
+    { }
+    off_t start_;
+    off_t end_;
+  };
+  typedef std::list<Free_list_node>::const_iterator Const_iterator;
+
   Free_list()
-    : list_(), last_remove_(list_.begin()), extend_(false), length_(0)
+    : list_(), last_remove_(list_.begin()), extend_(false), length_(0),
+      min_hole_(0)
   { }
 
+  // Initialize the free list for a section of length LEN.
+  // If EXTEND is true, free space may be allocated past the end.
   void
   init(off_t len, bool extend);
 
+  // Set the minimum hole size that is allowed when allocating
+  // from the free list.
+  void
+  set_min_hole_size(off_t min_hole)
+  { this->min_hole_ = min_hole; }
+
+  // Remove a chunk from the free list.
   void
   remove(off_t start, off_t end);
 
+  // Allocate a chunk of space from the free list of length LEN,
+  // with alignment ALIGN, and minimum offset MINOFF.
   off_t
   allocate(off_t len, uint64_t align, off_t minoff);
 
+  // Return an iterator for the beginning of the free list.
+  Const_iterator
+  begin() const
+  { return this->list_.begin(); }
+
+  // Return an iterator for the end of the free list.
+  Const_iterator
+  end() const
+  { return this->list_.end(); }
+
+  // Dump the free list (for debugging).
   void
   dump();
 
+  // Print usage statistics.
   static void
   print_stats();
 
  private:
-  struct Free_list_node
-  {
-    Free_list_node(off_t start, off_t end)
-      : start_(start), end_(end)
-    { }
-    off_t start_;
-    off_t end_;
-  };
   typedef std::list<Free_list_node>::iterator Iterator;
 
   // The free list.
@@ -113,6 +139,10 @@ class Free_list
   // The total length of the section, segment, or file.
   off_t length_;
 
+  // The minimum hole size allowed.  When allocating from the free list,
+  // we must not leave a hole smaller than this.
+  off_t min_hole_;
+
   // Statistics:
   // The total number of free lists used.
   static unsigned int num_lists;
diff --git a/gold/output.cc b/gold/output.cc
index affc6f7..12268c9 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -36,6 +36,7 @@
 
 #include "libiberty.h"
 
+#include "dwarf.h"
 #include "parameters.h"
 #include "object.h"
 #include "symtab.h"
@@ -1926,6 +1927,140 @@ Output_symtab_xindex::endian_do_write(unsigned char* const oview)
     }
 }
 
+// Output_fill_debug_info methods.
+
+// Return the minimum size needed for a dummy compilation unit header.
+
+size_t
+Output_fill_debug_info::do_minimum_hole_size() const
+{
+  // Compile unit header fields: unit_length, version, debug_abbrev_offset,
+  // address_size.
+  const size_t len = 4 + 2 + 4 + 1;
+  // For type units, add type_signature, type_offset.
+  if (this->is_debug_types_)
+    return len + 8 + 4;
+  return len;
+}
+
+// Write a dummy compilation unit header to fill a hole in the
+// .debug_info or .debug_types section.
+
+void
+Output_fill_debug_info::do_write(Output_file* of, off_t off, size_t len) const
+{
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_info(%08lx, %08lx)", off, len);
+
+  gold_assert(len >= this->do_minimum_hole_size());
+
+  unsigned char* const oview = of->get_output_view(off, len);
+  unsigned char* pov = oview;
+
+  // Write header fields: unit_length, version, debug_abbrev_offset,
+  // address_size.
+  if (this->is_big_endian())
+    {
+      elfcpp::Swap<32, true>::writeval(pov, len - 4);
+      elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, true>::writeval(pov + 6, 0);
+    }
+  else
+    {
+      elfcpp::Swap<32, false>::writeval(pov, len - 4);
+      elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, false>::writeval(pov + 6, 0);
+    }
+  pov += 4 + 2 + 4;
+  *pov++ = 4;
+
+  // For type units, the additional header fields -- type_signature,
+  // type_offset -- can be filled with zeroes.
+
+  // Fill the remainder of the free space with zeroes.  The first
+  // zero should tell the consumer there are no DIEs to read in this
+  // compilation unit.
+  if (pov < oview + len)
+    memset(pov, 0, oview + len - pov);
+
+  of->write_output_view(off, len, oview);
+}
+
+// Output_fill_debug_line methods.
+
+// Return the minimum size needed for a dummy line number program header.
+
+size_t
+Output_fill_debug_line::do_minimum_hole_size() const
+{
+  // Line number program header fields: unit_length, version, header_length,
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  const size_t len = 4 + 2 + 4 + this->header_length;
+  return len;
+}
+
+// Write a dummy line number program header to fill a hole in the
+// .debug_line section.
+
+void
+Output_fill_debug_line::do_write(Output_file* of, off_t off, size_t len) const
+{
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_line(%08lx, %08lx)", off, len);
+
+  gold_assert(len >= this->do_minimum_hole_size());
+
+  unsigned char* const oview = of->get_output_view(off, len);
+  unsigned char* pov = oview;
+
+  // Write header fields: unit_length, version, header_length,
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  // We set the header_length field to cover the entire hole, so the
+  // line number program is empty.
+  if (this->is_big_endian())
+    {
+      elfcpp::Swap<32, true>::writeval(pov, len - 4);
+      elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, true>::writeval(pov + 6, len - (4 + 2 + 4));
+    }
+  else
+    {
+      elfcpp::Swap<32, false>::writeval(pov, len - 4);
+      elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, false>::writeval(pov + 6, len - (4 + 2 + 4));
+    }
+  pov += 4 + 2 + 4;
+  *pov++ = 1;	// minimum_instruction_length
+  *pov++ = 0;	// default_is_stmt
+  *pov++ = 0;	// line_base
+  *pov++ = 5;	// line_range
+  *pov++ = 13;	// opcode_base
+  *pov++ = 0;	// standard_opcode_lengths[1]
+  *pov++ = 1;	// standard_opcode_lengths[2]
+  *pov++ = 1;	// standard_opcode_lengths[3]
+  *pov++ = 1;	// standard_opcode_lengths[4]
+  *pov++ = 1;	// standard_opcode_lengths[5]
+  *pov++ = 0;	// standard_opcode_lengths[6]
+  *pov++ = 0;	// standard_opcode_lengths[7]
+  *pov++ = 0;	// standard_opcode_lengths[8]
+  *pov++ = 1;	// standard_opcode_lengths[9]
+  *pov++ = 0;	// standard_opcode_lengths[10]
+  *pov++ = 0;	// standard_opcode_lengths[11]
+  *pov++ = 1;	// standard_opcode_lengths[12]
+  *pov++ = 0;	// include_directories (empty)
+  *pov++ = 0;	// filenames (empty)
+
+  // Some consumers don't check the header_length field, and simply
+  // start reading the line number program immediately following the
+  // header.  For those consumers, we fill the remainder of the free
+  // space with DW_LNS_set_basic_block opcodes.  These are effectively
+  // no-ops: the resulting line table program will not create any rows.
+  if (pov < oview + len)
+    memset(pov, elfcpp::DW_LNS_set_basic_block, oview + len - pov);
+
+  of->write_output_view(off, len, oview);
+}
+
 // Output_section::Input_section methods.
 
 // Return the current data size.  For an input section we store the size here.
@@ -2158,6 +2293,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
     free_list_(),
+    free_space_fill_(NULL),
     patch_space_(0)
 {
   // An unallocated section has no address.  Forcing this means that
@@ -2981,7 +3117,10 @@ Output_section::set_final_data_size()
   if (this->is_patch_space_allowed_ && parameters->incremental_full())
     {
       double pct = parameters->options().incremental_patch();
-      off_t extra = static_cast<off_t>(data_size * pct);
+      size_t extra = static_cast<size_t>(data_size * pct);
+      if (this->free_space_fill_ != NULL
+          && this->free_space_fill_->minimum_hole_size() > extra)
+	extra = this->free_space_fill_->minimum_hole_size();
       off_t new_size = align_address(data_size + extra, this->addralign());
       this->patch_space_ = new_size - data_size;
       gold_debug(DEBUG_INCREMENTAL,
@@ -3515,6 +3654,26 @@ Output_section::do_write(Output_file* of)
       p->write(of);
       off = aligned_off + p->data_size();
     }
+
+  // For incremental links, fill in unused chunks in debug sections
+  // with dummy compilation unit headers.
+  if (this->free_space_fill_ != NULL)
+    {
+      for (Free_list::Const_iterator p = this->free_list_.begin();
+	   p != this->free_list_.end();
+	   ++p)
+	{
+	  off_t off = p->start_;
+	  size_t len = p->end_ - off;
+	  this->free_space_fill_->write(of, this->offset() + off, len);
+	}
+      if (this->patch_space_ > 0)
+	{
+	  off_t off = this->current_data_size_for_child() - this->patch_space_;
+	  this->free_space_fill_->write(of, this->offset() + off,
+					this->patch_space_);
+	}
+    }
 }
 
 // If a section requires postprocessing, create the buffer to use.
diff --git a/gold/output.h b/gold/output.h
index 20869e6..5c0eb69 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -2615,6 +2615,98 @@ class Output_section_lookup_maps
   Relaxed_input_sections_by_id relaxed_input_sections_by_id_;
 };
 
+// This abstract base class defines the interface for the
+// types of methods used to fill free space left in an output
+// section during an incremental link.  These methods are used
+// to insert dummy compilation units into debug info so that
+// debug info consumers can scan the debug info serially.
+
+class Output_fill
+{
+ public:
+  Output_fill()
+  { this->is_big_endian_ = parameters->target().is_big_endian(); }
+
+  // Return the smallest size chunk of free space that can be
+  // filled with a dummy compilation unit.
+  size_t
+  minimum_hole_size() const
+  { return this->do_minimum_hole_size(); }
+
+  // Write a fill pattern of length LEN at offset OFF in the file.
+  void
+  write(Output_file* of, off_t off, size_t len) const
+  { this->do_write(of, off, len); }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const = 0;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const = 0;
+
+  bool
+  is_big_endian() const
+  { return this->is_big_endian_; }
+
+ private:
+  bool is_big_endian_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_info or .debug_types section.
+
+class Output_fill_debug_info : public Output_fill
+{
+ public:
+  Output_fill_debug_info(bool is_debug_types)
+    : is_debug_types_(is_debug_types)
+  { }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+  // Version of the header.
+  static const int version = 4;
+  // True if this is a .debug_types section.
+  bool is_debug_types_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_line section.
+
+class Output_fill_debug_line : public Output_fill
+{
+ public:
+  Output_fill_debug_line()
+  { }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+  // Version of the header.  We write a DWARF-3 header because it's smaller
+  // and many tools have not yet been updated to understand the DWARF-4 header.
+  static const int version = 3;
+  // Length of the portion of the header that follows the header_length
+  // field.  This includes the following fields:
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  // The standard_opcode_lengths array is 12 bytes long, and the
+  // include_directories and filenames fields each contain only a single
+  // null byte.
+  static const size_t header_length = 19;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -3438,6 +3530,15 @@ class Output_section : public Output_data
   set_is_patch_space_allowed()
   { this->is_patch_space_allowed_ = true; }
 
+  // Set a fill method to use for free space left in the output section
+  // during incremental links.
+  void
+  set_free_space_fill(Output_fill* free_space_fill)
+  {
+    this->free_space_fill_ = free_space_fill;
+    this->free_list_.set_min_hole_size(free_space_fill->minimum_hole_size());
+  }
+
   // Reserve space within the fixed layout for the section.  Used for
   // incremental update links.
   void
@@ -3913,6 +4014,8 @@ class Output_section : public Output_data
   // List of available regions within the section, for incremental
   // update links.
   Free_list free_list_;
+  // Method for filling chunks of free space.
+  Output_fill* free_space_fill_;
   // Amount added as patch space for incremental linking.
   off_t patch_space_;
 };
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 755c055..ca07f87 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -1966,7 +1966,7 @@ MOSTLYCLEANFILES += two_file_test_tmp_3.o
 incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 	@sleep 1
 	cp -f two_file_test_1b.o two_file_test_tmp_3.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
@@ -1976,7 +1976,7 @@ MOSTLYCLEANFILES += incremental_test_4.base two_file_test_tmp_4.o
 incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
 	mv -f incremental_test_4 incremental_test_4.base
 	@sleep 1
 	cp -f two_file_test_2.o two_file_test_tmp_4.o
@@ -1988,7 +1988,7 @@ incremental_test_5: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
 	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
 	@sleep 1
 	cp -f two_file_test_1b.o two_file_test_tmp_5.o
 	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
@@ -2002,7 +2002,7 @@ incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b.o two_file_test_tmp_6.o
 	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
 	@sleep 1
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
 	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
@@ -2011,7 +2011,7 @@ incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 check_PROGRAMS += incremental_copy_test
 incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 	cp -f copy_test_v1.o copy_test_tmp.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 	@sleep 1
 	cp -f copy_test.o copy_test_tmp.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
@@ -2019,7 +2019,7 @@ incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 check_PROGRAMS += incremental_common_test_1
 incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
 	cp -f common_test_1_v1.o common_test_1_tmp.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ common_test_1_tmp.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
 	@sleep 1
 	cp -f common_test_1_v2.o common_test_1_tmp.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index d937b7d..f0339fd 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -4942,14 +4942,14 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_3.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	mv -f incremental_test_4 incremental_test_4.base
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_2.o two_file_test_tmp_4.o
@@ -4958,7 +4958,7 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_5.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
@@ -4967,20 +4967,20 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_6.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_main.o -Wl,--incremental-unchanged two_file_test_6.a -Wl,--incremental-unknown
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f copy_test_v1.o copy_test_tmp.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f copy_test.o copy_test_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f common_test_1_v1.o common_test_1_tmp.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ common_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f common_test_1_v2.o common_test_1_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [gold patch] Add incremental link support for debug sections
  2011-08-18 21:58 ` Cary Coutant
@ 2011-08-28  9:16   ` Ian Lance Taylor
  2011-08-29 18:21   ` Jan Kratochvil
  1 sibling, 0 replies; 5+ messages in thread
From: Ian Lance Taylor @ 2011-08-28  9:16 UTC (permalink / raw)
  To: Cary Coutant; +Cc: Binutils

Cary Coutant <ccoutant@google.com> writes:

>>        * gold/layout.cc (Free_list::allocate): Provide guarantee of minimum
>>        remaining hole size when allocating.
>>        (Layout::make_output_section): Set fill methods for debug sections.
>>        * gold/layout.h (Free_list::Free_list_node): Move from private to
>>        public.
>>        (Free_list::set_min_hole_size): New function.
>>        (Free_list::begin, Free_list::end): New functions.
>>        (Free_list::min_hole_): New data member.
>>        * gold/output.cc: Include dwarf.h.
>>        (Output_fill_debug_info::do_minimum_hole_size): New function.
>>        (Output_fill_debug_info::do_write): New function.
>>        (Output_fill_debug_line::do_minimum_hole_size): New function.
>>        (Output_fill_debug_line::do_write): New function.
>>        (Output_section::Output_section): Initialize new data member.
>>        (Output_section::set_final_data_size): Ensure patch space is larger
>>        than minimum hole size.
>>        (Output_section::do_write): Fill holes in debug sections.
>>        * gold/output.h (Output_fill): New class.
>>        (Output_fill_debug_info): New class.
>>        (Output_fill_debug_line): New class.
>>        (Output_section::set_free_space_fill): New function.
>>        (Output_section::free_space_fill_): New data member.
>>        * gold/testsuite/Makefile.am (incremental_test_3): Add
>>        --incremental-patch option.
>>        (incremental_test_4): Likewise.
>>        (incremental_test_5): Likewise.
>>        (incremental_test_6): Likewise.
>>        (incremental_copy_test): Likewise.
>>        (incremental_common_test_1): Likewise.
>>        * gold/testsuite/Makefile.in: Regenerate.


> +class Output_fill
> +{
> + public:
> +  Output_fill()
> +  { this->is_big_endian_ = parameters->target().is_big_endian(); }

Why not just write
    : is_big_endian_(parameters->target().is_big_endian())
  { }


This is OK with or without that change.

Thanks.

Ian

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [gold patch] Add incremental link support for debug sections
  2011-08-18 21:58 ` Cary Coutant
  2011-08-28  9:16   ` Ian Lance Taylor
@ 2011-08-29 18:21   ` Jan Kratochvil
  2011-08-30 10:28     ` Cary Coutant
  1 sibling, 1 reply; 5+ messages in thread
From: Jan Kratochvil @ 2011-08-29 18:21 UTC (permalink / raw)
  To: Cary Coutant; +Cc: Ian Lance Taylor, Binutils

On Thu, 18 Aug 2011 23:57:52 +0200, Cary Coutant wrote:
> 2011-08-18  Cary Coutant  <ccoutant@google.com>
> 
> 	* layout.cc (Free_list::allocate): Provide guarantee of minimum
> 	remaining hole size when allocating.
> 	(Layout::make_output_section): Set fill methods for debug sections.
> 	* layout.h (Free_list::Free_list_node): Move from private to
> 	public.
> 	(Free_list::set_min_hole_size): New function.
> 	(Free_list::begin, Free_list::end): New functions.
> 	(Free_list::min_hole_): New data member.
> 	* output.cc: Include dwarf.h.
> 	(Output_fill_debug_info::do_minimum_hole_size): New function.
> 	(Output_fill_debug_info::do_write): New function.
> 	(Output_fill_debug_line::do_minimum_hole_size): New function.
> 	(Output_fill_debug_line::do_write): New function.
> 	(Output_section::Output_section): Initialize new data member.
> 	(Output_section::set_final_data_size): Ensure patch space is larger
> 	than minimum hole size.
> 	(Output_section::do_write): Fill holes in debug sections.
> 	* output.h (Output_fill): New class.
> 	(Output_fill_debug_info): New class.
> 	(Output_fill_debug_line): New class.
> 	(Output_section::set_free_space_fill): New function.
> 	(Output_section::free_space_fill_): New data member.
> 	* testsuite/Makefile.am (incremental_test_3): Add
> 	--incremental-patch option.
> 	(incremental_test_4): Likewise.
> 	(incremental_test_5): Likewise.
> 	(incremental_test_6): Likewise.
> 	(incremental_copy_test): Likewise.
> 	(incremental_common_test_1): Likewise.
> 	* testsuite/Makefile.in: Regenerate.

on i686-fedora16pre-linux-gnu (gcc-4.6.1-8.fc16.i686) getting:

output.cc: In member function ‘virtual void gold::Output_fill_debug_info::do_write(gold::Output_file*, off_t, size_t) const’:
output.cc:1952:3: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘off_t {aka long long int}’ [-Werror=format]
output.cc:1952:3: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t {aka unsigned int}’ [-Werror=format]
output.cc: In member function ‘virtual void gold::Output_fill_debug_line::do_write(gold::Output_file*, off_t, size_t) const’:
output.cc:2008:3: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘off_t {aka long long int}’ [-Werror=format]
output.cc:2008:3: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t {aka unsigned int}’ [-Werror=format]
cc1plus: all warnings being treated as errors


Thanks,
Jan

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [gold patch] Add incremental link support for debug sections
  2011-08-29 18:21   ` Jan Kratochvil
@ 2011-08-30 10:28     ` Cary Coutant
  0 siblings, 0 replies; 5+ messages in thread
From: Cary Coutant @ 2011-08-30 10:28 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Ian Lance Taylor, Binutils

> on i686-fedora16pre-linux-gnu (gcc-4.6.1-8.fc16.i686) getting:
>
> output.cc: In member function ‘virtual void gold::Output_fill_debug_info::do_write(gold::Output_file*, off_t, size_t) const’:
> output.cc:1952:3: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘off_t {aka long long int}’ [-Werror=format]
> ...

Sorry! Applying the following patch as obvious...

-cary


	* output.cc: (Output_fill_debug_info::do_minimum_hole_size): Add
	casts to match formatting specs.
	(Output_fill_debug_line::do_minimum_hole_size): Likewise.


Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.157
diff -u -p -r1.157 output.cc
--- output.cc	27 Aug 2011 01:28:17 -0000	1.157
+++ output.cc	29 Aug 2011 18:09:58 -0000
@@ -1949,7 +1949,8 @@ Output_fill_debug_info::do_minimum_hole_
 void
 Output_fill_debug_info::do_write(Output_file* of, off_t off, size_t len) const
 {
-  gold_debug(DEBUG_INCREMENTAL, "fill_debug_info(%08lx, %08lx)", off, len);
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_info(%08lx, %08lx)",
+	     static_cast<long>(off), static_cast<long>(len));

   gold_assert(len >= this->do_minimum_hole_size());

@@ -2005,7 +2006,8 @@ Output_fill_debug_line::do_minimum_hole_
 void
 Output_fill_debug_line::do_write(Output_file* of, off_t off, size_t len) const
 {
-  gold_debug(DEBUG_INCREMENTAL, "fill_debug_line(%08lx, %08lx)", off, len);
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_line(%08lx, %08lx)",
+	     static_cast<long>(off), static_cast<long>(len));

   gold_assert(len >= this->do_minimum_hole_size());

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-08-29 18:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-15 22:49 [gold patch] Add incremental link support for debug sections Cary Coutant
2011-08-18 21:58 ` Cary Coutant
2011-08-28  9:16   ` Ian Lance Taylor
2011-08-29 18:21   ` Jan Kratochvil
2011-08-30 10:28     ` Cary Coutant

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).