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