Home | History | Annotate | Download | only in gold
      1 // cref.cc -- cross reference for gold
      2 
      3 // Copyright (C) 2008-2016 Free Software Foundation, Inc.
      4 // Written by Ian Lance Taylor <iant (at) google.com>.
      5 
      6 // This file is part of gold.
      7 
      8 // This program is free software; you can redistribute it and/or modify
      9 // it under the terms of the GNU General Public License as published by
     10 // the Free Software Foundation; either version 3 of the License, or
     11 // (at your option) any later version.
     12 
     13 // This program is distributed in the hope that it will be useful,
     14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 // GNU General Public License for more details.
     17 
     18 // You should have received a copy of the GNU General Public License
     19 // along with this program; if not, write to the Free Software
     20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21 // MA 02110-1301, USA.
     22 
     23 #include "gold.h"
     24 
     25 #include <cerrno>
     26 #include <cstdio>
     27 #include <cstring>
     28 #include <map>
     29 #include <string>
     30 #include <vector>
     31 
     32 #include "object.h"
     33 #include "archive.h"
     34 #include "symtab.h"
     35 #include "cref.h"
     36 
     37 namespace gold
     38 {
     39 
     40 // Class Cref_inputs.  This is used to hold the list of input files
     41 // for cross referencing.
     42 
     43 class Cref_inputs
     44 {
     45  public:
     46   Cref_inputs()
     47     : objects_(), archives_(), current_(&this->objects_)
     48   { }
     49 
     50   // Add an input object file.
     51   void
     52   add_object(Object* object);
     53 
     54   // Start adding an archive.  We support nested archives for future
     55   // flexibility.
     56   void
     57   add_archive_start(Archive*);
     58 
     59   // Finish adding an archive.
     60   void
     61   add_archive_stop(Archive*);
     62 
     63   // Report symbol counts.
     64   void
     65   print_symbol_counts(const Symbol_table*, FILE*) const;
     66 
     67   // Print a cross reference table.
     68   void
     69   print_cref(const Symbol_table*, FILE*) const;
     70 
     71  private:
     72   // A list of input objects.
     73   typedef std::vector<Object*> Objects;
     74 
     75   // Information we record for an archive.
     76   struct Archive_info
     77   {
     78     // Archive name.
     79     std::string name;
     80     // List of objects included from the archive.
     81     Objects* objects;
     82     // Number of archive members.
     83     size_t member_count;
     84   };
     85 
     86   // A mapping from the name of an archive to the list of objects in
     87   // that archive.
     88   typedef std::map<std::string, Archive_info> Archives;
     89 
     90   // For --cref, we build a cross reference table which maps from
     91   // symbols to lists of objects.  The symbols are sorted
     92   // alphabetically.
     93 
     94   class Cref_table_compare
     95   {
     96   public:
     97     bool
     98     operator()(const Symbol*, const Symbol*) const;
     99   };
    100 
    101   typedef std::map<const Symbol*, Objects*, Cref_table_compare> Cref_table;
    102 
    103   // Report symbol counts for a list of Objects.
    104   void
    105   print_objects_symbol_counts(const Symbol_table*, FILE*, const Objects*) const;
    106 
    107   // Report symbol counts for an object.
    108   void
    109   print_object_symbol_counts(const Symbol_table*, FILE*, const Object*) const;
    110 
    111   // Gather cross reference information.
    112   void
    113   gather_cref(const Objects*, Cref_table*) const;
    114 
    115   // List of input objects.
    116   Objects objects_;
    117   // List of input archives.  This is a mapping from the archive file
    118   // name to the list of objects.
    119   Archives archives_;
    120   // The list to which we are currently adding objects.
    121   Objects* current_;
    122 };
    123 
    124 // Add an object.
    125 
    126 void
    127 Cref_inputs::add_object(Object* object)
    128 {
    129   this->current_->push_back(object);
    130 }
    131 
    132 // Start adding an archive.
    133 
    134 void
    135 Cref_inputs::add_archive_start(Archive* archive)
    136 {
    137   gold_assert(this->current_ == &this->objects_);
    138   if (this->archives_.find(archive->name()) == this->archives_.end())
    139     {
    140       Archive_info* pai = &this->archives_[archive->name()];
    141       pai->name = archive->filename();
    142       pai->objects = new Objects();
    143       pai->member_count = archive->count_members();
    144     }
    145   this->current_ = this->archives_[archive->name()].objects;
    146 }
    147 
    148 // Stop adding an archive.
    149 
    150 void
    151 Cref_inputs::add_archive_stop(Archive*)
    152 {
    153   gold_assert(this->current_ != &this->objects_);
    154   this->current_ = &this->objects_;
    155 }
    156 
    157 // Report symbol counts for an object.
    158 
    159 void
    160 Cref_inputs::print_object_symbol_counts(const Symbol_table* symtab,
    161 					FILE* f,
    162 					const Object* object) const
    163 {
    164   size_t defined, used;
    165   object->get_global_symbol_counts(symtab, &defined, &used);
    166   fprintf(f, "symbols %s %zu %zu\n", object->name().c_str(), defined, used);
    167 }
    168 
    169 // Report symbol counts for a list of inputs.
    170 
    171 void
    172 Cref_inputs::print_objects_symbol_counts(const Symbol_table* symtab,
    173 					 FILE* f,
    174 					 const Objects* objects) const
    175 {
    176   for (Objects::const_iterator p = objects->begin();
    177        p != objects->end();
    178        ++p)
    179     this->print_object_symbol_counts(symtab, f, *p);
    180 }
    181 
    182 // Print symbol counts.  This implements --print-symbol-counts.  This
    183 // is intended to be easily read by a program.  This outputs a series
    184 // of lines.  There are two different types of lines.
    185 
    186 // The first is "symbols FILENAME DEFINED USED".  FILENAME is the name
    187 // of an object file included in the link; for an archive, this will
    188 // be ARCHIVEFILENAME(MEMBERNAME).  DEFINED is the number of symbols
    189 // which the object file defines.  USED is the number of symbols which
    190 // are used in the final output; this is the number of symbols which
    191 // appear in the final output table as having been defined by this
    192 // object.  These numbers will be different when weak symbols are
    193 // used, and they will be different for dynamic objects.
    194 
    195 // The second is "archives FILENAME MEMBERS USED".  FILENAME is the
    196 // name of an archive file included in the link.  MEMBERS is the
    197 // number of members of the archive.  USED is the number of archive
    198 // members included in the link.
    199 
    200 void
    201 Cref_inputs::print_symbol_counts(const Symbol_table* symtab, FILE* f) const
    202 {
    203   this->print_objects_symbol_counts(symtab, f, &this->objects_);
    204   for (Archives::const_iterator p = this->archives_.begin();
    205        p != this->archives_.end();
    206        ++p)
    207     {
    208       fprintf(f, "archive %s %zu %zu\n", p->second.name.c_str(),
    209 	     p->second.member_count, p->second.objects->size());
    210       this->print_objects_symbol_counts(symtab, f, p->second.objects);
    211     }
    212 }
    213 
    214 // Sort symbols for the cross reference table.
    215 
    216 bool
    217 Cref_inputs::Cref_table_compare::operator()(const Symbol* s1,
    218 					    const Symbol* s2) const
    219 {
    220   int i = strcmp(s1->name(), s2->name());
    221   if (i != 0)
    222     return i < 0;
    223 
    224   if (s1->version() == NULL)
    225     {
    226       if (s2->version() != NULL)
    227 	return true;
    228     }
    229   else if (s2->version() == NULL)
    230     return false;
    231   else
    232     {
    233       i = strcmp(s1->version(), s2->version());
    234       if (i != 0)
    235 	return i < 0;
    236     }
    237 
    238   // We should never have two different symbols with the same name and
    239   // version.
    240   if (s1 == s2)
    241     return false;
    242   gold_unreachable();
    243 }
    244 
    245 // Gather cross reference information from a list of inputs.
    246 
    247 void
    248 Cref_inputs::gather_cref(const Objects* objects, Cref_table* table) const
    249 {
    250   for (Objects::const_iterator po = objects->begin();
    251        po != objects->end();
    252        ++po)
    253     {
    254       const Object::Symbols* symbols = (*po)->get_global_symbols();
    255       if (symbols == NULL)
    256 	continue;
    257       for (Object::Symbols::const_iterator ps = symbols->begin();
    258 	   ps != symbols->end();
    259 	   ++ps)
    260 	{
    261 	  const Symbol* sym = *ps;
    262 	  if (sym == NULL)
    263 	    continue;
    264 	  Objects* const onull = NULL;
    265 	  std::pair<Cref_table::iterator, bool> ins =
    266 	    table->insert(std::make_pair(sym, onull));
    267 	  Cref_table::iterator pc = ins.first;
    268 	  if (ins.second)
    269 	    pc->second = new Objects();
    270 	  if (sym->source() == Symbol::FROM_OBJECT
    271 	      && sym->object() == *po
    272 	      && sym->is_defined())
    273 	    pc->second->insert(pc->second->begin(), *po);
    274 	  else
    275 	    pc->second->push_back(*po);
    276 	}
    277     }
    278 }
    279 
    280 // The column where the file name starts in a cross reference table.
    281 
    282 static const size_t filecol = 50;
    283 
    284 // Print a cross reference table.
    285 
    286 void
    287 Cref_inputs::print_cref(const Symbol_table*, FILE* f) const
    288 {
    289   Cref_table table;
    290   this->gather_cref(&this->objects_, &table);
    291   for (Archives::const_iterator p = this->archives_.begin();
    292        p != this->archives_.end();
    293        ++p)
    294     this->gather_cref(p->second.objects, &table);
    295 
    296   for (Cref_table::const_iterator pc = table.begin();
    297        pc != table.end();
    298        ++pc)
    299     {
    300       // If all the objects are dynamic, skip this symbol.
    301       const Symbol* sym = pc->first;
    302       const Objects* objects = pc->second;
    303       Objects::const_iterator po;
    304       for (po = objects->begin(); po != objects->end(); ++po)
    305 	if (!(*po)->is_dynamic())
    306 	  break;
    307       if (po == objects->end())
    308 	continue;
    309 
    310       std::string s = sym->demangled_name();
    311       if (sym->version() != NULL)
    312 	{
    313 	  s += '@';
    314 	  if (sym->is_default())
    315 	    s += '@';
    316 	  s += sym->version();
    317 	}
    318 
    319       fputs(s.c_str(), f);
    320 
    321       size_t len = s.length();
    322 
    323       for (po = objects->begin(); po != objects->end(); ++po)
    324 	{
    325 	  int n = len < filecol ? filecol - len : 1;
    326 	  fprintf(f, "%*c%s\n", n, ' ', (*po)->name().c_str());
    327 	  len = 0;
    328 	}
    329     }
    330 }
    331 
    332 // Class Cref.
    333 
    334 // Make sure the Cref_inputs object has been created.
    335 
    336 void
    337 Cref::need_inputs()
    338 {
    339   if (this->inputs_ == NULL)
    340     this->inputs_ = new Cref_inputs();
    341 }
    342 
    343 // Add an input object file.
    344 
    345 void
    346 Cref::add_object(Object* object)
    347 {
    348   this->need_inputs();
    349   this->inputs_->add_object(object);
    350 }
    351 
    352 // Start adding an archive.
    353 
    354 void
    355 Cref::add_archive_start(Archive* archive)
    356 {
    357   this->need_inputs();
    358   this->inputs_->add_archive_start(archive);
    359 }
    360 
    361 // Stop adding an archive.
    362 
    363 void
    364 Cref::add_archive_stop(Archive* archive)
    365 {
    366   this->inputs_->add_archive_stop(archive);
    367 }
    368 
    369 // Print symbol counts.
    370 
    371 void
    372 Cref::print_symbol_counts(const Symbol_table* symtab) const
    373 {
    374   if (parameters->options().user_set_print_symbol_counts()
    375       && this->inputs_ != NULL)
    376     {
    377       FILE* f;
    378       if (strcmp(parameters->options().print_symbol_counts(), "-") == 0)
    379 	f = stdout;
    380       else
    381 	{
    382 	  f = fopen(parameters->options().print_symbol_counts(), "w");
    383 	  if (f == NULL)
    384 	    gold_error(_("cannot open symbol count file %s: %s"),
    385 		       parameters->options().print_symbol_counts(),
    386 		       strerror(errno));
    387 	}
    388       if (f != NULL)
    389 	this->inputs_->print_symbol_counts(symtab, f);
    390     }
    391 }
    392 
    393 // Print a cross reference table.
    394 
    395 void
    396 Cref::print_cref(const Symbol_table* symtab, FILE* f) const
    397 {
    398   fprintf(f, _("\nCross Reference Table\n\n"));
    399   const char* msg = _("Symbol");
    400   int len = filecol - strlen(msg);
    401   fprintf(f, "%s%*c%s\n", msg, len, ' ', _("File"));
    402 
    403   if (parameters->options().cref() && this->inputs_ != NULL)
    404     this->inputs_->print_cref(symtab, f);
    405 }
    406 
    407 } // End namespace gold.
    408