123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- // cref.cc -- cross reference for gold
- // Copyright (C) 2008-2015 Free Software Foundation, Inc.
- // Written by Ian Lance Taylor <iant@google.com>.
- // 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 <cerrno>
- #include <cstdio>
- #include <cstring>
- #include <map>
- #include <string>
- #include <vector>
- #include "object.h"
- #include "archive.h"
- #include "symtab.h"
- #include "cref.h"
- namespace gold
- {
- // Class Cref_inputs. This is used to hold the list of input files
- // for cross referencing.
- class Cref_inputs
- {
- public:
- Cref_inputs()
- : objects_(), archives_(), current_(&this->objects_)
- { }
- // Add an input object file.
- void
- add_object(Object* object);
- // Start adding an archive. We support nested archives for future
- // flexibility.
- void
- add_archive_start(Archive*);
- // Finish adding an archive.
- void
- add_archive_stop(Archive*);
- // Report symbol counts.
- void
- print_symbol_counts(const Symbol_table*, FILE*) const;
- // Print a cross reference table.
- void
- print_cref(const Symbol_table*, FILE*) const;
- private:
- // A list of input objects.
- typedef std::vector<Object*> Objects;
- // Information we record for an archive.
- struct Archive_info
- {
- // Archive name.
- std::string name;
- // List of objects included from the archive.
- Objects* objects;
- // Number of archive members.
- size_t member_count;
- };
- // A mapping from the name of an archive to the list of objects in
- // that archive.
- typedef std::map<std::string, Archive_info> Archives;
- // For --cref, we build a cross reference table which maps from
- // symbols to lists of objects. The symbols are sorted
- // alphabetically.
- class Cref_table_compare
- {
- public:
- bool
- operator()(const Symbol*, const Symbol*) const;
- };
- typedef std::map<const Symbol*, Objects*, Cref_table_compare> Cref_table;
- // Report symbol counts for a list of Objects.
- void
- print_objects_symbol_counts(const Symbol_table*, FILE*, const Objects*) const;
- // Report symbol counts for an object.
- void
- print_object_symbol_counts(const Symbol_table*, FILE*, const Object*) const;
- // Gather cross reference information.
- void
- gather_cref(const Objects*, Cref_table*) const;
- // List of input objects.
- Objects objects_;
- // List of input archives. This is a mapping from the archive file
- // name to the list of objects.
- Archives archives_;
- // The list to which we are currently adding objects.
- Objects* current_;
- };
- // Add an object.
- void
- Cref_inputs::add_object(Object* object)
- {
- this->current_->push_back(object);
- }
- // Start adding an archive.
- void
- Cref_inputs::add_archive_start(Archive* archive)
- {
- gold_assert(this->current_ == &this->objects_);
- if (this->archives_.find(archive->name()) == this->archives_.end())
- {
- Archive_info* pai = &this->archives_[archive->name()];
- pai->name = archive->filename();
- pai->objects = new Objects();
- pai->member_count = archive->count_members();
- }
- this->current_ = this->archives_[archive->name()].objects;
- }
- // Stop adding an archive.
- void
- Cref_inputs::add_archive_stop(Archive*)
- {
- gold_assert(this->current_ != &this->objects_);
- this->current_ = &this->objects_;
- }
- // Report symbol counts for an object.
- void
- Cref_inputs::print_object_symbol_counts(const Symbol_table* symtab,
- FILE* f,
- const Object* object) const
- {
- size_t defined, used;
- object->get_global_symbol_counts(symtab, &defined, &used);
- fprintf(f, "symbols %s %zu %zu\n", object->name().c_str(), defined, used);
- }
- // Report symbol counts for a list of inputs.
- void
- Cref_inputs::print_objects_symbol_counts(const Symbol_table* symtab,
- FILE* f,
- const Objects* objects) const
- {
- for (Objects::const_iterator p = objects->begin();
- p != objects->end();
- ++p)
- this->print_object_symbol_counts(symtab, f, *p);
- }
- // Print symbol counts. This implements --print-symbol-counts. This
- // is intended to be easily read by a program. This outputs a series
- // of lines. There are two different types of lines.
- // The first is "symbols FILENAME DEFINED USED". FILENAME is the name
- // of an object file included in the link; for an archive, this will
- // be ARCHIVEFILENAME(MEMBERNAME). DEFINED is the number of symbols
- // which the object file defines. USED is the number of symbols which
- // are used in the final output; this is the number of symbols which
- // appear in the final output table as having been defined by this
- // object. These numbers will be different when weak symbols are
- // used, and they will be different for dynamic objects.
- // The second is "archives FILENAME MEMBERS USED". FILENAME is the
- // name of an archive file included in the link. MEMBERS is the
- // number of members of the archive. USED is the number of archive
- // members included in the link.
- void
- Cref_inputs::print_symbol_counts(const Symbol_table* symtab, FILE* f) const
- {
- this->print_objects_symbol_counts(symtab, f, &this->objects_);
- for (Archives::const_iterator p = this->archives_.begin();
- p != this->archives_.end();
- ++p)
- {
- fprintf(f, "archive %s %zu %zu\n", p->second.name.c_str(),
- p->second.member_count, p->second.objects->size());
- this->print_objects_symbol_counts(symtab, f, p->second.objects);
- }
- }
- // Sort symbols for the cross reference table.
- bool
- Cref_inputs::Cref_table_compare::operator()(const Symbol* s1,
- const Symbol* s2) const
- {
- int i = strcmp(s1->name(), s2->name());
- if (i != 0)
- return i < 0;
- if (s1->version() == NULL)
- {
- if (s2->version() != NULL)
- return true;
- }
- else if (s2->version() == NULL)
- return false;
- else
- {
- i = strcmp(s1->version(), s2->version());
- if (i != 0)
- return i < 0;
- }
- // We should never have two different symbols with the same name and
- // version.
- if (s1 == s2)
- return false;
- gold_unreachable();
- }
- // Gather cross reference information from a list of inputs.
- void
- Cref_inputs::gather_cref(const Objects* objects, Cref_table* table) const
- {
- for (Objects::const_iterator po = objects->begin();
- po != objects->end();
- ++po)
- {
- const Object::Symbols* symbols = (*po)->get_global_symbols();
- if (symbols == NULL)
- continue;
- for (Object::Symbols::const_iterator ps = symbols->begin();
- ps != symbols->end();
- ++ps)
- {
- const Symbol* sym = *ps;
- if (sym == NULL)
- continue;
- Objects* const onull = NULL;
- std::pair<Cref_table::iterator, bool> ins =
- table->insert(std::make_pair(sym, onull));
- Cref_table::iterator pc = ins.first;
- if (ins.second)
- pc->second = new Objects();
- if (sym->source() == Symbol::FROM_OBJECT
- && sym->object() == *po
- && sym->is_defined())
- pc->second->insert(pc->second->begin(), *po);
- else
- pc->second->push_back(*po);
- }
- }
- }
- // The column where the file name starts in a cross reference table.
- static const size_t filecol = 50;
- // Print a cross reference table.
- void
- Cref_inputs::print_cref(const Symbol_table*, FILE* f) const
- {
- Cref_table table;
- this->gather_cref(&this->objects_, &table);
- for (Archives::const_iterator p = this->archives_.begin();
- p != this->archives_.end();
- ++p)
- this->gather_cref(p->second.objects, &table);
- for (Cref_table::const_iterator pc = table.begin();
- pc != table.end();
- ++pc)
- {
- // If all the objects are dynamic, skip this symbol.
- const Symbol* sym = pc->first;
- const Objects* objects = pc->second;
- Objects::const_iterator po;
- for (po = objects->begin(); po != objects->end(); ++po)
- if (!(*po)->is_dynamic())
- break;
- if (po == objects->end())
- continue;
- std::string s = sym->demangled_name();
- if (sym->version() != NULL)
- {
- s += '@';
- if (sym->is_default())
- s += '@';
- s += sym->version();
- }
- fputs(s.c_str(), f);
- size_t len = s.length();
- for (po = objects->begin(); po != objects->end(); ++po)
- {
- int n = len < filecol ? filecol - len : 1;
- fprintf(f, "%*c%s\n", n, ' ', (*po)->name().c_str());
- len = 0;
- }
- }
- }
- // Class Cref.
- // Make sure the Cref_inputs object has been created.
- void
- Cref::need_inputs()
- {
- if (this->inputs_ == NULL)
- this->inputs_ = new Cref_inputs();
- }
- // Add an input object file.
- void
- Cref::add_object(Object* object)
- {
- this->need_inputs();
- this->inputs_->add_object(object);
- }
- // Start adding an archive.
- void
- Cref::add_archive_start(Archive* archive)
- {
- this->need_inputs();
- this->inputs_->add_archive_start(archive);
- }
- // Stop adding an archive.
- void
- Cref::add_archive_stop(Archive* archive)
- {
- this->inputs_->add_archive_stop(archive);
- }
- // Print symbol counts.
- void
- Cref::print_symbol_counts(const Symbol_table* symtab) const
- {
- if (parameters->options().user_set_print_symbol_counts()
- && this->inputs_ != NULL)
- {
- FILE* f;
- if (strcmp(parameters->options().print_symbol_counts(), "-") == 0)
- f = stdout;
- else
- {
- f = fopen(parameters->options().print_symbol_counts(), "w");
- if (f == NULL)
- gold_error(_("cannot open symbol count file %s: %s"),
- parameters->options().print_symbol_counts(),
- strerror(errno));
- }
- if (f != NULL)
- this->inputs_->print_symbol_counts(symtab, f);
- }
- }
- // Print a cross reference table.
- void
- Cref::print_cref(const Symbol_table* symtab, FILE* f) const
- {
- fprintf(f, _("\nCross Reference Table\n\n"));
- const char* msg = _("Symbol");
- int len = filecol - strlen(msg);
- fprintf(f, "%s%*c%s\n", msg, len, ' ', _("File"));
- if (parameters->options().cref() && this->inputs_ != NULL)
- this->inputs_->print_cref(symtab, f);
- }
- } // End namespace gold.
|