1 // mapfile.cc -- map file generation for gold 2 3 // Copyright (C) 2008-2014 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 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_file<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 != -1ULL) 257 addr += os->address(); 258 } 259 260 char sizebuf[50]; 261 section_size_type size; 262 if (!relobj->section_is_compressed(shndx, &size)) 263 size = relobj->section_size(shndx); 264 snprintf(sizebuf, sizeof sizebuf, "0x%llx", 265 static_cast<unsigned long long>(size)); 266 267 fprintf(this->map_file_, "0x%0*llx %10s %s\n", 268 parameters->target().get_size() / 4, 269 static_cast<unsigned long long>(addr), sizebuf, 270 relobj->name().c_str()); 271 272 if (os != NULL) 273 { 274 switch (parameters->size_and_endianness()) 275 { 276 #ifdef HAVE_TARGET_32_LITTLE 277 case Parameters::TARGET_32_LITTLE: 278 { 279 const Sized_relobj_file<32, false>* sized_relobj = 280 static_cast<Sized_relobj_file<32, false>*>(relobj); 281 this->print_input_section_symbols(sized_relobj, shndx); 282 } 283 break; 284 #endif 285 #ifdef HAVE_TARGET_32_BIG 286 case Parameters::TARGET_32_BIG: 287 { 288 const Sized_relobj_file<32, true>* sized_relobj = 289 static_cast<Sized_relobj_file<32, true>*>(relobj); 290 this->print_input_section_symbols(sized_relobj, shndx); 291 } 292 break; 293 #endif 294 #ifdef HAVE_TARGET_64_LITTLE 295 case Parameters::TARGET_64_LITTLE: 296 { 297 const Sized_relobj_file<64, false>* sized_relobj = 298 static_cast<Sized_relobj_file<64, false>*>(relobj); 299 this->print_input_section_symbols(sized_relobj, shndx); 300 } 301 break; 302 #endif 303 #ifdef HAVE_TARGET_64_BIG 304 case Parameters::TARGET_64_BIG: 305 { 306 const Sized_relobj_file<64, true>* sized_relobj = 307 static_cast<Sized_relobj_file<64, true>*>(relobj); 308 this->print_input_section_symbols(sized_relobj, shndx); 309 } 310 break; 311 #endif 312 default: 313 gold_unreachable(); 314 } 315 } 316 } 317 318 // Print an Output_section_data. This is printed to look like an 319 // input section. 320 321 void 322 Mapfile::print_output_data(const Output_data* od, const char* name) 323 { 324 this->print_memory_map_header(); 325 326 putc(' ', this->map_file_); 327 328 fprintf(this->map_file_, "%s", name); 329 330 this->advance_to_column(strlen(name) + 1, Mapfile::section_name_map_length); 331 332 char sizebuf[50]; 333 snprintf(sizebuf, sizeof sizebuf, "0x%llx", 334 static_cast<unsigned long long>(od->current_data_size())); 335 336 fprintf(this->map_file_, "0x%0*llx %10s\n", 337 parameters->target().get_size() / 4, 338 (od->is_address_valid() 339 ? static_cast<unsigned long long>(od->address()) 340 : 0), 341 sizebuf); 342 } 343 344 // Print the discarded input sections. 345 346 void 347 Mapfile::print_discarded_sections(const Input_objects* input_objects) 348 { 349 bool printed_header = false; 350 for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); 351 p != input_objects->relobj_end(); 352 ++p) 353 { 354 Relobj* relobj = *p; 355 // Lock the object so we can read from it. This is only called 356 // single-threaded from Layout_task_runner, so it is OK to lock. 357 // Unfortunately we have no way to pass in a Task token. 358 const Task* dummy_task = reinterpret_cast<const Task*>(-1); 359 Task_lock_obj<Object> tl(dummy_task, relobj); 360 361 unsigned int shnum = relobj->shnum(); 362 for (unsigned int i = 0; i < shnum; ++i) 363 { 364 unsigned int sh_type = relobj->section_type(i); 365 if ((sh_type == elfcpp::SHT_PROGBITS 366 || sh_type == elfcpp::SHT_NOBITS 367 || sh_type == elfcpp::SHT_GROUP) 368 && !relobj->is_section_included(i)) 369 { 370 if (!printed_header) 371 { 372 fprintf(this->map_file_, _("\nDiscarded input sections\n\n")); 373 printed_header = true; 374 } 375 376 this->print_input_section(relobj, i); 377 } 378 } 379 } 380 } 381 382 // Print an output section. 383 384 void 385 Mapfile::print_output_section(const Output_section* os) 386 { 387 this->print_memory_map_header(); 388 389 fprintf(this->map_file_, "\n%s", os->name()); 390 391 this->advance_to_column(strlen(os->name()), Mapfile::section_name_map_length); 392 393 char sizebuf[50]; 394 snprintf(sizebuf, sizeof sizebuf, "0x%llx", 395 static_cast<unsigned long long>(os->current_data_size())); 396 397 fprintf(this->map_file_, "0x%0*llx %10s", 398 parameters->target().get_size() / 4, 399 static_cast<unsigned long long>(os->address()), sizebuf); 400 401 if (os->has_load_address()) 402 fprintf(this->map_file_, " load address 0x%-*llx", 403 parameters->target().get_size() / 4, 404 static_cast<unsigned long long>(os->load_address())); 405 406 if (os->requires_postprocessing()) 407 fprintf(this->map_file_, " (before compression)"); 408 409 putc('\n', this->map_file_); 410 } 411 412 } // End namespace gold. 413