+ return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 8);
+ }
+
+ // Return the local symbol count -- for objects only.
+ unsigned int
+ get_local_symbol_count() const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+ || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 12);
+ }
+
+ // Return the index of the first dynamic relocation -- for objects only.
+ unsigned int
+ get_first_dyn_reloc() const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+ || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 16);
+ }
+
+ // Return the dynamic relocation count -- for objects only.
+ unsigned int
+ get_dyn_reloc_count() const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+ || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+
+ 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
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_SCRIPT);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_);
+ }
+
+ // Return the input file offset for object N -- for scripts only.
+ unsigned int
+ get_object_offset(unsigned int n) const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_SCRIPT);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_
+ + 4 + n * 4);
+ }
+
+ // Return the member count -- for archives only.
+ unsigned int
+ get_member_count() const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_);
+ }
+
+ // Return the unused symbol count -- for archives only.
+ unsigned int
+ get_unused_symbol_count() const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4);
+ }
+
+ // Return the input file offset for archive member N -- for archives only.
+ unsigned int
+ get_member_offset(unsigned int n) const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
+ return Swap32::readval(this->inputs_->p_ + this->info_offset_
+ + 8 + n * 4);
+ }
+
+ // Return the Nth unused global symbol -- for archives only.
+ const char*
+ get_unused_symbol(unsigned int n) const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
+ unsigned int member_count = this->get_member_count();
+ unsigned int offset = Swap32::readval(this->inputs_->p_
+ + this->info_offset_ + 8
+ + member_count * 4
+ + n * 4);
+ return this->inputs_->get_string(offset);
+ }
+
+ // Information about an input section.
+ struct Input_section_info
+ {
+ const char* name;
+ unsigned int output_shndx;
+ off_t sh_offset;
+ off_t sh_size;
+ };
+
+ // Return info about the Nth input section -- for objects only.
+ Input_section_info
+ get_input_section(unsigned int n) const
+ {
+ Input_section_info info;
+ const unsigned char* p = (this->inputs_->p_
+ + this->info_offset_
+ + this->object_info_size
+ + n * this->input_section_entry_size);
+ unsigned int name_offset = Swap32::readval(p);
+ info.name = this->inputs_->get_string(name_offset);
+ info.output_shndx = Swap32::readval(p + 4);
+ info.sh_offset = Swap::readval(p + 8);
+ info.sh_size = Swap::readval(p + 8 + size / 8);
+ return info;
+ }
+
+ // Return info about the Nth global symbol -- for objects only.
+ Incremental_global_symbol_reader<big_endian>
+ get_global_symbol_reader(unsigned int n) const
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+ || 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_
+ + this->object_info_size
+ + section_count * this->input_section_entry_size
+ + n * this->global_sym_entry_size);
+ 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_
+ + this->object_info_size
+ + section_count * this->input_section_entry_size
+ + symbol_count * this->global_sym_entry_size
+ + 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. Sets *IS_COPY to TRUE if the symbol was copied from this
+ // input file with a COPY relocation.
+ unsigned int
+ get_output_symbol_index(unsigned int n, bool* is_def, bool* is_copy)
+ {
+ gold_assert(this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY);
+ const unsigned char* p = (this->inputs_->p_
+ + this->info_offset_ + 8
+ + n * 4);
+ unsigned int output_symndx = Swap32::readval(p);
+ unsigned int flags = output_symndx >> INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT;
+ output_symndx &= ((1U << INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT) - 1);
+ switch (flags)
+ {
+ case INCREMENTAL_SHLIB_SYM_DEF:
+ *is_def = true;
+ *is_copy = false;
+ break;
+ case INCREMENTAL_SHLIB_SYM_COPY:
+ *is_def = true;
+ *is_copy = true;
+ break;
+ default:
+ *is_def = false;
+ *is_copy = false;
+ }
+ return output_symndx;
+ }
+
+ private:
+ // The reader instance for the containing section.
+ const Incremental_inputs_reader* inputs_;
+ // The flags, including the type of input file.
+ unsigned int flags_;
+ // Section offset to the input file entry.
+ unsigned int offset_;
+ // Section offset to the supplemental info for the input file.
+ unsigned int info_offset_;
+ };
+
+ // Return the offset of an input file entry given its index N.
+ unsigned int
+ input_file_offset(unsigned int n) const
+ {
+ gold_assert(n < this->input_file_count_);
+ return this->header_size + n * this->input_entry_size;
+ }
+
+ // Return the index of an input file entry given its OFFSET.
+ unsigned int
+ input_file_index(unsigned int offset) const
+ {
+ int n = ((offset - this->header_size) / this->input_entry_size);
+ gold_assert(input_file_offset(n) == offset);
+ return n;
+ }
+
+ // Return a reader for the Nth input file entry.
+ Incremental_input_entry_reader
+ input_file(unsigned int n) const
+ { return Incremental_input_entry_reader(this, this->input_file_offset(n)); }
+
+ // Return a reader for the input file entry at OFFSET.
+ Incremental_input_entry_reader
+ input_file_at_offset(unsigned int offset) const
+ {
+ gold_assert(offset < (this->header_size
+ + this->input_file_count_ * this->input_entry_size));
+ return Incremental_input_entry_reader(this, offset);
+ }
+
+ // Return a reader for the global symbol info at OFFSET.
+ Incremental_global_symbol_reader<big_endian>
+ global_symbol_reader_at_offset(unsigned int offset) const
+ {
+ const unsigned char* p = this->p_ + offset;
+ return Incremental_global_symbol_reader<big_endian>(p);
+ }
+
+ private:
+ // Lookup a string in the ELF string table.
+ const char* get_string(unsigned int offset) const
+ {
+ const char* s;
+ if (this->strtab_.get_c_string(offset, &s))
+ return s;
+ return NULL;
+ }
+
+ // Base address of the .gnu_incremental_inputs section.
+ const unsigned char* p_;
+ // The associated ELF string table.
+ elfcpp::Elf_strtab strtab_;
+ // The number of input file entries in this section.
+ unsigned int input_file_count_;
+};
+
+// Reader class for the .gnu_incremental_symtab section.
+
+template<bool big_endian>
+class Incremental_symtab_reader
+{
+ public:
+ Incremental_symtab_reader()
+ : p_(NULL), len_(0)
+ { }
+
+ Incremental_symtab_reader(const unsigned char* p, off_t len)
+ : p_(p), len_(len)
+ { }
+
+ // Return the count of symbols in this section.
+ unsigned int
+ symbol_count() const
+ { return static_cast<unsigned int>(this->len_ / 4); }
+
+ // Return the list head for symbol table entry N.
+ unsigned int
+ get_list_head(unsigned int n) const
+ { return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4 * n); }
+
+ private:
+ // Base address of the .gnu_incremental_relocs section.
+ const unsigned char* p_;
+ // Size of the section.
+ off_t len_;
+};
+
+// Reader class for the .gnu_incremental_relocs section.
+
+template<int size, bool big_endian>
+class Incremental_relocs_reader
+{
+ private:
+ // Size of each field.
+ static const unsigned int field_size = size / 8;
+
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Swxword Addend;
+
+ // Size of each entry.
+ static const unsigned int reloc_size = 8 + 2 * field_size;
+
+ Incremental_relocs_reader()
+ : p_(NULL), len_(0)
+ { }
+
+ Incremental_relocs_reader(const unsigned char* p, off_t len)
+ : p_(p), len_(len)
+ { }
+
+ // Return the count of relocations in this section.
+ unsigned int
+ reloc_count() const
+ { return static_cast<unsigned int>(this->len_ / reloc_size); }
+
+ // Return the relocation type for relocation entry at offset OFF.
+ unsigned int
+ get_r_type(unsigned int off) const
+ { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off); }
+
+ // Return the output section index for relocation entry at offset OFF.
+ unsigned int
+ get_r_shndx(unsigned int off) const
+ { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off + 4); }
+
+ // Return the output section offset for relocation entry at offset OFF.
+ Address
+ get_r_offset(unsigned int off) const
+ { return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8); }
+
+ // Return the addend for relocation entry at offset OFF.
+ Addend
+ get_r_addend(unsigned int off) const
+ {
+ return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8
+ + this->field_size);
+ }
+
+ // Return a pointer to the relocation entry at offset OFF.
+ const unsigned char*
+ data(unsigned int off) const
+ { return this->p_ + off; }
+
+ private:
+ // Base address of the .gnu_incremental_relocs section.
+ const unsigned char* p_;
+ // Size of the section.
+ off_t len_;
+};
+
+// Reader class for the .gnu_incremental_got_plt section.
+
+template<bool big_endian>
+class Incremental_got_plt_reader
+{
+ public:
+ Incremental_got_plt_reader()
+ : p_(NULL), got_count_(0), got_desc_p_(NULL), plt_desc_p_(NULL)
+ { }
+
+ Incremental_got_plt_reader(const unsigned char* p) : p_(p)
+ {
+ this->got_count_ = elfcpp::Swap<32, big_endian>::readval(p);
+ this->got_desc_p_ = p + 8 + ((this->got_count_ + 3) & ~3);
+ this->plt_desc_p_ = this->got_desc_p_ + this->got_count_ * 8;
+ }
+
+ // Return the GOT entry count.
+ unsigned int
+ get_got_entry_count() const
+ {
+ return this->got_count_;
+ }
+
+ // Return the PLT entry count.
+ unsigned int
+ get_plt_entry_count() const
+ {
+ return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4);
+ }
+
+ // Return the GOT type for GOT entry N.
+ unsigned int
+ get_got_type(unsigned int n)
+ {
+ return this->p_[8 + n];
+ }
+
+ // Return the symbol index for GOT entry N.
+ unsigned int
+ get_got_symndx(unsigned int n)
+ {
+ return elfcpp::Swap<32, big_endian>::readval(this->got_desc_p_ + n * 8);
+ }
+
+ // Return the input file index for GOT entry N.
+ unsigned int
+ get_got_input_index(unsigned int n)
+ {
+ return elfcpp::Swap<32, big_endian>::readval(this->got_desc_p_ + n * 8 + 4);
+ }
+
+ // Return the PLT descriptor for PLT entry N.
+ unsigned int
+ get_plt_desc(unsigned int n)
+ {
+ return elfcpp::Swap<32, big_endian>::readval(this->plt_desc_p_ + n * 4);
+ }