]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
elfcpp/:
authorIan Lance Taylor <ian@airs.com>
Fri, 9 Oct 2009 22:38:07 +0000 (22:38 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 9 Oct 2009 22:38:07 +0000 (22:38 +0000)
* elf_file.h: (class Elf_strtab): New class.
gold/:
* gold.cc: (queue_initial_tasks): Pass incremental_inputs to
Incremental_checker.
* incremental.cc: (INCREMENTAL_LINK_VERSION): Change type to
unsigned int.
(class Incremental_inputs_header): New class.
(Incremental_inputs_header_writer): Edit comment.
(Incremental_inputs_entry): New class.
(Incremental_inputs_entry_writer): Edit comment.
(Sized_incremental_binary::do_find_incremental_inputs_section):
Add *strtab_shndx parameter, fill it.
(Sized_incremental_binary::do_check_inputs): New method.
(Incremental_checker::can_incrementally_link_output_file): Use
Sized_incremental_binary::check_inputs.
(Incremental_inputs::report_command_line): Save command line in
command_line_.
* incremental.h:
(Incremental_binary::find_incremental_inputs_section): New
method.
(Incremental_binary::do_find_incremental_inputs_section): Add
strtab_shndx parameter.
(Incremental_binary::do_check_inputs): New pure virtual method.
(Sized_incremental_binary::do_check_inputs): Declare.
(Incremental_checker::Incremental_checker): Add incremental_inputs
parameter, use it to initialize incremental_inputs_.
(Incremental_checker::incremental_inputs_): New field.
(Incremental_checker::command_line): New method.
(Incremental_checker::inputs): New method.
(Incremental_checker::command_line_): New field.

elfcpp/ChangeLog
elfcpp/elfcpp_file.h
gold/ChangeLog
gold/gold.cc
gold/incremental.cc
gold/incremental.h

index 7569cbdbf7b70724dff958fe16a7200c679d33a8..8aeb513caa611628e20bbdc48d19f38bdc21ceed 100644 (file)
@@ -1,3 +1,7 @@
+2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
+
+       * elf_file.h: (class Elf_strtab): New class.
+
 2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
 
        * elfcpp_file.h: Fix header guard.  Include <cstdio>.
index 00ab28b36e11f000f9869dca338af2b0335552d9..12f09250510e1eaa54b19c2089dfa7cb736d5434 100644 (file)
@@ -228,6 +228,33 @@ class Elf_file
   int large_shndx_offset_;
 };
 
+// A small wrapper around SHT_STRTAB data mapped to memory. It checks that the
+// index is not out of bounds and the string is NULL-terminated.
+
+class Elf_strtab
+{
+ public:
+  // Construct an Elf_strtab for a section with contents *P and size SIZE.
+  Elf_strtab(const unsigned char* p, size_t size);
+
+  // Return the file offset to the section headers.
+  bool
+  get_c_string(size_t offset, const char** cstring) const
+  {
+    if (offset >= this->usable_size_)
+      return false;
+    *cstring = this->base_ + offset;
+    return true;
+  }
+
+ private:
+  // Contents of the section mapped to memory.
+  const char* base_;
+  // One larger that the position of the last NULL character in the section.
+  // For valid SHT_STRTAB sections, this is the size of the section.
+  size_t usable_size_;
+};
+
 // Inline function definitions.
 
 // Check for presence of the ELF magic number.
@@ -642,6 +669,18 @@ Elf_file<size, big_endian, File>::section_addralign(unsigned int shndx)
   return shdr.get_sh_addralign();
 }
 
+inline
+Elf_strtab::Elf_strtab(const unsigned char* p, size_t size)
+{
+  // Check if the section is NUL-terminated. If it isn't, we ignore
+  // the last part to make sure we don't return non-NUL-terminated
+  // strings.
+  while (size > 0 && p[size - 1] != 0)
+    size--;
+  this->base_ = reinterpret_cast<const char*>(p);
+  this->usable_size_ = size;
+}
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFCPP_FILE_H)
index 227ded71401238f9745df278080887723801d565..0e34e612696194a0959e7985f25ddee0769be2ab 100644 (file)
@@ -1,3 +1,34 @@
+2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
+
+       * gold.cc: (queue_initial_tasks): Pass incremental_inputs to
+       Incremental_checker.
+       * incremental.cc: (INCREMENTAL_LINK_VERSION): Change type to
+       unsigned int.
+       (class Incremental_inputs_header): New class.
+       (Incremental_inputs_header_writer): Edit comment.
+       (Incremental_inputs_entry): New class.
+       (Incremental_inputs_entry_writer): Edit comment.
+       (Sized_incremental_binary::do_find_incremental_inputs_section):
+       Add *strtab_shndx parameter, fill it.
+       (Sized_incremental_binary::do_check_inputs): New method.
+       (Incremental_checker::can_incrementally_link_output_file): Use
+       Sized_incremental_binary::check_inputs.
+       (Incremental_inputs::report_command_line): Save command line in
+       command_line_.
+       * incremental.h:
+       (Incremental_binary::find_incremental_inputs_section): New
+       method.
+       (Incremental_binary::do_find_incremental_inputs_section): Add
+       strtab_shndx parameter.
+       (Incremental_binary::do_check_inputs): New pure virtual method.
+       (Sized_incremental_binary::do_check_inputs): Declare.
+       (Incremental_checker::Incremental_checker): Add incremental_inputs
+       parameter, use it to initialize incremental_inputs_.
+       (Incremental_checker::incremental_inputs_): New field.
+       (Incremental_checker::command_line): New method.
+       (Incremental_checker::inputs): New method.
+       (Incremental_checker::command_line_): New field.
+
 2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
 
        * incremental.cc: Include <cstdarg> and "target-select.h".
index 43fd2fc49f7f9f7d8202392678242107fec38bb5..ac2f62c5d809fc606007d19dad6c2ec10295a490 100644 (file)
@@ -180,7 +180,8 @@ queue_initial_tasks(const General_options& options,
   if (cmdline.options().incremental())
     {
       Incremental_checker incremental_checker(
-          parameters->options().output_file_name());
+          parameters->options().output_file_name(),
+          layout->incremental_inputs());
       if (incremental_checker.can_incrementally_link_output_file())
         {
           // TODO: remove when incremental linking implemented.
index 9f7c4c20ec10b5b0cad939302299ef5877edb4e4..519f35fe150c798e04e5f4e2825508eee646c41d 100644 (file)
@@ -37,7 +37,7 @@ namespace gold {
 
 // Version information. Will change frequently during the development, later
 // we could think about backward (and forward?) compatibility.
-const int INCREMENTAL_LINK_VERSION = 1;
+const unsigned int INCREMENTAL_LINK_VERSION = 1;
 
 namespace internal {
 
@@ -84,7 +84,42 @@ struct Incremental_inputs_entry_data
 
 // Accessors.
 
-// See internal::Incremental_input_header for fields descriptions.
+// Reader class for .gnu_incremental_inputs header. See
+// internal::Incremental_input_header for fields descriptions.
+
+template<int size, bool big_endian>
+class Incremental_inputs_header
+{
+ public:
+  Incremental_inputs_header(const unsigned char *p)
+    : p_(reinterpret_cast<const internal::Incremental_inputs_header_data*>(p))
+  { }
+
+  static const int data_size = sizeof(internal::Incremental_inputs_header_data);
+
+  elfcpp::Elf_Word
+  get_version() const
+  { return Convert<32, big_endian>::convert_host(this->p_->version); }
+
+  elfcpp::Elf_Word
+  get_input_file_count() const
+  { return Convert<32, big_endian>::convert_host(this->p_->input_file_count); }
+
+  elfcpp::Elf_Word
+  get_command_line_offset() const
+  { return Convert<32, big_endian>::convert_host(this->p_->command_line_offset); }
+
+  elfcpp::Elf_Word
+  get_reserved() const
+  { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
+
+ private:
+  const internal::Incremental_inputs_header_data* p_;
+};
+
+// Writer class for .gnu_incremental_inputs header. See
+// internal::Incremental_input_header for fields descriptions.
+
 template<int size, bool big_endian>
 class Incremental_inputs_header_write
 {
@@ -115,7 +150,48 @@ class Incremental_inputs_header_write
   internal::Incremental_inputs_header_data* p_;
 };
 
-// See internal::Incremental_input_entry for fields descriptions.
+// Reader class for an .gnu_incremental_inputs entry. See
+// internal::Incremental_input_entry for fields descriptions.
+template<int size, bool big_endian>
+class Incremental_inputs_entry
+{
+ public:
+  Incremental_inputs_entry(const unsigned char *p)
+    : p_(reinterpret_cast<const internal::Incremental_inputs_entry_data*>(p))
+  { }
+
+  static const int data_size = sizeof(internal::Incremental_inputs_entry_data);
+
+  elfcpp::Elf_Word
+  get_filename_offset(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->filename_offset); }
+
+  elfcpp::Elf_Word
+  get_data_offset(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->data_offset); }
+
+  elfcpp::Elf_Xword
+  get_timestamp_sec(elfcpp::Elf_Xword v)
+  { return Convert<64, big_endian>::convert_host(this->p_->timestamp_sec); }
+
+  elfcpp::Elf_Word
+  get_timestamp_nsec(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->timestamp_nsec); }
+
+  elfcpp::Elf_Word
+  get_input_type(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->input_type); }
+
+  elfcpp::Elf_Word
+  get_reserved(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
+
+ private:
+  const internal::Incremental_inputs_entry_data* p_;
+};
+
+// Writer class for an .gnu_incremental_inputs entry. See
+// internal::Incremental_input_entry for fields descriptions.
 template<int size, bool big_endian>
 class Incremental_inputs_entry_write
 {
@@ -196,16 +272,77 @@ Incremental_binary::error(const char* format, ...) const
 template<int size, bool big_endian>
 bool
 Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section(
-    Location* location)
+    Location* location,
+    unsigned int* strtab_shndx)
 {
   unsigned int shndx = this->elf_file_.find_section_by_type(
       elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
   if (shndx == elfcpp::SHN_UNDEF)  // Not found.
     return false;
+  *strtab_shndx = this->elf_file_.section_link(shndx);
   *location = this->elf_file_.section_contents(shndx);
   return true;
 }
 
+template<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::do_check_inputs(
+    Incremental_inputs* incremental_inputs)
+{
+  const int entry_size =
+      Incremental_inputs_entry_write<size, big_endian>::data_size;
+  const int header_size =
+      Incremental_inputs_header_write<size, big_endian>::data_size;
+
+  unsigned int strtab_shndx;
+  Location location;
+
+  if (!do_find_incremental_inputs_section(&location, &strtab_shndx))
+    {
+      explain_no_incremental(_("no incremental data from previous build"));
+      return false;
+    }
+  if (location.data_size < header_size
+      || strtab_shndx >= this->elf_file_.shnum()
+      || this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
+    {
+      explain_no_incremental(_("invalid incremental build data"));
+      return false;
+    }
+
+  Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
+  View data_view(view(location));
+  View strtab_view(view(strtab_location));
+  elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
+  Incremental_inputs_header<size, big_endian> header(data_view.data());
+
+  if (header.get_version() != INCREMENTAL_LINK_VERSION)
+    {
+      explain_no_incremental(_("different version of incremental build data"));
+      return false;
+    }
+
+  const char* command_line;
+  // We divide instead of multiplying to make sure there is no integer
+  // overflow.
+  size_t max_input_entries = (location.data_size - header_size) / entry_size;
+  if (header.get_input_file_count() > max_input_entries
+      || !strtab.get_c_string(header.get_command_line_offset(), &command_line))
+    {
+      explain_no_incremental(_("invalid incremental build data"));
+      return false;
+    }
+
+  if (incremental_inputs->command_line() != command_line)
+    {
+      explain_no_incremental(_("command line changed"));
+      return false;
+    }
+
+  // TODO: compare incremental_inputs->inputs() with entries in data_view.
+  return true;
+}
+
 namespace
 {
 
@@ -322,14 +459,7 @@ Incremental_checker::can_incrementally_link_output_file()
   Incremental_binary* binary = open_incremental_binary(&output);
   if (binary == NULL)
     return false;
-  Incremental_binary::Location inputs_location;
-  if (!binary->find_incremental_inputs_section(&inputs_location))
-    {
-      explain_no_incremental("no incremental data from previous build");
-      delete binary;
-      return false;
-    }
-  return true;
+  return binary->check_inputs(this->incremental_inputs_);
 }
 
 // Add the command line to the string table, setting
@@ -366,7 +496,10 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
         }
       args.append("'");
     }
-  this->strtab_->add(args.c_str(), true, &this->command_line_key_);
+
+  this->command_line_ = args;
+  this->strtab_->add(this->command_line_.c_str(), false,
+                     &this->command_line_key_);
 }
 
 // Record that the input argument INPUT is an achive ARCHIVE.  This is
index 8909324884d3402340e0e4b7f833d9ae9c1f3f63..b53f6c1cc3c0243b86002b929848c8db346d2056 100644 (file)
@@ -119,18 +119,34 @@ class Incremental_binary
   void
   error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
 
-
   // Find the .gnu_incremental_inputs section.  It selects the first section
   // of type SHT_GNU_INCREMENTAL_INPUTS.  Returns false if such a section
   // is not found.
   bool
-  find_incremental_inputs_section(Location* location)
-  { return do_find_incremental_inputs_section(location); }
+  find_incremental_inputs_section(Location* location,
+                                  unsigned int* strtab_shndx)
+  { return do_find_incremental_inputs_section(location, strtab_shndx); }
+
+  // Check the .gnu_incremental_inputs section to see whether an incremental
+  // build is possible.
+  // TODO: on success, should report what files needs to be rebuilt.
+  // INCREMENTAL_INPUTS is used to read the canonical form of the command line
+  // and read the input arguments.  TODO: for items that don't need to be
+  // rebuilt, we should also copy the incremental input information.
+  virtual bool
+  check_inputs(Incremental_inputs* incremental_inputs)
+  { return do_check_inputs(incremental_inputs); }
 
  protected:
   // Find incremental inputs section.
   virtual bool
-  do_find_incremental_inputs_section(Location* location) = 0;
+  do_find_incremental_inputs_section(Location* location,
+                                     unsigned int* strtab_shndx) = 0;
+
+  // Check the .gnu_incremental_inputs section to see whether an incremental
+  // build is possible.
+  virtual bool
+  do_check_inputs(Incremental_inputs* incremental_inputs) = 0;
 
  private:
   // Edited output file object.
@@ -151,7 +167,11 @@ class Sized_incremental_binary : public Incremental_binary
 
  protected:
   virtual bool
-  do_find_incremental_inputs_section(Location* location);
+  do_find_incremental_inputs_section(Location* location,
+                                     unsigned int* strtab_shndx);
+
+  virtual bool
+  do_check_inputs(Incremental_inputs* incremental_inputs);
 
  private:
   // Output as an ELF file.
@@ -168,8 +188,14 @@ open_incremental_binary(Output_file* file);
 class Incremental_checker
 {
  public:
-  Incremental_checker(const char* output_name)
-    : output_name_(output_name)
+  // Check if the file named OUTPUT_NAME can be linked incrementally.
+  // INCREMENTAL_INPUTS must have the canonical form of the command line
+  // and input arguments filled - at this point of linking other fields are
+  // probably not filled yet.  TODO: for inputs that don't need to be
+  // rebuilt, this function should fill the incremental input information.
+  Incremental_checker(const char* output_name,
+                      Incremental_inputs* incremental_inputs)
+    : output_name_(output_name), incremental_inputs_(incremental_inputs)
   { }
 
   // Analyzes the output file to check if incremental linking is possible and
@@ -178,7 +204,12 @@ class Incremental_checker
   can_incrementally_link_output_file();
 
  private:
+  // Name of the output file to analyze.
   const char* output_name_;
+
+  // The Incremental_inputs object. At this stage of link, only the command
+  // line and inputs are filled.
+  Incremental_inputs* incremental_inputs_;
 };
 
 // This class contains the information needed during an incremental
@@ -227,6 +258,17 @@ class Incremental_inputs
   get_stringpool()
   { return this->strtab_; }
 
+  // Return the canonical form of the command line, as will be stored in
+  // .gnu_incremental_strtab.
+  const std::string&
+  command_line()
+  { return this->command_line_; }
+
+  // Return the input files found in the command line.
+  const Input_arguments*
+  inputs()
+  { return this->inputs_; }
+
  private:
   // Code for each of the four possible variants of create_inputs_section_data.
   template<int size, bool big_endian>
@@ -289,8 +331,13 @@ class Incremental_inputs
   // A map containing additional information about the input elements.
   Inputs_info_map inputs_map_;
 
+  // Canonical form of the command line, as will be stored in
+  // .gnu_incremental_strtab.
+  std::string command_line_;
+
   // The key of the command line string in the string pool.
   Stringpool::Key command_line_key_;
+
   // The .gnu_incremental_strtab string pool associated with the
   // .gnu_incremental_inputs.
   Stringpool* strtab_;