1// mapfile.cc -- map file generation for gold 2 3// Copyright (C) 2008-2017 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 37namespace gold 38{ 39 40// Mapfile constructor. 41 42Mapfile::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 52Mapfile::~Mapfile() 53{ 54 if (this->map_file_ != NULL) 55 this->close(); 56} 57 58// Open the map file. 59 60bool 61Mapfile::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 80void 81Mapfile::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 90void 91Mapfile::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 107void 108Mapfile::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 154void 155Mapfile::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 186const size_t Mapfile::section_name_map_length = 16; 187 188// Print the memory map header if necessary. 189 190void 191Mapfile::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 202template<int size, bool big_endian> 203void 204Mapfile::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 235void 236Mapfile::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 321void 322Mapfile::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 346void 347Mapfile::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 384void 385Mapfile::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