// gdb-index.cc -- generate .gdb_index section for fast debug lookup // Copyright 2012 Free Software Foundation, Inc. // Written by Cary Coutant . // This file is part of gold. // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, // MA 02110-1301, USA. #include "gold.h" #include "gdb-index.h" #include "dwarf_reader.h" #include "dwarf.h" #include "object.h" #include "output.h" #include "demangle.h" namespace gold { const int gdb_index_version = 5; // Sizes of various records in the .gdb_index section. const int gdb_index_offset_size = 4; const int gdb_index_hdr_size = 6 * gdb_index_offset_size; const int gdb_index_cu_size = 16; const int gdb_index_tu_size = 24; const int gdb_index_addr_size = 16 + gdb_index_offset_size; const int gdb_index_sym_size = 2 * gdb_index_offset_size; // This class manages the hashed symbol table for the .gdb_index section. // It is essentially equivalent to the hashtab implementation in libiberty, // but is copied into gdb sources and here for compatibility because its // data structure is exposed on disk. template class Gdb_hashtab { public: Gdb_hashtab() : size_(0), capacity_(0), hashtab_(NULL) { } ~Gdb_hashtab() { for (size_t i = 0; i < this->capacity_; ++i) if (this->hashtab_[i] != NULL) delete this->hashtab_[i]; delete[] this->hashtab_; } // Add a symbol. T* add(T* symbol) { // Resize the hash table if necessary. if (4 * this->size_ / 3 >= this->capacity_) this->expand(); T** slot = this->find_slot(symbol); if (*slot == NULL) { ++this->size_; *slot = symbol; } return *slot; } // Return the current size. size_t size() const { return this->size_; } // Return the current capacity. size_t capacity() const { return this->capacity_; } // Return the contents of slot N. T* operator[](size_t n) { return this->hashtab_[n]; } private: // Find a symbol in the hash table, or return an empty slot if // the symbol is not in the table. T** find_slot(T* symbol) { unsigned int index = symbol->hash() & (this->capacity_ - 1); unsigned int step = ((symbol->hash() * 17) & (this->capacity_ - 1)) | 1; for (;;) { if (this->hashtab_[index] == NULL || this->hashtab_[index]->equal(symbol)) return &this->hashtab_[index]; index = (index + step) & (this->capacity_ - 1); } } // Expand the hash table. void expand() { if (this->capacity_ == 0) { // Allocate the hash table for the first time. this->capacity_ = Gdb_hashtab::initial_size; this->hashtab_ = new T*[this->capacity_]; memset(this->hashtab_, 0, this->capacity_ * sizeof(T*)); } else { // Expand and rehash. unsigned int old_cap = this->capacity_; T** old_hashtab = this->hashtab_; this->capacity_ *= 2; this->hashtab_ = new T*[this->capacity_]; memset(this->hashtab_, 0, this->capacity_ * sizeof(T*)); for (size_t i = 0; i < old_cap; ++i) { if (old_hashtab[i] != NULL) { T** slot = this->find_slot(old_hashtab[i]); *slot = old_hashtab[i]; } } delete[] old_hashtab; } } // Initial size of the hash table; must be a power of 2. static const int initial_size = 1024; size_t size_; size_t capacity_; T** hashtab_; }; // The hash function for strings in the mapped index. This is copied // directly from gdb/dwarf2read.c. static unsigned int mapped_index_string_hash(const unsigned char* str) { unsigned int r = 0; unsigned char c; while ((c = *str++) != 0) { if (gdb_index_version >= 5) c = tolower (c); r = r * 67 + c - 113; } return r; } // A specialization of Dwarf_info_reader, for building the .gdb_index. class Gdb_index_info_reader : public Dwarf_info_reader { public: Gdb_index_info_reader(bool is_type_unit, Relobj* object, const unsigned char* symbols, off_t symbols_size, unsigned int shndx, unsigned int reloc_shndx, unsigned int reloc_type, Gdb_index* gdb_index) : Dwarf_info_reader(is_type_unit, object, symbols, symbols_size, shndx, reloc_shndx, reloc_type), gdb_index_(gdb_index), cu_index_(0), cu_language_(0) { } ~Gdb_index_info_reader() { this->clear_declarations(); } // Print usage statistics. static void print_stats(); protected: // Visit a compilation unit. virtual void visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*); // Visit a type unit. virtual void visit_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature, Dwarf_die*); private: // A map for recording DIEs we've seen that may be referred to be // later DIEs (via DW_AT_specification or DW_AT_abstract_origin). // The map is indexed by a DIE offset within the compile unit. // PARENT_OFFSET_ is the offset of the DIE that represents the // outer context, and NAME_ is a pointer to a component of the // fully-qualified name. // Normally, the names we point to are in a string table, so we don't // have to manage them, but when we have a fully-qualified name // computed, we put it in the table, and set PARENT_OFFSET_ to -1 // indicate a string that we are managing. struct Declaration_pair { Declaration_pair(off_t parent_offset, const char* name) : parent_offset_(parent_offset), name_(name) { } off_t parent_offset_; const char* name_; }; typedef Unordered_map Declaration_map; // Visit a top-level DIE. void visit_top_die(Dwarf_die* die); // Visit the children of a DIE. void visit_children(Dwarf_die* die, Dwarf_die* context); // Visit a DIE. void visit_die(Dwarf_die* die, Dwarf_die* context); // Visit the children of a DIE. void visit_children_for_decls(Dwarf_die* die); // Visit a DIE. void visit_die_for_decls(Dwarf_die* die, Dwarf_die* context); // Guess a fully-qualified name for a class type, based on member function // linkage names. std::string guess_full_class_name(Dwarf_die* die); // Add a declaration DIE to the table of declarations. void add_declaration(Dwarf_die* die, Dwarf_die* context); // Add a declaration whose fully-qualified name is already known. void add_declaration_with_full_name(Dwarf_die* die, const char* full_name); // Return the context for a DIE whose parent is at DIE_OFFSET. std::string get_context(off_t die_offset); // Construct a fully-qualified name for DIE. std::string get_qualified_name(Dwarf_die* die, Dwarf_die* context); // Record the address ranges for a compilation unit. void record_cu_ranges(Dwarf_die* die); // Read the .debug_pubnames and .debug_pubtypes tables. bool read_pubnames_and_pubtypes(Dwarf_die* die); // Clear the declarations map. void clear_declarations(); // The Gdb_index section. Gdb_index* gdb_index_; // The current CU index (negative for a TU). int cu_index_; // The language of the current CU or TU. unsigned int cu_language_; // Map from DIE offset to (parent offset, name) pair, // for DW_AT_specification. Declaration_map declarations_; // Statistics. // Total number of DWARF compilation units processed. static unsigned int dwarf_cu_count; // Number of DWARF compilation units with pubnames/pubtypes. static unsigned int dwarf_cu_nopubnames_count; // Total number of DWARF type units processed. static unsigned int dwarf_tu_count; // Number of DWARF type units with pubnames/pubtypes. static unsigned int dwarf_tu_nopubnames_count; }; // Total number of DWARF compilation units processed. unsigned int Gdb_index_info_reader::dwarf_cu_count = 0; // Number of DWARF compilation units without pubnames/pubtypes. unsigned int Gdb_index_info_reader::dwarf_cu_nopubnames_count = 0; // Total number of DWARF type units processed. unsigned int Gdb_index_info_reader::dwarf_tu_count = 0; // Number of DWARF type units without pubnames/pubtypes. unsigned int Gdb_index_info_reader::dwarf_tu_nopubnames_count = 0; // Process a compilation unit and parse its child DIE. void Gdb_index_info_reader::visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die* root_die) { ++Gdb_index_info_reader::dwarf_cu_count; this->cu_index_ = this->gdb_index_->add_comp_unit(cu_offset, cu_length); this->visit_top_die(root_die); } // Process a type unit and parse its child DIE. void Gdb_index_info_reader::visit_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature, Dwarf_die* root_die) { ++Gdb_index_info_reader::dwarf_tu_count; // Use a negative index to flag this as a TU instead of a CU. this->cu_index_ = -1 - this->gdb_index_->add_type_unit(tu_offset, type_offset, signature); this->visit_top_die(root_die); } // Process a top-level DIE. // For compile_unit DIEs, record the address ranges. For all // interesting tags, add qualified names to the symbol table // and process interesting children. We may need to process // certain children just for saving declarations that might be // referenced by later DIEs with a DW_AT_specification attribute. void Gdb_index_info_reader::visit_top_die(Dwarf_die* die) { this->clear_declarations(); switch (die->tag()) { case elfcpp::DW_TAG_compile_unit: case elfcpp::DW_TAG_type_unit: this->cu_language_ = die->int_attribute(elfcpp::DW_AT_language); // Check for languages that require specialized knowledge to // construct fully-qualified names, that we don't yet support. if (this->cu_language_ == elfcpp::DW_LANG_Ada83 || this->cu_language_ == elfcpp::DW_LANG_Fortran77 || this->cu_language_ == elfcpp::DW_LANG_Fortran90 || this->cu_language_ == elfcpp::DW_LANG_Java || this->cu_language_ == elfcpp::DW_LANG_Ada95 || this->cu_language_ == elfcpp::DW_LANG_Fortran95) { gold_warning(_("%s: --gdb-index currently supports " "only C and C++ languages"), this->object()->name().c_str()); return; } if (die->tag() == elfcpp::DW_TAG_compile_unit) this->record_cu_ranges(die); // If there is a pubnames and/or pubtypes section for this // compilation unit, use those; otherwise, parse the DWARF // info to extract the names. if (!this->read_pubnames_and_pubtypes(die)) { if (die->tag() == elfcpp::DW_TAG_compile_unit) ++Gdb_index_info_reader::dwarf_cu_nopubnames_count; else ++Gdb_index_info_reader::dwarf_tu_nopubnames_count; this->visit_children(die, NULL); } break; default: // The top level DIE should be one of the above. gold_warning(_("%s: top level DIE is not DW_TAG_compile_unit " "or DW_TAG_type_unit"), this->object()->name().c_str()); return; } } // Visit the children of PARENT, looking for symbols to add to the index. // CONTEXT points to the DIE to use for constructing the qualified name -- // NULL if PARENT is the top-level DIE; otherwise it is the same as PARENT. void Gdb_index_info_reader::visit_children(Dwarf_die* parent, Dwarf_die* context) { off_t next_offset = 0; for (off_t die_offset = parent->child_offset(); die_offset != 0; die_offset = next_offset) { Dwarf_die die(this, die_offset, parent); if (die.tag() == 0) break; this->visit_die(&die, context); next_offset = die.sibling_offset(); } } // Visit a child DIE, looking for symbols to add to the index. // CONTEXT is the parent DIE, used for constructing the qualified name; // it is NULL if the parent DIE is the top-level DIE. void Gdb_index_info_reader::visit_die(Dwarf_die* die, Dwarf_die* context) { switch (die->tag()) { case elfcpp::DW_TAG_subprogram: case elfcpp::DW_TAG_constant: case elfcpp::DW_TAG_variable: case elfcpp::DW_TAG_enumerator: case elfcpp::DW_TAG_base_type: if (die->is_declaration()) this->add_declaration(die, context); else { // If the DIE is not a declaration, add it to the index. std::string full_name = this->get_qualified_name(die, context); if (!full_name.empty()) this->gdb_index_->add_symbol(this->cu_index_, full_name.c_str()); } break; case elfcpp::DW_TAG_typedef: case elfcpp::DW_TAG_union_type: case elfcpp::DW_TAG_class_type: case elfcpp::DW_TAG_interface_type: case elfcpp::DW_TAG_structure_type: case elfcpp::DW_TAG_enumeration_type: case elfcpp::DW_TAG_subrange_type: case elfcpp::DW_TAG_namespace: { std::string full_name; // For classes at the top level, we need to look for a // member function with a linkage name in order to get // the properly-canonicalized name. if (context == NULL && (die->tag() == elfcpp::DW_TAG_class_type || die->tag() == elfcpp::DW_TAG_structure_type || die->tag() == elfcpp::DW_TAG_union_type)) full_name.assign(this->guess_full_class_name(die)); // Because we will visit the children, we need to add this DIE // to the declarations table. if (full_name.empty()) this->add_declaration(die, context); else this->add_declaration_with_full_name(die, full_name.c_str()); // If the DIE is not a declaration, add it to the index. // Gdb stores a namespace in the index even when it is // a declaration. if (die->tag() == elfcpp::DW_TAG_namespace || !die->is_declaration()) { if (full_name.empty()) full_name = this->get_qualified_name(die, context); if (!full_name.empty()) this->gdb_index_->add_symbol(this->cu_index_, full_name.c_str()); } // We're interested in the children only for namespaces and // enumeration types. For enumeration types, we do not include // the enumeration tag as part of the full name. For other tags, // visit the children only to collect declarations. if (die->tag() == elfcpp::DW_TAG_namespace || die->tag() == elfcpp::DW_TAG_enumeration_type) this->visit_children(die, die); else this->visit_children_for_decls(die); } break; default: break; } } // Visit the children of PARENT, looking only for declarations that // may be referenced by later specification DIEs. void Gdb_index_info_reader::visit_children_for_decls(Dwarf_die* parent) { off_t next_offset = 0; for (off_t die_offset = parent->child_offset(); die_offset != 0; die_offset = next_offset) { Dwarf_die die(this, die_offset, parent); if (die.tag() == 0) break; this->visit_die_for_decls(&die, parent); next_offset = die.sibling_offset(); } } // Visit a child DIE, looking only for declarations that // may be referenced by later specification DIEs. void Gdb_index_info_reader::visit_die_for_decls(Dwarf_die* die, Dwarf_die* context) { switch (die->tag()) { case elfcpp::DW_TAG_subprogram: case elfcpp::DW_TAG_constant: case elfcpp::DW_TAG_variable: case elfcpp::DW_TAG_enumerator: case elfcpp::DW_TAG_base_type: { if (die->is_declaration()) this->add_declaration(die, context); } break; case elfcpp::DW_TAG_typedef: case elfcpp::DW_TAG_union_type: case elfcpp::DW_TAG_class_type: case elfcpp::DW_TAG_interface_type: case elfcpp::DW_TAG_structure_type: case elfcpp::DW_TAG_enumeration_type: case elfcpp::DW_TAG_subrange_type: case elfcpp::DW_TAG_namespace: { if (die->is_declaration()) this->add_declaration(die, context); this->visit_children_for_decls(die); } break; default: break; } } // Extract the class name from the linkage name of a member function. // This code is adapted from ../gdb/cp-support.c. #define d_left(dc) (dc)->u.s_binary.left #define d_right(dc) (dc)->u.s_binary.right static char* class_name_from_linkage_name(const char* linkage_name) { void* storage; struct demangle_component* tree = cplus_demangle_v3_components(linkage_name, DMGL_NO_OPTS, &storage); if (tree == NULL) return NULL; int done = 0; // First strip off any qualifiers, if we have a function or // method. while (!done) switch (tree->type) { case DEMANGLE_COMPONENT_CONST: case DEMANGLE_COMPONENT_RESTRICT: case DEMANGLE_COMPONENT_VOLATILE: case DEMANGLE_COMPONENT_CONST_THIS: case DEMANGLE_COMPONENT_RESTRICT_THIS: case DEMANGLE_COMPONENT_VOLATILE_THIS: case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: tree = d_left(tree); break; default: done = 1; break; } // If what we have now is a function, discard the argument list. if (tree->type == DEMANGLE_COMPONENT_TYPED_NAME) tree = d_left(tree); // If what we have now is a template, strip off the template // arguments. The left subtree may be a qualified name. if (tree->type == DEMANGLE_COMPONENT_TEMPLATE) tree = d_left(tree); // What we have now should be a name, possibly qualified. // Additional qualifiers could live in the left subtree or the right // subtree. Find the last piece. done = 0; struct demangle_component* prev_comp = NULL; struct demangle_component* cur_comp = tree; while (!done) switch (cur_comp->type) { case DEMANGLE_COMPONENT_QUAL_NAME: case DEMANGLE_COMPONENT_LOCAL_NAME: prev_comp = cur_comp; cur_comp = d_right(cur_comp); break; case DEMANGLE_COMPONENT_TEMPLATE: case DEMANGLE_COMPONENT_NAME: case DEMANGLE_COMPONENT_CTOR: case DEMANGLE_COMPONENT_DTOR: case DEMANGLE_COMPONENT_OPERATOR: case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: done = 1; break; default: done = 1; cur_comp = NULL; break; } char* ret = NULL; if (cur_comp != NULL && prev_comp != NULL) { // We want to discard the rightmost child of PREV_COMP. *prev_comp = *d_left(prev_comp); size_t allocated_size; ret = cplus_demangle_print(DMGL_NO_OPTS, tree, 30, &allocated_size); } free(storage); return ret; } // Guess a fully-qualified name for a class type, based on member function // linkage names. This is needed for class/struct/union types at the // top level, because GCC does not always properly embed them within // the namespace. As in gdb, we look for a member function with a linkage // name and extract the qualified name from the demangled name. std::string Gdb_index_info_reader::guess_full_class_name(Dwarf_die* die) { std::string full_name; off_t next_offset = 0; // This routine scans ahead in the DIE structure, possibly advancing // the relocation tracker beyond the current DIE. We need to checkpoint // the tracker and reset it when we're done. uint64_t checkpoint = this->get_reloc_checkpoint(); for (off_t child_offset = die->child_offset(); child_offset != 0; child_offset = next_offset) { Dwarf_die child(this, child_offset, die); if (child.tag() == 0) break; if (child.tag() == elfcpp::DW_TAG_subprogram) { const char* linkage_name = child.linkage_name(); if (linkage_name != NULL) { char* guess = class_name_from_linkage_name(linkage_name); if (guess != NULL) { full_name.assign(guess); free(guess); break; } } } next_offset = child.sibling_offset(); } this->reset_relocs(checkpoint); return full_name; } // Add a declaration DIE to the table of declarations. void Gdb_index_info_reader::add_declaration(Dwarf_die* die, Dwarf_die* context) { const char* name = die->name(); off_t parent_offset = context != NULL ? context->offset() : 0; // If this DIE has a DW_AT_specification or DW_AT_abstract_origin // attribute, use the parent and name from the earlier declaration. off_t spec = die->specification(); if (spec == 0) spec = die->abstract_origin(); if (spec > 0) { Declaration_map::iterator it = this->declarations_.find(spec); if (it != this->declarations_.end()) { parent_offset = it->second.parent_offset_; name = it->second.name_; } } if (name == NULL) { if (die->tag() == elfcpp::DW_TAG_namespace) name = "(anonymous namespace)"; else if (die->tag() == elfcpp::DW_TAG_union_type) name = "(anonymous union)"; else name = "(unknown)"; } Declaration_pair decl(parent_offset, name); this->declarations_.insert(std::make_pair(die->offset(), decl)); } // Add a declaration whose fully-qualified name is already known. // In the case where we had to get the canonical name by demangling // a linkage name, this ensures we use that name instead of the one // provided in DW_AT_name. void Gdb_index_info_reader::add_declaration_with_full_name( Dwarf_die* die, const char* full_name) { // We need to copy the name. int len = strlen(full_name); char* copy = new char[len + 1]; memcpy(copy, full_name, len + 1); // Flag that we now manage the memory this points to. Declaration_pair decl(-1, copy); this->declarations_.insert(std::make_pair(die->offset(), decl)); } // Return the context for a DIE whose parent is at DIE_OFFSET. std::string Gdb_index_info_reader::get_context(off_t die_offset) { std::string context; Declaration_map::iterator it = this->declarations_.find(die_offset); if (it != this->declarations_.end()) { off_t parent_offset = it->second.parent_offset_; if (parent_offset > 0) { context = get_context(parent_offset); context.append("::"); } if (it->second.name_ != NULL) context.append(it->second.name_); } return context; } // Construct the fully-qualified name for DIE. std::string Gdb_index_info_reader::get_qualified_name(Dwarf_die* die, Dwarf_die* context) { std::string full_name; const char* name = die->name(); off_t parent_offset = context != NULL ? context->offset() : 0; // If this DIE has a DW_AT_specification or DW_AT_abstract_origin // attribute, use the parent and name from the earlier declaration. off_t spec = die->specification(); if (spec == 0) spec = die->abstract_origin(); if (spec > 0) { Declaration_map::iterator it = this->declarations_.find(spec); if (it != this->declarations_.end()) { parent_offset = it->second.parent_offset_; name = it->second.name_; } } if (name == NULL && die->tag() == elfcpp::DW_TAG_namespace) name = "(anonymous namespace)"; else if (name == NULL) return full_name; // If this is an enumerator constant, skip the immediate parent, // which is the enumeration tag. if (die->tag() == elfcpp::DW_TAG_enumerator) { Declaration_map::iterator it = this->declarations_.find(parent_offset); if (it != this->declarations_.end()) parent_offset = it->second.parent_offset_; } if (parent_offset > 0) { full_name.assign(this->get_context(parent_offset)); full_name.append("::"); } full_name.append(name); return full_name; } // Record the address ranges for a compilation unit. void Gdb_index_info_reader::record_cu_ranges(Dwarf_die* die) { unsigned int shndx; unsigned int shndx2; off_t ranges_offset = die->ref_attribute(elfcpp::DW_AT_ranges, &shndx); if (ranges_offset != -1) { Dwarf_range_list* ranges = this->read_range_list(shndx, ranges_offset); if (ranges != NULL) this->gdb_index_->add_address_range_list(this->object(), this->cu_index_, ranges); return; } off_t low_pc = die->ref_attribute(elfcpp::DW_AT_low_pc, &shndx); off_t high_pc = die->ref_attribute(elfcpp::DW_AT_high_pc, &shndx2); if (low_pc != 0 && high_pc != 0 && low_pc != -1 && high_pc != -1) { if (shndx != shndx2) { gold_warning(_("%s: DWARF info may be corrupt; low_pc and high_pc " "are in different sections"), this->object()->name().c_str()); return; } if (shndx == 0 || this->object()->is_section_included(shndx)) { Dwarf_range_list* ranges = new Dwarf_range_list(); ranges->add(shndx, low_pc, high_pc); this->gdb_index_->add_address_range_list(this->object(), this->cu_index_, ranges); } } } // Read the .debug_pubnames and .debug_pubtypes tables for the CU or TU. // Returns TRUE if either a pubnames or pubtypes section was found. bool Gdb_index_info_reader::read_pubnames_and_pubtypes(Dwarf_die* die) { 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 (this->gdb_index_->pubnames_read(pubnames_shndx, pubnames_offset)) ret = true; else { Dwarf_pubnames_table pubnames(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; } } // 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) { if (this->gdb_index_->pubtypes_read(pubtypes_shndx, pubtypes_offset)) ret = true; else { Dwarf_pubnames_table pubtypes(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; } } return ret; } // Clear the declarations map. void Gdb_index_info_reader::clear_declarations() { // Free strings in memory we manage. for (Declaration_map::iterator it = this->declarations_.begin(); it != this->declarations_.end(); ++it) { if (it->second.parent_offset_ == -1) delete[] it->second.name_; } this->declarations_.clear(); } // Print usage statistics. void Gdb_index_info_reader::print_stats() { fprintf(stderr, _("%s: DWARF CUs: %u\n"), program_name, Gdb_index_info_reader::dwarf_cu_count); fprintf(stderr, _("%s: DWARF CUs without pubnames/pubtypes: %u\n"), program_name, Gdb_index_info_reader::dwarf_cu_nopubnames_count); fprintf(stderr, _("%s: DWARF TUs: %u\n"), program_name, Gdb_index_info_reader::dwarf_tu_count); fprintf(stderr, _("%s: DWARF TUs without pubnames/pubtypes: %u\n"), program_name, Gdb_index_info_reader::dwarf_tu_nopubnames_count); } // Class Gdb_index. // Construct the .gdb_index section. Gdb_index::Gdb_index(Output_section* gdb_index_section) : Output_section_data(4), gdb_index_section_(gdb_index_section), comp_units_(), type_units_(), ranges_(), cu_vector_list_(), cu_vector_offsets_(NULL), stringpool_(), tu_offset_(0), addr_offset_(0), symtab_offset_(0), cu_pool_offset_(0), stringpool_offset_(0), pubnames_shndx_(0), pubnames_offset_(0), pubtypes_shndx_(0), pubtypes_offset_(0) { this->gdb_symtab_ = new Gdb_hashtab(); } Gdb_index::~Gdb_index() { // Free the memory used by the symbol table. delete this->gdb_symtab_; // Free the memory used by the CU vectors. for (unsigned int i = 0; i < this->cu_vector_list_.size(); ++i) delete this->cu_vector_list_[i]; } // Scan a .debug_info or .debug_types input section. void Gdb_index::scan_debug_info(bool is_type_unit, Relobj* object, const unsigned char* symbols, off_t symbols_size, unsigned int shndx, unsigned int reloc_shndx, unsigned int reloc_type) { Gdb_index_info_reader dwinfo(is_type_unit, object, symbols, symbols_size, shndx, reloc_shndx, reloc_type, this); dwinfo.parse(); } // Add a symbol. void Gdb_index::add_symbol(int cu_index, const char* sym_name) { unsigned int hash = mapped_index_string_hash( reinterpret_cast(sym_name)); Gdb_symbol* sym = new Gdb_symbol(); this->stringpool_.add(sym_name, true, &sym->name_key); sym->hashval = hash; sym->cu_vector_index = 0; Gdb_symbol* found = this->gdb_symtab_->add(sym); if (found == sym) { // New symbol -- allocate a new CU index vector. found->cu_vector_index = this->cu_vector_list_.size(); this->cu_vector_list_.push_back(new Cu_vector()); } else { // Found an existing symbol -- append to the existing // CU index vector. delete sym; } // Add the CU index to the vector list for this symbol, // if it's not already on the list. We only need to // check the last added entry. Cu_vector* cu_vec = this->cu_vector_list_[found->cu_vector_index]; if (cu_vec->size() == 0 || cu_vec->back() != cu_index) cu_vec->push_back(cu_index); } // Return TRUE if we have already processed the pubnames set at // OFFSET in section SHNDX bool Gdb_index::pubnames_read(unsigned int shndx, off_t offset) { bool ret = (this->pubnames_shndx_ == shndx && this->pubnames_offset_ == offset); this->pubnames_shndx_ = shndx; this->pubnames_offset_ = offset; return ret; } // Return TRUE if we have already processed the pubtypes set at // OFFSET in section SHNDX bool Gdb_index::pubtypes_read(unsigned int shndx, off_t offset) { bool ret = (this->pubtypes_shndx_ == shndx && this->pubtypes_offset_ == offset); this->pubtypes_shndx_ = shndx; this->pubtypes_offset_ = offset; return ret; } // Set the size of the .gdb_index section. void Gdb_index::set_final_data_size() { // Finalize the string pool. this->stringpool_.set_string_offsets(); // Compute the total size of the CU vectors. // For each CU vector, include one entry for the count at the // beginning of the vector. unsigned int cu_vector_count = this->cu_vector_list_.size(); unsigned int cu_vector_size = 0; this->cu_vector_offsets_ = new off_t[cu_vector_count]; for (unsigned int i = 0; i < cu_vector_count; ++i) { Cu_vector* cu_vec = this->cu_vector_list_[i]; cu_vector_offsets_[i] = cu_vector_size; cu_vector_size += gdb_index_offset_size * (cu_vec->size() + 1); } // Assign relative offsets to each portion of the index, // and find the total size of the section. section_size_type data_size = gdb_index_hdr_size; data_size += this->comp_units_.size() * gdb_index_cu_size; this->tu_offset_ = data_size; data_size += this->type_units_.size() * gdb_index_tu_size; this->addr_offset_ = data_size; for (unsigned int i = 0; i < this->ranges_.size(); ++i) data_size += this->ranges_[i].ranges->size() * gdb_index_addr_size; this->symtab_offset_ = data_size; data_size += this->gdb_symtab_->capacity() * gdb_index_sym_size; this->cu_pool_offset_ = data_size; data_size += cu_vector_size; this->stringpool_offset_ = data_size; data_size += this->stringpool_.get_strtab_size(); this->set_data_size(data_size); } // Write the data to the file. void Gdb_index::do_write(Output_file* of) { const off_t off = this->offset(); const off_t oview_size = this->data_size(); unsigned char* const oview = of->get_output_view(off, oview_size); unsigned char* pov = oview; // Write the file header. // (1) Version number. elfcpp::Swap<32, false>::writeval(pov, gdb_index_version); pov += 4; // (2) Offset of the CU list. elfcpp::Swap<32, false>::writeval(pov, gdb_index_hdr_size); pov += 4; // (3) Offset of the types CU list. elfcpp::Swap<32, false>::writeval(pov, this->tu_offset_); pov += 4; // (4) Offset of the address area. elfcpp::Swap<32, false>::writeval(pov, this->addr_offset_); pov += 4; // (5) Offset of the symbol table. elfcpp::Swap<32, false>::writeval(pov, this->symtab_offset_); pov += 4; // (6) Offset of the constant pool. elfcpp::Swap<32, false>::writeval(pov, this->cu_pool_offset_); pov += 4; gold_assert(pov - oview == gdb_index_hdr_size); // Write the CU list. unsigned int comp_units_count = this->comp_units_.size(); for (unsigned int i = 0; i < comp_units_count; ++i) { const Comp_unit& cu = this->comp_units_[i]; elfcpp::Swap<64, false>::writeval(pov, cu.cu_offset); elfcpp::Swap<64, false>::writeval(pov + 8, cu.cu_length); pov += 16; } gold_assert(pov - oview == this->tu_offset_); // Write the types CU list. for (unsigned int i = 0; i < this->type_units_.size(); ++i) { const Type_unit& tu = this->type_units_[i]; elfcpp::Swap<64, false>::writeval(pov, tu.tu_offset); elfcpp::Swap<64, false>::writeval(pov + 8, tu.type_offset); elfcpp::Swap<64, false>::writeval(pov + 16, tu.type_signature); pov += 24; } gold_assert(pov - oview == this->addr_offset_); // Write the address area. for (unsigned int i = 0; i < this->ranges_.size(); ++i) { int cu_index = this->ranges_[i].cu_index; // Translate negative indexes, which refer to a TU, to a // logical index into a concatenated CU/TU list. if (cu_index < 0) cu_index = comp_units_count + (-1 - cu_index); Relobj* object = this->ranges_[i].object; const Dwarf_range_list& ranges = *this->ranges_[i].ranges; for (unsigned int j = 0; j < ranges.size(); ++j) { const Dwarf_range_list::Range& range = ranges[j]; uint64_t base = 0; if (range.shndx > 0) { const Output_section* os = object->output_section(range.shndx); base = (os->address() + object->output_section_offset(range.shndx)); } elfcpp::Swap<64, false>::writeval(pov, base + range.start); elfcpp::Swap<64, false>::writeval(pov + 8, base + range.end); elfcpp::Swap<32, false>::writeval(pov + 16, cu_index); pov += 20; } } gold_assert(pov - oview == this->symtab_offset_); // Write the symbol table. for (unsigned int i = 0; i < this->gdb_symtab_->capacity(); ++i) { const Gdb_symbol* sym = (*this->gdb_symtab_)[i]; section_offset_type name_offset = 0; unsigned int cu_vector_offset = 0; if (sym != NULL) { name_offset = (this->stringpool_.get_offset_from_key(sym->name_key) + this->stringpool_offset_ - this->cu_pool_offset_); cu_vector_offset = this->cu_vector_offsets_[sym->cu_vector_index]; } elfcpp::Swap<32, false>::writeval(pov, name_offset); elfcpp::Swap<32, false>::writeval(pov + 4, cu_vector_offset); pov += 8; } gold_assert(pov - oview == this->cu_pool_offset_); // Write the CU vectors into the constant pool. for (unsigned int i = 0; i < this->cu_vector_list_.size(); ++i) { Cu_vector* cu_vec = this->cu_vector_list_[i]; elfcpp::Swap<32, false>::writeval(pov, cu_vec->size()); pov += 4; for (unsigned int j = 0; j < cu_vec->size(); ++j) { int cu_index = (*cu_vec)[j]; if (cu_index < 0) cu_index = comp_units_count + (-1 - cu_index); elfcpp::Swap<32, false>::writeval(pov, cu_index); pov += 4; } } gold_assert(pov - oview == this->stringpool_offset_); // Write the strings into the constant pool. this->stringpool_.write_to_buffer(pov, oview_size - this->stringpool_offset_); of->write_output_view(off, oview_size, oview); } // Print usage statistics. void Gdb_index::print_stats() { if (parameters->options().gdb_index()) Gdb_index_info_reader::print_stats(); } } // End namespace gold.