+2013-07-22 Sterling Augustine <saugustine@google.com>
+
+ * dwarf_reader.cc (Dwarf_pubnames_table::read_section):
+ Convert parameter shndx to local variable. Add parameters symtab
+ and symtab_size. Scan over section names. Find relocation
+ section corresponding to current section. Create and initialize
+ reloc_mapper_ and reloc_type_.
+ (Dwarf_pubnames_table::read_header): Add assertion. Change
+ unit_length to off_t. Initialize member unit_length_. Fill in field
+ cu_offset_.
+ * dwarf_reader.h (Dwarf_pubnames_table::Dwarf_pubnames_table):
+ Initialize new fields unit_length_ and cu_offset_.
+ (Dwarf_pubnames_table::read_section): Update prototype.
+ (Dwarf_pubnames_table::cu_offset): New member function.
+ (Dwarf_pubnames_table::subsection_size): Likewise.
+ (Dwarf_pubnames_table::cu_offset_, Dwarf_pubnames_table::unit_length):
+ New fields.
+ (Dwarf_info_reader::symtab, Dwarf_info_reader::symtab_size): Make
+ member functions public.
+ * gdb_index.cc (Gdb_index_info_reader::read_pubnames_and_pubtypes):
+ Update comment. Rework logic. Move repeated parts to...
+ (Gdb_index_info_reader::read_pubtable): ...here. New function.
+ (Gdb_index::Gdb_index): Initialize new fields, pubnames_table_,
+ pubtypes_table_, and stmt_list_offset.
+ (Gdb_index::map_pubtable_to_dies, Gdb_index::find_pubname_offset,
+ Gdb_index::find_pubtype_offset,
+ Gdb_index::map_pubnames_and_types_to_dies): Define new functions.
+ (Gdb_index::pubnames_read): Update prototype and rework logic.
+ * gdb_index.h (Gdb_index_info_reader, Dwarf_pubnames_table):
+ Forward declare.
+ (Gdb_index::map_pubtable_to_dies, Gdb_index::find_pubname_offset,
+ Gdb_index::find_pubtype_offset, Gdb_index::pubnames_table)
+ Gdb_index::pubtypes_table, Gdb_index::map_pubnames_and_types_to_dies,
+ Gdb_index::map_pubtable_to_dies):
+ Declare functions.
+ (Gdb_index::pubnames_read): Update declaration.
+ (Gdb_index::Pubname_offset_map): New type.
+ (Gdb_index::cu_pubname_map_, Gdb_index::cu_pubtype_map_,
+ Gdb_index::pubnames_table_, Gdb_index::pubtypes_table_,
+ Gdb_index::stmt_list_offset): Declare.
+ (Gdb_index::pubnames_shndx_, Gdb_index::pubnames_offet_,
+ Gdb_index::pubtypes_object_, Gdb_index::pubtypes_shndx_)
+ Gdb_index::pubtypes_offset_): Remove.
+
2013-07-19 Roland McGrath <mcgrathr@google.com>
* options.h (General_options): Add -Trodata-segment option.
// class Dwarf_pubnames_table
-// Read the pubnames section SHNDX from the object file.
+// Read the pubnames section from the object file.
bool
-Dwarf_pubnames_table::read_section(Relobj* object, unsigned int shndx)
+Dwarf_pubnames_table::read_section(Relobj* object, const unsigned char* symtab,
+ off_t symtab_size)
{
section_size_type buffer_size;
+ unsigned int shndx = 0;
- // If we don't have relocations, shndx will be 0, and
- // we'll have to hunt for the .debug_pubnames/pubtypes section.
- if (shndx == 0)
+ // Find the .debug_pubnames/pubtypes section.
+ const char* name = (this->is_pubtypes_
+ ? ".debug_pubtypes"
+ : ".debug_pubnames");
+ for (unsigned int i = 1; i < object->shnum(); ++i)
{
- const char* name = (this->is_pubtypes_
- ? ".debug_pubtypes"
- : ".debug_pubnames");
- for (unsigned int i = 1; i < object->shnum(); ++i)
- {
- if (object->section_name(i) == name)
- {
- shndx = i;
- this->output_section_offset_ = object->output_section_offset(i);
- break;
- }
- }
- if (shndx == 0)
- return false;
+ if (object->section_name(i) == name)
+ {
+ shndx = i;
+ this->output_section_offset_ = object->output_section_offset(i);
+ break;
+ }
}
+ if (shndx == 0)
+ return false;
+
this->buffer_ = object->decompressed_section_contents(shndx,
&buffer_size,
if (this->buffer_ == NULL)
return false;
this->buffer_end_ = this->buffer_ + buffer_size;
+
+ // For incremental objects, we have no relocations.
+ if (object->is_incremental())
+ return true;
+
+ // Find the relocation section
+ unsigned int reloc_shndx = 0;
+ unsigned int reloc_type = 0;
+ for (unsigned int i = 0; i < object->shnum(); ++i)
+ {
+ reloc_type = object->section_type(i);
+ if ((reloc_type == elfcpp::SHT_REL
+ || reloc_type == elfcpp::SHT_RELA)
+ && object->section_info(i) == shndx)
+ {
+ reloc_shndx = i;
+ break;
+ }
+ }
+
+ this->reloc_mapper_ = make_elf_reloc_mapper(object, symtab, symtab_size);
+ this->reloc_mapper_->initialize(reloc_shndx, reloc_type);
+ this->reloc_type_ = reloc_type;
+
return true;
}
bool
Dwarf_pubnames_table::read_header(off_t offset)
{
+ // Make sure we have actually read the section.
+ gold_assert(this->buffer_ != NULL);
+
// Correct the offset. For incremental update links, we have a
// relocated offset that is relative to the output section, but
// here we need an offset relative to the input section.
const unsigned char* pinfo = this->buffer_ + offset;
// Read the unit_length field.
- uint32_t unit_length = this->dwinfo_->read_from_pointer<32>(pinfo);
+ uint64_t unit_length = this->dwinfo_->read_from_pointer<32>(pinfo);
pinfo += 4;
if (unit_length == 0xffffffff)
{
unit_length = this->dwinfo_->read_from_pointer<64>(pinfo);
+ this->unit_length_ = unit_length + 12;
pinfo += 8;
this->offset_size_ = 8;
}
else
- this->offset_size_ = 4;
+ {
+ this->unit_length_ = unit_length + 4;
+ this->offset_size_ = 4;
+ }
// Check the version.
unsigned int version = this->dwinfo_->read_from_pointer<16>(pinfo);
if (version != 2)
return false;
+ this->reloc_mapper_->get_reloc_target(pinfo - this->buffer_,
+ &this->cu_offset_);
+
// Skip the debug_info_offset and debug_info_size fields.
pinfo += 2 * this->offset_size_;
Dwarf_pubnames_table(Dwarf_info_reader* dwinfo, bool is_pubtypes)
: dwinfo_(dwinfo), buffer_(NULL), buffer_end_(NULL), owns_buffer_(false),
offset_size_(0), pinfo_(NULL), is_pubtypes_(is_pubtypes),
- output_section_offset_(0)
+ output_section_offset_(0), unit_length_(0), cu_offset_(0)
{ }
~Dwarf_pubnames_table()
delete[] this->buffer_;
}
- // Read the pubnames section SHNDX from the object file.
+ // Read the pubnames section from the object file, using the symbol
+ // table for relocating it.
bool
- read_section(Relobj* object, unsigned int shndx);
+ read_section(Relobj* object, const unsigned char* symbol_table,
+ off_t symtab_size);
// Read the header for the set at OFFSET.
bool
read_header(off_t offset);
+ // Return the offset to the cu within the info or types section.
+ off_t
+ cu_offset()
+ { return this->cu_offset_; }
+
+ // Return the size of this subsection of the table. The unit length
+ // doesn't include the size of its own field.
+ off_t
+ subsection_size()
+ { return this->unit_length_; }
+
// Read the next name from the set.
const char*
next_name();
// relocated data will be relative to the output section, and need
// to be corrected before reading data from the input section.
uint64_t output_section_offset_;
+ // Fields read from the header.
+ uint64_t unit_length_;
+ off_t cu_offset_;
+
+ // Track relocations for this table so we can find the CUs that
+ // correspond to the subsections.
+ Elf_reloc_mapper* reloc_mapper_;
+ // Type of the relocation section (SHT_REL or SHT_RELA).
+ unsigned int reloc_type_;
};
// This class represents a DWARF Debug Info Entry (DIE).
set_abbrev_shndx(unsigned int abbrev_shndx)
{ this->abbrev_shndx_ = abbrev_shndx; }
+ // Return a pointer to the object file's ELF symbol table.
+ const unsigned char*
+ symtab() const
+ { return this->symtab_; }
+
+ // Return the size of the object file's ELF symbol table.
+ off_t
+ symtab_size() const
+ { return this->symtab_size_; }
+
+ // Return the offset of the current compilation unit.
+ off_t
+ cu_offset() const
+ { return this->cu_offset_; }
+
protected:
// Begin parsing the debug info. This calls visit_compilation_unit()
// or visit_type_unit() for each compilation or type unit found in the
object() const
{ return this->object_; }
- // Return a pointer to the object file's ELF symbol table.
- const unsigned char*
- symtab() const
- { return this->symtab_; }
-
- // Return the size of the object file's ELF symbol table.
- off_t
- symtab_size() const
- { return this->symtab_size_; }
-
// Checkpoint the relocation tracker.
uint64_t
get_reloc_checkpoint() const
void
record_cu_ranges(Dwarf_die* die);
- // Read the .debug_pubnames and .debug_pubtypes tables.
+ // Wrapper for read_pubtable.
bool
read_pubnames_and_pubtypes(Dwarf_die* die);
+ // Read the .debug_pubnames and .debug_pubtypes tables.
+ bool
+ read_pubtable(Dwarf_pubnames_table* table, off_t offset);
+
// Clear the declarations map.
void
clear_declarations();
}
}
-// Read the .debug_pubnames and .debug_pubtypes tables for the CU or TU.
-// Returns TRUE if either a pubnames or pubtypes section was found.
+// Read table and add the relevant names to the index. Returns true
+// if any names were added.
bool
-Gdb_index_info_reader::read_pubnames_and_pubtypes(Dwarf_die* die)
+Gdb_index_info_reader::read_pubtable(Dwarf_pubnames_table* table, off_t offset)
{
- bool ret = false;
-
- // If we find a DW_AT_GNU_pubnames attribute, read the pubnames table.
- unsigned int pubnames_shndx;
- off_t pubnames_offset = die->ref_attribute(elfcpp::DW_AT_GNU_pubnames,
- &pubnames_shndx);
- if (pubnames_offset != -1)
+ // If we couldn't read the section when building the cu_pubname_map,
+ // then we won't find any pubnames now.
+ if (table == NULL)
+ return false;
+
+ if (!table->read_header(offset))
+ return false;
+ while (true)
{
- if (this->gdb_index_->pubnames_read(this->object(), pubnames_shndx,
- pubnames_offset))
- ret = true;
- else
- {
- Dwarf_pubnames_table pubnames(this, false);
- if (!pubnames.read_section(this->object(), pubnames_shndx))
- return false;
- if (!pubnames.read_header(pubnames_offset))
- return false;
- while (true)
- {
- const char* name = pubnames.next_name();
- if (name == NULL)
- break;
- this->gdb_index_->add_symbol(this->cu_index_, name);
- }
- ret = true;
- }
+ const char* name = table->next_name();
+ if (name == NULL)
+ break;
+
+ this->gdb_index_->add_symbol(this->cu_index_, name);
}
+ return true;
+}
+
+// Read the .debug_pubnames and .debug_pubtypes tables for the CU or TU.
+// Returns TRUE if either a pubnames or pubtypes section was found.
- // If we find a DW_AT_GNU_pubtypes attribute, read the pubtypes table.
- unsigned int pubtypes_shndx;
- off_t pubtypes_offset = die->ref_attribute(elfcpp::DW_AT_GNU_pubtypes,
- &pubtypes_shndx);
- if (pubtypes_offset != -1)
+bool
+Gdb_index_info_reader::read_pubnames_and_pubtypes(Dwarf_die* die)
+{
+ // We use stmt_list_off as a unique identifier for the
+ // compilation unit and its associated type units.
+ unsigned int shndx;
+ off_t stmt_list_off = die->ref_attribute (elfcpp::DW_AT_stmt_list,
+ &shndx);
+ // Look for the attr as either a flag or a ref.
+ off_t offset = die->ref_attribute(elfcpp::DW_AT_GNU_pubnames, &shndx);
+
+ // Newer versions of GCC generate CUs, but not TUs, with
+ // DW_AT_FORM_flag_present.
+ unsigned int flag = die->uint_attribute(elfcpp::DW_AT_GNU_pubnames);
+ if (offset == -1 && flag == 0)
{
- if (this->gdb_index_->pubtypes_read(this->object(),
- pubtypes_shndx, pubtypes_offset))
- ret = true;
+ // Didn't find the attribute.
+ if (die->tag() == elfcpp::DW_TAG_type_unit)
+ {
+ // If die is a TU, then it might correspond to a CU which we
+ // have read. If it does, then no need to read the pubnames.
+ // If it doesn't, then the caller will have to parse the
+ // dies manually to find the names.
+ return this->gdb_index_->pubnames_read(this->object(),
+ stmt_list_off);
+ }
else
- {
- Dwarf_pubnames_table pubtypes(this, true);
- if (!pubtypes.read_section(this->object(), pubtypes_shndx))
- return false;
- if (!pubtypes.read_header(pubtypes_offset))
- return false;
- while (true)
- {
- const char* name = pubtypes.next_name();
- if (name == NULL)
- break;
- this->gdb_index_->add_symbol(this->cu_index_, name);
- }
- ret = true;
- }
+ {
+ // No attribute on the CU means that no pubnames were read.
+ return false;
+ }
}
- return ret;
+ // We found the attribute, so we can check if the corresponding
+ // pubnames have been read.
+ if (this->gdb_index_->pubnames_read(this->object(), stmt_list_off))
+ return true;
+
+ this->gdb_index_->set_pubnames_read(this->object(), stmt_list_off);
+
+ // We have an attribute, and the pubnames haven't been read, so read
+ // them.
+ bool names = false;
+ // In some of the cases, we could rely on the previous value of
+ // offset here, but sorting out which cases complicates the logic
+ // enough that it isn't worth it. So just look up the offset again.
+ offset = this->gdb_index_->find_pubname_offset(this->cu_offset());
+ names = this->read_pubtable(this->gdb_index_->pubnames_table(), offset);
+
+ bool types = false;
+ offset = this->gdb_index_->find_pubtype_offset(this->cu_offset());
+ types = this->read_pubtable(this->gdb_index_->pubtypes_table(), offset);
+ return names || types;
}
// Clear the declarations map.
Gdb_index::Gdb_index(Output_section* gdb_index_section)
: Output_section_data(4),
+ pubnames_table_(NULL),
+ pubtypes_table_(NULL),
gdb_index_section_(gdb_index_section),
comp_units_(),
type_units_(),
cu_pool_offset_(0),
stringpool_offset_(0),
pubnames_object_(NULL),
- pubnames_shndx_(0),
- pubnames_offset_(0),
- pubtypes_object_(NULL),
- pubtypes_shndx_(0),
- pubtypes_offset_(0)
+ stmt_list_offset_(-1)
{
this->gdb_symtab_ = new Gdb_hashtab<Gdb_symbol>();
}
delete this->cu_vector_list_[i];
}
+
+// Scan the pubnames and pubtypes sections and build a map of the
+// various cus and tus they refer to, so we can process the entries
+// when we encounter the die for that cu or tu.
+// Return the just-read table so it can be cached.
+
+Dwarf_pubnames_table*
+Gdb_index::map_pubtable_to_dies(unsigned int attr,
+ Gdb_index_info_reader* dwinfo,
+ Relobj* object,
+ const unsigned char* symbols,
+ off_t symbols_size)
+{
+ uint64_t section_offset = 0;
+ Dwarf_pubnames_table* table;
+ Pubname_offset_map* map;
+
+ if (attr == elfcpp::DW_AT_GNU_pubnames)
+ {
+ table = new Dwarf_pubnames_table(dwinfo, false);
+ map = &this->cu_pubname_map_;
+ }
+ else
+ {
+ table = new Dwarf_pubnames_table(dwinfo, true);
+ map = &this->cu_pubtype_map_;
+ }
+
+ map->clear();
+ if (!table->read_section(object, symbols, symbols_size))
+ return NULL;
+
+ while (table->read_header(section_offset))
+ {
+ map->insert(std::make_pair(table->cu_offset(), section_offset));
+ section_offset += table->subsection_size();
+ }
+
+ return table;
+}
+
+// Wrapper for map_pubtable_to_dies
+
+void
+Gdb_index::map_pubnames_and_types_to_dies(Gdb_index_info_reader* dwinfo,
+ Relobj* object,
+ const unsigned char* symbols,
+ off_t symbols_size)
+{
+ // This is a new object, so reset the relevant variables.
+ this->pubnames_object_ = object;
+ this->stmt_list_offset_ = -1;
+
+ delete this->pubnames_table_;
+ this->pubnames_table_
+ = this->map_pubtable_to_dies(elfcpp::DW_AT_GNU_pubnames, dwinfo,
+ object, symbols, symbols_size);
+ delete this->pubtypes_table_;
+ this->pubtypes_table_
+ = this->map_pubtable_to_dies(elfcpp::DW_AT_GNU_pubtypes, dwinfo,
+ object, symbols, symbols_size);
+}
+
+// Given a cu_offset, find the associated section of the pubnames
+// table.
+
+off_t
+Gdb_index::find_pubname_offset(off_t cu_offset)
+{
+ Pubname_offset_map::iterator it = this->cu_pubname_map_.find(cu_offset);
+ if (it != this->cu_pubname_map_.end())
+ return it->second;
+ return -1;
+}
+
+// Given a cu_offset, find the associated section of the pubnames
+// table.
+
+off_t
+Gdb_index::find_pubtype_offset(off_t cu_offset)
+{
+ Pubname_offset_map::iterator it = this->cu_pubtype_map_.find(cu_offset);
+ if (it != this->cu_pubtype_map_.end())
+ return it->second;
+ return -1;
+}
+
// Scan a .debug_info or .debug_types input section.
void
symbols, symbols_size,
shndx, reloc_shndx,
reloc_type, this);
+ if (object != this->pubnames_object_)
+ map_pubnames_and_types_to_dies(&dwinfo, object, symbols, symbols_size);
dwinfo.parse();
}
cu_vec->push_back(cu_index);
}
-// Return TRUE if we have already processed the pubnames set at
-// OFFSET in section SHNDX
+// Return TRUE if we have already processed the pubnames associated
+// with the statement list at the given OFFSET.
bool
-Gdb_index::pubnames_read(const Relobj* object, unsigned int shndx, off_t offset)
+Gdb_index::pubnames_read(const Relobj* object, off_t offset)
{
bool ret = (this->pubnames_object_ == object
- && this->pubnames_shndx_ == shndx
- && this->pubnames_offset_ == offset);
- this->pubnames_object_ = object;
- this->pubnames_shndx_ = shndx;
- this->pubnames_offset_ = offset;
+ && this->stmt_list_offset_ == offset);
return ret;
}
-// Return TRUE if we have already processed the pubtypes set at
-// OFFSET in section SHNDX
+// Record that we have processed the pubnames associated with the
+// statement list for OBJECT at the given OFFSET.
-bool
-Gdb_index::pubtypes_read(const Relobj* object, unsigned int shndx, off_t offset)
+void
+Gdb_index::set_pubnames_read(const Relobj* object, off_t offset)
{
- bool ret = (this->pubtypes_object_ == object
- && this->pubtypes_shndx_ == shndx
- && this->pubtypes_offset_ == offset);
- this->pubtypes_object_ = object;
- this->pubtypes_shndx_ = shndx;
- this->pubtypes_offset_ = offset;
- return ret;
+ this->pubnames_object_ = object;
+ this->stmt_list_offset_ = offset;
}
// Set the size of the .gdb_index section.
class Dwarf_range_list;
template <typename T>
class Gdb_hashtab;
+class Gdb_index_info_reader;
+class Dwarf_pubnames_table;
// This class manages the .gdb_index section, which is a fast
// lookup table for DWARF information used by the gdb debugger.
void
add_symbol(int cu_index, const char* sym_name);
- // Return TRUE if we have already processed the pubnames set for
- // OBJECT at OFFSET in section SHNDX
- bool
- pubnames_read(const Relobj* object, unsigned int shndx, off_t offset);
+ // Return the offset into the pubnames table for the cu at the given
+ // offset.
+ off_t
+ find_pubname_offset(off_t cu_offset);
+
+ // Return the offset into the pubtypes table for the cu at the
+ // given offset.
+ off_t
+ find_pubtype_offset(off_t cu_offset);
- // Return TRUE if we have already processed the pubtypes set for
- // OBJECT at OFFSET in section SHNDX
+ // Return TRUE if we have already processed the pubnames and types
+ // set for OBJECT of the CUs and TUS associated with the statement
+ // list at OFFSET.
bool
- pubtypes_read(const Relobj* object, unsigned int shndx, off_t offset);
+ pubnames_read(const Relobj* object, off_t offset);
+
+ // Record that we have already read the pubnames associated with
+ // OBJECT and OFFSET.
+ void
+ set_pubnames_read(const Relobj* object, off_t offset);
+
+ // Return a pointer to the given table.
+ Dwarf_pubnames_table*
+ pubnames_table()
+ { return pubnames_table_; }
+
+ Dwarf_pubnames_table*
+ pubtypes_table()
+ { return pubtypes_table_; }
// Print usage statistics.
static void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** gdb_index")); }
+ // Create a map from dies to pubnames.
+ Dwarf_pubnames_table*
+ map_pubtable_to_dies(unsigned int attr,
+ Gdb_index_info_reader* dwinfo,
+ Relobj* object,
+ const unsigned char* symbols,
+ off_t symbols_size);
+
+ // Wrapper for map_pubtable_to_dies
+ void
+ map_pubnames_and_types_to_dies(Gdb_index_info_reader* dwinfo,
+ Relobj* object,
+ const unsigned char* symbols,
+ off_t symbols_size);
+
private:
// An entry in the compilation unit list.
struct Comp_unit
typedef std::vector<int> Cu_vector;
+ typedef Unordered_map<off_t, off_t> Pubname_offset_map;
+ Pubname_offset_map cu_pubname_map_;
+ Pubname_offset_map cu_pubtype_map_;
+
+ // Scan the given pubtable and build a map of the various dies it
+ // refers to, so we can process the entries when we encounter the
+ // die.
+ void
+ map_pubtable_to_dies(Dwarf_pubnames_table* table,
+ Pubname_offset_map* map);
+
+ // Tables to store the pubnames section of the current object.
+ Dwarf_pubnames_table* pubnames_table_;
+ Dwarf_pubnames_table* pubtypes_table_;
+
// The .gdb_index section.
Output_section* gdb_index_section_;
// The list of DWARF compilation units.
off_t symtab_offset_;
off_t cu_pool_offset_;
off_t stringpool_offset_;
- // Object, section index and offset of last read pubnames section.
+ // Object, stmt list offset of the CUs and TUs associated with the
+ // last read pubnames and pubtypes sections.
const Relobj* pubnames_object_;
- unsigned int pubnames_shndx_;
- off_t pubnames_offset_;
- // Object, section index and offset of last read pubtypes section.
- const Relobj* pubtypes_object_;
- unsigned int pubtypes_shndx_;
- off_t pubtypes_offset_;
+ off_t stmt_list_offset_;
};
} // End namespace gold.