1 // mapfile.cc -- map file generation for gold 2 3 // Copyright 2008 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 29 #include "archive.h" 30 #include "symtab.h" 31 #include "output.h" 32 #include "mapfile.h" 33 34 // This file holds the code for printing information to the map file. 35 // In general we try to produce pretty much the same format as GNU ld. 36 37 namespace gold 38 { 39 40 // Mapfile constructor. 41 42 Mapfile::Mapfile() 43 : map_file_(NULL), 44 printed_archive_header_(false), 45 printed_common_header_(false), 46 printed_memory_map_header_(false) 47 { 48 } 49 50 // Mapfile destructor. 51 52 Mapfile::~Mapfile() 53 { 54 if (this->map_file_ != NULL) 55 this->close(); 56 } 57 58 // Open the map file. 59 60 bool 61 Mapfile::open(const char* map_filename) 62 { 63 if (strcmp(map_filename, "-") == 0) 64 this->map_file_ = stdout; 65 else 66 { 67 this->map_file_ = ::fopen(map_filename, "w"); 68 if (this->map_file_ == NULL) 69 { 70 gold_error(_("cannot open map file %s: %s"), map_filename, 71 strerror(errno)); 72 return false; 73 } 74 } 75 return true; 76 } 77 78 // Close the map file. 79 80 void 81 Mapfile::close() 82 { 83 if (fclose(this->map_file_) != 0) 84 gold_error(_("cannot close map file: %s"), strerror(errno)); 85 this->map_file_ = NULL; 86 } 87 88 // Advance to a column. 89 90 void 91 Mapfile::advance_to_column(size_t from, size_t to) 92 { 93 if (from >= to - 1) 94 { 95 putc('\n', this->map_file_); 96 from = 0; 97 } 98 while (from < to) 99 { 100 putc(' ', this->map_file_); 101 ++from; 102 } 103 } 104 105 // Report about including a member from an archive. 106 107 void 108 Mapfile::report_include_archive_member(const std::string& member_name, 109 const Symbol* sym, const char* why) 110 { 111 // We print a header before the list of archive members, mainly for 112 // GNU ld compatibility. 113 if (!this->printed_archive_header_) 114 { 115 fprintf(this->map_file_, 116 _("Archive member included because of file (symbol)\n\n")); 117 this->printed_archive_header_ = true; 118 } 119 120 fprintf(this->map_file_, "%s", member_name.c_str()); 121 122 this->advance_to_column(member_name.length(), 30); 123 124 if (sym == NULL) 125 fprintf(this->map_file_, "%s", why); 126 else 127 { 128 switch (sym->source()) 129 { 130 case Symbol::FROM_OBJECT: 131 fprintf(this->map_file_, "%s", sym->object()->name().c_str()); 132 break; 133 134 case Symbol::IS_UNDEFINED: 135 fprintf(this->map_file_, "-u"); 136 break; 137 138 default: 139 case Symbol::IN_OUTPUT_DATA: 140 case Symbol::IN_OUTPUT_SEGMENT: 141 case Symbol::IS_CONSTANT: 142 // We should only see an undefined symbol here. 143 gold_unreachable(); 144 } 145 146 fprintf(this->map_file_, " (%s)", sym->name()); 147 } 148 149 putc('\n', this->map_file_); 150 } 151 152 // Report allocating a common symbol. 153 154 void 155 Mapfile::report_allocate_common(const Symbol* sym, uint64_t symsize) 156 { 157 if (!this->printed_common_header_) 158 { 159 fprintf(this->map_file_, _("\nAllocating common symbols\n")); 160 fprintf(this->map_file_, 161 _("Common symbol size file\n\n")); 162 this->printed_common_header_ = true; 163 } 164 165 std::string demangled_name = sym->demangled_name(); 166 fprintf(this->map_file_, "%s", demangled_name.c_str()); 167 168 this->advance_to_column(demangled_name.length(), 20); 169 170 char buf[50]; 171 snprintf(buf, sizeof buf, "0x%llx", static_cast<unsigned long long>(symsize)); 172 fprintf(this->map_file_, "%s", buf); 173 174 size_t len = strlen(buf); 175 while (len < 18) 176 { 177 putc(' ', this->map_file_); 178 ++len; 179 } 180 181 fprintf(this->map_file_, "%s\n", sym->object()->name().c_str()); 182 } 183 184 // The space we make for a section name. 185 186 const size_t Mapfile::section_name_map_length = 16; 187 188 // Print the memory map header if necessary. 189 190 void 191 Mapfile::print_memory_map_header() 192 { 193 if (!this->printed_memory_map_header_) 194 { 195 fprintf(this->map_file_, _("\nMemory map\n\n")); 196 this->printed_memory_map_header_ = true; 197 } 198 } 199 200 // Print the symbols associated with an input section. 201 202 template<int size, bool big_endian> 203 void 204 Mapfile::print_input_section_symbols( 205 const Sized_relobj<size, big_endian>* relobj, 206 unsigned int shndx) 207 { 208 unsigned int symcount = relobj->symbol_count(); 209 for (unsigned int i = relobj->local_symbol_count(); i < symcount; ++i) 210 { 211 const Symbol* sym = relobj->global_symbol(i); 212 bool is_ordinary; 213 if (sym != NULL 214 && sym->source() == Symbol::FROM_OBJECT 215 && sym->object() == relobj 216 && sym->shndx(&is_ordinary) == shndx 217 && is_ordinary 218 && sym->is_defined()) 219 { 220 for (size_t i = 0; i < Mapfile::section_name_map_length; ++i) 221 putc(' ', this->map_file_); 222 const Sized_symbol<size>* ssym = 223 static_cast<const Sized_symbol<size>*>(sym); 224 fprintf(this->map_file_, 225 "0x%0*llx %s\n", 226 size / 4, 227 static_cast<unsigned long long>(ssym->value()), 228 sym->demangled_name().c_str()); 229 } 230 } 231 } 232 233 // Print an input section. 234 235 void 236 Mapfile::print_input_section(Relobj* relobj, unsigned int shndx) 237 { 238 putc(' ', this->map_file_); 239 240 std::string name = relobj->section_name(shndx); 241 fprintf(this->map_file_, "%s", name.c_str()); 242 243 this->advance_to_column(name.length() + 1, Mapfile::section_name_map_length); 244 245 Output_section* os; 246 uint64_t addr; 247 if (!relobj->is_section_included(shndx)) 248 { 249 os = NULL; 250 addr = 0; 251 } 252 else 253 { 254 os = relobj->output_section(shndx); 255 addr = relobj->output_section_offset(shndx); 256 if (addr != -1U) 257 addr += os->address(); 258 } 259 260 char sizebuf[50]; 261 snprintf(sizebuf, sizeof sizebuf, "0x%llx", 262 static_cast<unsigned long long>(relobj->section_size(shndx))); 263 264 fprintf(this->map_file_, "0x%0*llx %10s %s\n", 265 parameters->target().get_size() / 4, 266 static_cast<unsigned long long>(addr), sizebuf, 267 relobj->name().c_str()); 268 269 if (os != NULL) 270 { 271 switch (parameters->size_and_endianness()) 272 { 273 #ifdef HAVE_TARGET_32_LITTLE 274 case Parameters::TARGET_32_LITTLE: 275 { 276 const Sized_relobj<32, false>* sized_relobj = 277 static_cast<Sized_relobj<32, false>*>(relobj); 278 this->print_input_section_symbols(sized_relobj, shndx); 279 } 280 break; 281 #endif 282 #ifdef HAVE_TARGET_32_BIG 283 case Parameters::TARGET_32_BIG: 284 { 285 const Sized_relobj<32, true>* sized_relobj = 286 static_cast<Sized_relobj<32, true>*>(relobj); 287 this->print_input_section_symbols(sized_relobj, shndx); 288 } 289 break; 290 #endif 291 #ifdef HAVE_TARGET_64_LITTLE 292 case Parameters::TARGET_64_LITTLE: 293 { 294 const Sized_relobj<64, false>* sized_relobj = 295 static_cast<Sized_relobj<64, false>*>(relobj); 296 this->print_input_section_symbols(sized_relobj, shndx); 297 } 298 break; 299 #endif 300 #ifdef HAVE_TARGET_64_BIG 301 case Parameters::TARGET_64_BIG: 302 { 303 const Sized_relobj<64, true>* sized_relobj = 304 static_cast<Sized_relobj<64, true>*>(relobj); 305 this->print_input_section_symbols(sized_relobj, shndx); 306 } 307 break; 308 #endif 309 default: 310 gold_unreachable(); 311 } 312 } 313 } 314 315 // Print an Output_section_data. This is printed to look like an 316 // input section. 317 318 void 319 Mapfile::print_output_data(const Output_data* od, const char* name) 320 { 321 this->print_memory_map_header(); 322 323 putc(' ', this->map_file_); 324 325 fprintf(this->map_file_, "%s", name); 326 327 this->advance_to_column(strlen(name) + 1, Mapfile::section_name_map_length); 328 329 char sizebuf[50]; 330 snprintf(sizebuf, sizeof sizebuf, "0x%llx", 331 static_cast<unsigned long long>(od->data_size())); 332 333 fprintf(this->map_file_, "0x%0*llx %10s\n", 334 parameters->target().get_size() / 4, 335 static_cast<unsigned long long>(od->address()), 336 sizebuf); 337 } 338 339 // Print the discarded input sections. 340 341 void 342 Mapfile::print_discarded_sections(const Input_objects* input_objects) 343 { 344 bool printed_header = false; 345 for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); 346 p != input_objects->relobj_end(); 347 ++p) 348 { 349 Relobj* relobj = *p; 350 unsigned int shnum = relobj->shnum(); 351 for (unsigned int i = 0; i < shnum; ++i) 352 { 353 unsigned int sh_type = relobj->section_type(i); 354 if ((sh_type == elfcpp::SHT_PROGBITS 355 || sh_type == elfcpp::SHT_NOBITS 356 || sh_type == elfcpp::SHT_GROUP) 357 && !relobj->is_section_included(i)) 358 { 359 if (!printed_header) 360 { 361 fprintf(this->map_file_, _("\nDiscarded input sections\n\n")); 362 printed_header = true; 363 } 364 365 this->print_input_section(relobj, i); 366 } 367 } 368 } 369 } 370 371 // Print an output section. 372 373 void 374 Mapfile::print_output_section(const Output_section* os) 375 { 376 this->print_memory_map_header(); 377 378 fprintf(this->map_file_, "\n%s", os->name()); 379 380 this->advance_to_column(strlen(os->name()), Mapfile::section_name_map_length); 381 382 char sizebuf[50]; 383 snprintf(sizebuf, sizeof sizebuf, "0x%llx", 384 static_cast<unsigned long long>(os->data_size())); 385 386 fprintf(this->map_file_, "0x%0*llx %10s", 387 parameters->target().get_size() / 4, 388 static_cast<unsigned long long>(os->address()), sizebuf); 389 390 if (os->has_load_address()) 391 fprintf(this->map_file_, " load address 0x%-*llx", 392 parameters->target().get_size() / 4, 393 static_cast<unsigned long long>(os->load_address())); 394 395 putc('\n', this->map_file_); 396 } 397 398 } // End namespace gold. 399