mapfile.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. // mapfile.cc -- map file generation for gold
  2. // Copyright (C) 2008-2022 Free Software Foundation, Inc.
  3. // Written by Ian Lance Taylor <iant@google.com>.
  4. // This file is part of gold.
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. // MA 02110-1301, USA.
  17. #include "gold.h"
  18. #include <cerrno>
  19. #include <cstdio>
  20. #include <cstring>
  21. #include "archive.h"
  22. #include "symtab.h"
  23. #include "output.h"
  24. #include "mapfile.h"
  25. // This file holds the code for printing information to the map file.
  26. // In general we try to produce pretty much the same format as GNU ld.
  27. namespace gold
  28. {
  29. // Mapfile constructor.
  30. Mapfile::Mapfile()
  31. : map_file_(NULL),
  32. printed_archive_header_(false),
  33. printed_common_header_(false),
  34. printed_memory_map_header_(false)
  35. {
  36. }
  37. // Mapfile destructor.
  38. Mapfile::~Mapfile()
  39. {
  40. if (this->map_file_ != NULL)
  41. this->close();
  42. }
  43. // Open the map file.
  44. bool
  45. Mapfile::open(const char* map_filename)
  46. {
  47. if (strcmp(map_filename, "-") == 0)
  48. this->map_file_ = stdout;
  49. else
  50. {
  51. this->map_file_ = ::fopen(map_filename, "w");
  52. if (this->map_file_ == NULL)
  53. {
  54. gold_error(_("cannot open map file %s: %s"), map_filename,
  55. strerror(errno));
  56. return false;
  57. }
  58. }
  59. return true;
  60. }
  61. // Close the map file.
  62. void
  63. Mapfile::close()
  64. {
  65. if (fclose(this->map_file_) != 0)
  66. gold_error(_("cannot close map file: %s"), strerror(errno));
  67. this->map_file_ = NULL;
  68. }
  69. // Advance to a column.
  70. void
  71. Mapfile::advance_to_column(size_t from, size_t to)
  72. {
  73. if (from >= to - 1)
  74. {
  75. putc('\n', this->map_file_);
  76. from = 0;
  77. }
  78. while (from < to)
  79. {
  80. putc(' ', this->map_file_);
  81. ++from;
  82. }
  83. }
  84. // Report about including a member from an archive.
  85. void
  86. Mapfile::report_include_archive_member(const std::string& member_name,
  87. const Symbol* sym, const char* why)
  88. {
  89. // We print a header before the list of archive members, mainly for
  90. // GNU ld compatibility.
  91. if (!this->printed_archive_header_)
  92. {
  93. fprintf(this->map_file_,
  94. _("Archive member included because of file (symbol)\n\n"));
  95. this->printed_archive_header_ = true;
  96. }
  97. fprintf(this->map_file_, "%s", member_name.c_str());
  98. this->advance_to_column(member_name.length(), 30);
  99. if (sym == NULL)
  100. fprintf(this->map_file_, "%s", why);
  101. else
  102. {
  103. switch (sym->source())
  104. {
  105. case Symbol::FROM_OBJECT:
  106. fprintf(this->map_file_, "%s", sym->object()->name().c_str());
  107. break;
  108. case Symbol::IS_UNDEFINED:
  109. fprintf(this->map_file_, "-u");
  110. break;
  111. default:
  112. case Symbol::IN_OUTPUT_DATA:
  113. case Symbol::IN_OUTPUT_SEGMENT:
  114. case Symbol::IS_CONSTANT:
  115. // We should only see an undefined symbol here.
  116. gold_unreachable();
  117. }
  118. fprintf(this->map_file_, " (%s)", sym->name());
  119. }
  120. putc('\n', this->map_file_);
  121. }
  122. // Report allocating a common symbol.
  123. void
  124. Mapfile::report_allocate_common(const Symbol* sym, uint64_t symsize)
  125. {
  126. if (!this->printed_common_header_)
  127. {
  128. fprintf(this->map_file_, _("\nAllocating common symbols\n"));
  129. fprintf(this->map_file_,
  130. _("Common symbol size file\n\n"));
  131. this->printed_common_header_ = true;
  132. }
  133. std::string demangled_name = sym->demangled_name();
  134. fprintf(this->map_file_, "%s", demangled_name.c_str());
  135. this->advance_to_column(demangled_name.length(), 20);
  136. char buf[50];
  137. snprintf(buf, sizeof buf, "0x%llx", static_cast<unsigned long long>(symsize));
  138. fprintf(this->map_file_, "%s", buf);
  139. size_t len = strlen(buf);
  140. while (len < 18)
  141. {
  142. putc(' ', this->map_file_);
  143. ++len;
  144. }
  145. fprintf(this->map_file_, "%s\n", sym->object()->name().c_str());
  146. }
  147. // The space we make for a section name.
  148. const size_t Mapfile::section_name_map_length = 16;
  149. // Print the memory map header if necessary.
  150. void
  151. Mapfile::print_memory_map_header()
  152. {
  153. if (!this->printed_memory_map_header_)
  154. {
  155. fprintf(this->map_file_, _("\nMemory map\n\n"));
  156. this->printed_memory_map_header_ = true;
  157. }
  158. }
  159. // Print the symbols associated with an input section.
  160. template<int size, bool big_endian>
  161. void
  162. Mapfile::print_input_section_symbols(
  163. const Sized_relobj_file<size, big_endian>* relobj,
  164. unsigned int shndx)
  165. {
  166. unsigned int symcount = relobj->symbol_count();
  167. for (unsigned int i = relobj->local_symbol_count(); i < symcount; ++i)
  168. {
  169. const Symbol* sym = relobj->global_symbol(i);
  170. bool is_ordinary;
  171. if (sym != NULL
  172. && sym->source() == Symbol::FROM_OBJECT
  173. && sym->object() == relobj
  174. && sym->shndx(&is_ordinary) == shndx
  175. && is_ordinary
  176. && sym->is_defined())
  177. {
  178. for (size_t i = 0; i < Mapfile::section_name_map_length; ++i)
  179. putc(' ', this->map_file_);
  180. const Sized_symbol<size>* ssym =
  181. static_cast<const Sized_symbol<size>*>(sym);
  182. fprintf(this->map_file_,
  183. "0x%0*llx %s\n",
  184. size / 4,
  185. static_cast<unsigned long long>(ssym->value()),
  186. sym->demangled_name().c_str());
  187. }
  188. }
  189. }
  190. // Print an input section.
  191. void
  192. Mapfile::print_input_section(Relobj* relobj, unsigned int shndx)
  193. {
  194. putc(' ', this->map_file_);
  195. std::string name = relobj->section_name(shndx);
  196. fprintf(this->map_file_, "%s", name.c_str());
  197. this->advance_to_column(name.length() + 1, Mapfile::section_name_map_length);
  198. Output_section* os;
  199. uint64_t addr;
  200. if (!relobj->is_section_included(shndx))
  201. {
  202. os = NULL;
  203. addr = 0;
  204. }
  205. else
  206. {
  207. os = relobj->output_section(shndx);
  208. addr = relobj->output_section_offset(shndx);
  209. if (addr != -1ULL)
  210. addr += os->address();
  211. }
  212. char sizebuf[50];
  213. section_size_type size;
  214. if (!relobj->section_is_compressed(shndx, &size))
  215. size = relobj->section_size(shndx);
  216. snprintf(sizebuf, sizeof sizebuf, "0x%llx",
  217. static_cast<unsigned long long>(size));
  218. fprintf(this->map_file_, "0x%0*llx %10s %s\n",
  219. parameters->target().get_size() / 4,
  220. static_cast<unsigned long long>(addr), sizebuf,
  221. relobj->name().c_str());
  222. if (os != NULL)
  223. {
  224. switch (parameters->size_and_endianness())
  225. {
  226. #ifdef HAVE_TARGET_32_LITTLE
  227. case Parameters::TARGET_32_LITTLE:
  228. {
  229. const Sized_relobj_file<32, false>* sized_relobj =
  230. static_cast<Sized_relobj_file<32, false>*>(relobj);
  231. this->print_input_section_symbols(sized_relobj, shndx);
  232. }
  233. break;
  234. #endif
  235. #ifdef HAVE_TARGET_32_BIG
  236. case Parameters::TARGET_32_BIG:
  237. {
  238. const Sized_relobj_file<32, true>* sized_relobj =
  239. static_cast<Sized_relobj_file<32, true>*>(relobj);
  240. this->print_input_section_symbols(sized_relobj, shndx);
  241. }
  242. break;
  243. #endif
  244. #ifdef HAVE_TARGET_64_LITTLE
  245. case Parameters::TARGET_64_LITTLE:
  246. {
  247. const Sized_relobj_file<64, false>* sized_relobj =
  248. static_cast<Sized_relobj_file<64, false>*>(relobj);
  249. this->print_input_section_symbols(sized_relobj, shndx);
  250. }
  251. break;
  252. #endif
  253. #ifdef HAVE_TARGET_64_BIG
  254. case Parameters::TARGET_64_BIG:
  255. {
  256. const Sized_relobj_file<64, true>* sized_relobj =
  257. static_cast<Sized_relobj_file<64, true>*>(relobj);
  258. this->print_input_section_symbols(sized_relobj, shndx);
  259. }
  260. break;
  261. #endif
  262. default:
  263. gold_unreachable();
  264. }
  265. }
  266. }
  267. // Print an Output_section_data. This is printed to look like an
  268. // input section.
  269. void
  270. Mapfile::print_output_data(const Output_data* od, const char* name)
  271. {
  272. this->print_memory_map_header();
  273. putc(' ', this->map_file_);
  274. fprintf(this->map_file_, "%s", name);
  275. this->advance_to_column(strlen(name) + 1, Mapfile::section_name_map_length);
  276. char sizebuf[50];
  277. snprintf(sizebuf, sizeof sizebuf, "0x%llx",
  278. static_cast<unsigned long long>(od->current_data_size()));
  279. fprintf(this->map_file_, "0x%0*llx %10s\n",
  280. parameters->target().get_size() / 4,
  281. (od->is_address_valid()
  282. ? static_cast<unsigned long long>(od->address())
  283. : 0),
  284. sizebuf);
  285. }
  286. // Print the discarded input sections.
  287. void
  288. Mapfile::print_discarded_sections(const Input_objects* input_objects)
  289. {
  290. bool printed_header = false;
  291. for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
  292. p != input_objects->relobj_end();
  293. ++p)
  294. {
  295. Relobj* relobj = *p;
  296. // Lock the object so we can read from it. This is only called
  297. // single-threaded from Layout_task_runner, so it is OK to lock.
  298. // Unfortunately we have no way to pass in a Task token.
  299. const Task* dummy_task = reinterpret_cast<const Task*>(-1);
  300. Task_lock_obj<Object> tl(dummy_task, relobj);
  301. unsigned int shnum = relobj->shnum();
  302. for (unsigned int i = 0; i < shnum; ++i)
  303. {
  304. unsigned int sh_type = relobj->section_type(i);
  305. if ((sh_type == elfcpp::SHT_PROGBITS
  306. || sh_type == elfcpp::SHT_NOBITS
  307. || sh_type == elfcpp::SHT_GROUP)
  308. && !relobj->is_section_included(i))
  309. {
  310. if (!printed_header)
  311. {
  312. fprintf(this->map_file_, _("\nDiscarded input sections\n\n"));
  313. printed_header = true;
  314. }
  315. this->print_input_section(relobj, i);
  316. }
  317. }
  318. }
  319. }
  320. // Print an output section.
  321. void
  322. Mapfile::print_output_section(const Output_section* os)
  323. {
  324. this->print_memory_map_header();
  325. fprintf(this->map_file_, "\n%s", os->name());
  326. this->advance_to_column(strlen(os->name()), Mapfile::section_name_map_length);
  327. char sizebuf[50];
  328. snprintf(sizebuf, sizeof sizebuf, "0x%llx",
  329. static_cast<unsigned long long>(os->current_data_size()));
  330. fprintf(this->map_file_, "0x%0*llx %10s",
  331. parameters->target().get_size() / 4,
  332. static_cast<unsigned long long>(os->address()), sizebuf);
  333. if (os->has_load_address())
  334. fprintf(this->map_file_, " load address 0x%-*llx",
  335. parameters->target().get_size() / 4,
  336. static_cast<unsigned long long>(os->load_address()));
  337. if (os->requires_postprocessing())
  338. fprintf(this->map_file_, " (before compression)");
  339. putc('\n', this->map_file_);
  340. }
  341. } // End namespace gold.