1 // cref.cc -- cross reference for gold
2 
3 // Copyright (C) 2008-2020 Free Software Foundation, Inc.
4 // Written by Ian Lance Taylor <iant@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, where one doesn't forward to the other.
240   if (s1 == s2)
241     return false;
242   if (s1->is_forwarder() && !s2->is_forwarder())
243     return true;
244   if (!s1->is_forwarder() && s2->is_forwarder())
245     return false;
246   gold_unreachable();
247 }
248 
249 // Gather cross reference information from a list of inputs.
250 
251 void
252 Cref_inputs::gather_cref(const Objects* objects, Cref_table* table) const
253 {
254   for (Objects::const_iterator po = objects->begin();
255        po != objects->end();
256        ++po)
257     {
258       const Object::Symbols* symbols = (*po)->get_global_symbols();
259       if (symbols == NULL)
260 	continue;
261       for (Object::Symbols::const_iterator ps = symbols->begin();
262 	   ps != symbols->end();
263 	   ++ps)
264 	{
265 	  const Symbol* sym = *ps;
266 	  if (sym == NULL)
267 	    continue;
268 	  Objects* const onull = NULL;
269 	  std::pair<Cref_table::iterator, bool> ins =
270 	    table->insert(std::make_pair(sym, onull));
271 	  Cref_table::iterator pc = ins.first;
272 	  if (ins.second)
273 	    pc->second = new Objects();
274 	  if (sym->source() == Symbol::FROM_OBJECT
275 	      && sym->object() == *po
276 	      && sym->is_defined())
277 	    pc->second->insert(pc->second->begin(), *po);
278 	  else
279 	    pc->second->push_back(*po);
280 	}
281     }
282 }
283 
284 // The column where the file name starts in a cross reference table.
285 
286 static const size_t filecol = 50;
287 
288 // Print a cross reference table.
289 
290 void
291 Cref_inputs::print_cref(const Symbol_table*, FILE* f) const
292 {
293   Cref_table table;
294   this->gather_cref(&this->objects_, &table);
295   for (Archives::const_iterator p = this->archives_.begin();
296        p != this->archives_.end();
297        ++p)
298     this->gather_cref(p->second.objects, &table);
299 
300   for (Cref_table::const_iterator pc = table.begin();
301        pc != table.end();
302        ++pc)
303     {
304       // If all the objects are dynamic, skip this symbol.
305       const Symbol* sym = pc->first;
306       const Objects* objects = pc->second;
307       Objects::const_iterator po;
308       for (po = objects->begin(); po != objects->end(); ++po)
309 	if (!(*po)->is_dynamic())
310 	  break;
311       if (po == objects->end())
312 	continue;
313 
314       std::string s = sym->demangled_name();
315       if (sym->version() != NULL)
316 	{
317 	  s += '@';
318 	  if (sym->is_default())
319 	    s += '@';
320 	  s += sym->version();
321 	}
322 
323       fputs(s.c_str(), f);
324 
325       size_t len = s.length();
326 
327       for (po = objects->begin(); po != objects->end(); ++po)
328 	{
329 	  int n = len < filecol ? filecol - len : 1;
330 	  fprintf(f, "%*c%s\n", n, ' ', (*po)->name().c_str());
331 	  len = 0;
332 	}
333     }
334 }
335 
336 // Class Cref.
337 
338 // Make sure the Cref_inputs object has been created.
339 
340 void
341 Cref::need_inputs()
342 {
343   if (this->inputs_ == NULL)
344     this->inputs_ = new Cref_inputs();
345 }
346 
347 // Add an input object file.
348 
349 void
350 Cref::add_object(Object* object)
351 {
352   this->need_inputs();
353   this->inputs_->add_object(object);
354 }
355 
356 // Start adding an archive.
357 
358 void
359 Cref::add_archive_start(Archive* archive)
360 {
361   this->need_inputs();
362   this->inputs_->add_archive_start(archive);
363 }
364 
365 // Stop adding an archive.
366 
367 void
368 Cref::add_archive_stop(Archive* archive)
369 {
370   this->inputs_->add_archive_stop(archive);
371 }
372 
373 // Print symbol counts.
374 
375 void
376 Cref::print_symbol_counts(const Symbol_table* symtab) const
377 {
378   if (parameters->options().user_set_print_symbol_counts()
379       && this->inputs_ != NULL)
380     {
381       FILE* f;
382       if (strcmp(parameters->options().print_symbol_counts(), "-") == 0)
383 	f = stdout;
384       else
385 	{
386 	  f = fopen(parameters->options().print_symbol_counts(), "w");
387 	  if (f == NULL)
388 	    gold_error(_("cannot open symbol count file %s: %s"),
389 		       parameters->options().print_symbol_counts(),
390 		       strerror(errno));
391 	}
392       if (f != NULL)
393 	this->inputs_->print_symbol_counts(symtab, f);
394     }
395 }
396 
397 // Print a cross reference table.
398 
399 void
400 Cref::print_cref(const Symbol_table* symtab, FILE* f) const
401 {
402   fprintf(f, _("\nCross Reference Table\n\n"));
403   const char* msg = _("Symbol");
404   int len = filecol - strlen(msg);
405   fprintf(f, "%s%*c%s\n", msg, len, ' ', _("File"));
406 
407   if (parameters->options().cref() && this->inputs_ != NULL)
408     this->inputs_->print_cref(symtab, f);
409 }
410 
411 } // End namespace gold.
412