]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gold/cref.cc
Update year range in copyright notice of all files.
[thirdparty/binutils-gdb.git] / gold / cref.cc
CommitLineData
92de84a6
ILT
1// cref.cc -- cross reference for gold
2
2571583a 3// Copyright (C) 2008-2017 Free Software Foundation, Inc.
92de84a6
ILT
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"
dde3f402 34#include "symtab.h"
92de84a6
ILT
35#include "cref.h"
36
37namespace gold
38{
39
40// Class Cref_inputs. This is used to hold the list of input files
41// for cross referencing.
42
43class 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
9b547ce6 67 // Print a cross reference table.
dde3f402
ILT
68 void
69 print_cref(const Symbol_table*, FILE*) const;
70
92de84a6
ILT
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
dde3f402
ILT
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
92de84a6
ILT
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
dde3f402
ILT
111 // Gather cross reference information.
112 void
113 gather_cref(const Objects*, Cref_table*) const;
114
92de84a6
ILT
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
126void
127Cref_inputs::add_object(Object* object)
128{
129 this->current_->push_back(object);
130}
131
132// Start adding an archive.
133
134void
135Cref_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
150void
151Cref_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
159void
160Cref_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
dde3f402 169// Report symbol counts for a list of inputs.
92de84a6
ILT
170
171void
172Cref_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
200void
201Cref_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
dde3f402
ILT
214// Sort symbols for the cross reference table.
215
216bool
217Cref_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
247void
248Cref_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
282static const size_t filecol = 50;
283
284// Print a cross reference table.
285
286void
287Cref_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
92de84a6
ILT
332// Class Cref.
333
334// Make sure the Cref_inputs object has been created.
335
336void
337Cref::need_inputs()
338{
339 if (this->inputs_ == NULL)
340 this->inputs_ = new Cref_inputs();
341}
342
343// Add an input object file.
344
345void
346Cref::add_object(Object* object)
347{
348 this->need_inputs();
349 this->inputs_->add_object(object);
350}
351
352// Start adding an archive.
353
354void
355Cref::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
363void
364Cref::add_archive_stop(Archive* archive)
365{
366 this->inputs_->add_archive_stop(archive);
367}
368
369// Print symbol counts.
370
371void
372Cref::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
dde3f402
ILT
393// Print a cross reference table.
394
395void
396Cref::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
92de84a6 407} // End namespace gold.