Home | History | Annotate | Download | only in gold
      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