diff --git a/gold/ChangeLog b/gold/ChangeLog
index 292d3019fe0..4e92270437d 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,33 @@
+2011-05-26 Cary Coutant  <ccoutant@google.com>
+
+	* incremental-dump.cc (dump_incremental_inputs): Print COMDAT groups.
+	* incremental.cc (Incremental_inputs::report_input_section): Fix
+	comment, indentation.
+	(Incremental_inputs::report_comdat_group): New function.
+	(Output_section_incremental_inputs::set_final_data_size): Adjust size
+	of data for incremental input file entry.
+	(Output_section_incremental_inputs::write_info_blocks): Write COMDAT
+	group count, COMDAT group signatures.
+	(Sized_incr_relobj::do_layout): Record kept COMDAT group info from
+	an unchanged input file.
+	* incremental.h (Incremental_object_entry::Incremental_object_entry):
+	Initialize new data member.
+	(Incremental_object_entry::add_comdat_group): New function.
+	(Incremental_object_entry::get_comdat_group_count): New function.
+	(Incremental_object_entry::get_comdat_signature_key): New function.
+	(Incremental_object_entry::groups_): New data member.
+	(Incremental_inputs::report_comdat_group): New function.
+	(Incremental_input_entry_reader::get_symbol_offset): Adjust size of
+	data for incremental input file entry.
+	(Incremental_input_entry_reader::get_comdat_group_count): New function.
+	(Incremental_input_entry_reader::get_input_section): Adjust size of
+	data for incremental input file entry.
+	(Incremental_input_entry_reader::get_global_symbol_reader): Likewise.
+	(Incremental_input_entry_reader::get_comdat_group_signature): New
+	function.
+	* object.cc (Sized_relobj::include_section_group): Report kept
+	COMDAT groups for incremental links.
+
 2011-05-24  David Meyer  <pdox@google.com>
 
 	* dirsearch.cc (Dirsearch::find): Replace n1 and n2 parameters
diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc
index a727eb50384..fff4637617a 100644
--- a/gold/incremental-dump.cc
+++ b/gold/incremental-dump.cc
@@ -153,6 +153,8 @@ dump_incremental_inputs(const char* argv0, const char* filename,
 		 input_file.get_first_dyn_reloc());
 	  printf("    Dynamic reloc count: %d\n",
 		 input_file.get_dyn_reloc_count());
+	  printf("    COMDAT group count: %d\n",
+		 input_file.get_comdat_group_count());
 	  break;
 	case INCREMENTAL_INPUT_ARCHIVE:
 	  printf("Archive\n");
@@ -212,6 +214,11 @@ dump_incremental_inputs(const char* argv0, const char* filename,
 		 static_cast<long long>(info.sh_size),
 		 info.name);
 	}
+
+      unsigned int ncomdat = input_file.get_comdat_group_count();
+      for (unsigned int i = 0; i < ncomdat; ++i)
+	printf("    Comdat group: %s\n",
+	       input_file.get_comdat_group_signature(i));
     }
 
   // Get a view of the .symtab section.
diff --git a/gold/incremental.cc b/gold/incremental.cc
index a27afeef1c9..f4eb22c50bf 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -1028,9 +1028,7 @@ Incremental_inputs::report_object(Object* obj, unsigned int arg_serial,
     }
 }
 
-// Record the input object file OBJ.  If ARCH is not NULL, attach
-// the object file to the archive.  This is called by the
-// Add_symbols task after finding out the type of the file.
+// Record an input section SHNDX from object file OBJ.
 
 void
 Incremental_inputs::report_input_section(Object* obj, unsigned int shndx,
@@ -1039,13 +1037,27 @@ Incremental_inputs::report_input_section(Object* obj, unsigned int shndx,
   Stringpool::Key key = 0;
 
   if (name != NULL)
-      this->strtab_->add(name, true, &key);
+    this->strtab_->add(name, true, &key);
 
   gold_assert(obj == this->current_object_);
   gold_assert(this->current_object_entry_ != NULL);
   this->current_object_entry_->add_input_section(shndx, key, sh_size);
 }
 
+// Record a kept COMDAT group belonging to object file OBJ.
+
+void
+Incremental_inputs::report_comdat_group(Object* obj, const char* name)
+{
+  Stringpool::Key key = 0;
+
+  if (name != NULL)
+    this->strtab_->add(name, true, &key);
+  gold_assert(obj == this->current_object_);
+  gold_assert(this->current_object_entry_ != NULL);
+  this->current_object_entry_->add_comdat_group(key);
+}
+
 // Record that the input argument INPUT is a script SCRIPT.  This is
 // called by read_script after parsing the script and reading the list
 // of inputs added by this script.
@@ -1173,14 +1185,17 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
 	    gold_assert(entry != NULL);
 	    (*p)->set_info_offset(info_offset);
 	    // Input section count, global symbol count, local symbol offset,
-	    // local symbol count, first dynamic reloc, dynamic reloc count.
-	    info_offset += 24;
+	    // local symbol count, first dynamic reloc, dynamic reloc count,
+	    // comdat group count.
+	    info_offset += 28;
 	    // Each input section.
 	    info_offset += (entry->get_input_section_count()
 			    * (8 + 2 * sizeof_addr));
 	    // Each global symbol.
 	    const Object::Symbols* syms = entry->object()->get_global_symbols();
 	    info_offset += syms->size() * 20;
+	    // Each comdat group.
+	    info_offset += entry->get_comdat_group_count() * 4;
 	  }
 	  break;
 	case INCREMENTAL_INPUT_SHARED_LIBRARY:
@@ -1424,13 +1439,15 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
 	    unsigned int nlocals = relobj->output_local_symbol_count();
 	    unsigned int first_dynrel = relobj->first_dyn_reloc();
 	    unsigned int ndynrel = relobj->dyn_reloc_count();
+	    unsigned int ncomdat = entry->get_comdat_group_count();
 	    Swap32::writeval(pov, nsections);
 	    Swap32::writeval(pov + 4, nsyms);
 	    Swap32::writeval(pov + 8, static_cast<unsigned int>(locals_offset));
 	    Swap32::writeval(pov + 12, nlocals);
 	    Swap32::writeval(pov + 16, first_dynrel);
 	    Swap32::writeval(pov + 20, ndynrel);
-	    pov += 24;
+	    Swap32::writeval(pov + 24, ncomdat);
+	    pov += 28;
 
 	    // Build a temporary array to map input section indexes
 	    // from the original object file index to the index in the
@@ -1507,6 +1524,17 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
 		pov += 20;
 	      }
 
+	    // For each kept COMDAT group, write the group signature.
+	    for (unsigned int i = 0; i < ncomdat; i++)
+	      {
+		Stringpool::Key key = entry->get_comdat_signature_key(i);
+		off_t name_offset = 0;
+		if (key != 0)
+		  name_offset = strtab->get_offset_from_key(key);
+		Swap32::writeval(pov, name_offset);
+		pov += 4;
+	      }
+
 	    delete[] index_map;
 	  }
 	  break;
@@ -1862,6 +1890,20 @@ Sized_relobj_incr<size, big_endian>::do_layout(
       out_sections[i] = os;
       this->section_offsets()[i] = static_cast<Address>(sect.sh_offset);
     }
+
+  // Process the COMDAT groups.
+  unsigned int ncomdat = this->input_reader_.get_comdat_group_count();
+  for (unsigned int i = 0; i < ncomdat; i++)
+    {
+      const char* signature = this->input_reader_.get_comdat_group_signature(i);
+      if (signature == NULL || signature[0] == '\0')
+        this->error(_("COMDAT group has no signature"));
+      bool keep = layout->find_or_add_kept_section(signature, this, i, true,
+						   true, NULL);
+      if (!keep)
+        this->error(_("COMDAT group %s included twice in incremental link"),
+		    signature);
+    }
 }
 
 // Layout sections whose layout was deferred while waiting for
diff --git a/gold/incremental.h b/gold/incremental.h
index dc8ef33e058..f1fd1f88ae1 100644
--- a/gold/incremental.h
+++ b/gold/incremental.h
@@ -325,7 +325,7 @@ class Incremental_object_entry : public Incremental_input_entry
   Incremental_object_entry(Stringpool::Key filename_key, Object* obj,
 			   unsigned int arg_serial, Timespec mtime)
     : Incremental_input_entry(filename_key, arg_serial, mtime), obj_(obj),
-      is_member_(false), sections_()
+      is_member_(false), sections_(), groups_()
   { this->sections_.reserve(obj->shnum()); }
 
   // Get the object.
@@ -368,6 +368,21 @@ class Incremental_object_entry : public Incremental_input_entry
   get_input_section_size(unsigned int n) const
   { return this->sections_[n].sh_size_; }
 
+  // Add a kept COMDAT group.
+  void
+  add_comdat_group(Stringpool::Key signature_key)
+  { this->groups_.push_back(signature_key); }
+
+  // Return the number of COMDAT groups.
+  unsigned int
+  get_comdat_group_count() const
+  { return this->groups_.size(); }
+
+  // Return the stringpool key for the signature of the Nth comdat group.
+  Stringpool::Key
+  get_comdat_signature_key(unsigned int n) const
+  { return this->groups_[n]; }
+
  protected:
   virtual Incremental_input_type
   do_type() const
@@ -400,6 +415,9 @@ class Incremental_object_entry : public Incremental_input_entry
     off_t sh_size_;
   };
   std::vector<Input_section> sections_;
+
+  // COMDAT groups.
+  std::vector<Stringpool::Key> groups_;
 };
 
 // Class for recording shared library input files.
@@ -546,6 +564,10 @@ class Incremental_inputs
   report_input_section(Object* obj, unsigned int shndx, const char* name,
 		       off_t sh_size);
 
+  // Record a kept COMDAT group belonging to object file OBJ.
+  void
+  report_comdat_group(Object* obj, const char* name);
+
   // Record the info for input script SCRIPT.
   void
   report_script(Script_info* script, unsigned int arg_serial,
@@ -814,7 +836,7 @@ class Incremental_inputs_reader
 		  || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
 
       unsigned int section_count = this->get_input_section_count();
-      return (this->info_offset_ + 24
+      return (this->info_offset_ + 28
 	      + section_count * input_section_entry_size
 	      + symndx * 20);
     }
@@ -869,6 +891,16 @@ class Incremental_inputs_reader
       return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 20);
     }
 
+    // Return the COMDAT group count -- for objects only.
+    unsigned int
+    get_comdat_group_count() const
+    {
+      gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+		  || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+
+      return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 24);
+    }
+
     // Return the object count -- for scripts only.
     unsigned int
     get_object_count() const
@@ -939,7 +971,7 @@ class Incremental_inputs_reader
     {
       Input_section_info info;
       const unsigned char* p = (this->inputs_->p_
-				+ this->info_offset_ + 24
+				+ this->info_offset_ + 28
 				+ n * input_section_entry_size);
       unsigned int name_offset = Swap32::readval(p);
       info.name = this->inputs_->get_string(name_offset);
@@ -957,12 +989,27 @@ class Incremental_inputs_reader
 		  || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
       unsigned int section_count = this->get_input_section_count();
       const unsigned char* p = (this->inputs_->p_
-				+ this->info_offset_ + 24
+				+ this->info_offset_ + 28
 				+ section_count * input_section_entry_size
 				+ n * 20);
       return Incremental_global_symbol_reader<big_endian>(p);
     }
 
+    // Return the signature of the Nth comdat group -- for objects only.
+    const char*
+    get_comdat_group_signature(unsigned int n) const
+    {
+      unsigned int section_count = this->get_input_section_count();
+      unsigned int symbol_count = this->get_global_symbol_count();
+      const unsigned char* p = (this->inputs_->p_
+				+ this->info_offset_ + 28
+				+ section_count * input_section_entry_size
+				+ symbol_count * 20
+				+ n * 4);
+      unsigned int name_offset = Swap32::readval(p);
+      return this->inputs_->get_string(name_offset);
+    }
+
     // Return the output symbol index for the Nth global symbol -- for shared
     // libraries only.  Sets *IS_DEF to TRUE if the symbol is defined in this
     // input file.
diff --git a/gold/object.cc b/gold/object.cc
index 1160f0cf6af..b14c85db87a 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -825,6 +825,13 @@ Sized_relobj_file<size, big_endian>::include_section_group(
       is_comdat = true;
     }
 
+  if (is_comdat && include_group)
+    {
+      Incremental_inputs* incremental_inputs = layout->incremental_inputs();
+      if (incremental_inputs != NULL)
+	incremental_inputs->report_comdat_group(this, signature.c_str());
+    }
+
   size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word);
 
   std::vector<unsigned int> shndxes;