blob: 16f4dfd97434f8d7c5d503ee23aad59dec4d95cc [file] [log] [blame]
Rafael Espindola1ebfc592017-01-13 21:05:46 +00001//===- MapFile.cpp --------------------------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the -Map option. It shows lists in order and
11// hierarchically the output sections, input sections, input files and
12// symbol:
13//
14// Address Size Align Out In File Symbol
15// =================================================================
16// 00201000 00000015 4 .text
17// 00201000 0000000e 4 .text
18// 00201000 0000000e 4 test.o
19// 0020100e 00000000 0 local
20// 00201005 00000000 0 f(int)
21//
22//===----------------------------------------------------------------------===//
23
24#include "MapFile.h"
25#include "InputFiles.h"
26#include "Strings.h"
27
28#include "llvm/Support/FileUtilities.h"
29
30using namespace llvm;
31using namespace llvm::object;
32
33using namespace lld;
34using namespace lld::elf;
35
36static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
37 uint64_t Size, uint64_t Align, StringRef Name) {
38 OS << format_hex_no_prefix(Address, Width) << ' '
39 << format_hex_no_prefix(Size, Width) << ' ' << format("%5x ", Align)
40 << left_justify(Name, 7);
41}
42
43static void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
44 uint64_t Size, uint64_t Align, StringRef Name) {
45 // Pass an empty name to align the text to the correct column.
46 writeOutSecLine(OS, Width, Address, Size, Align, "");
47 OS << ' ' << left_justify(Name, 7);
48}
49
50static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address,
51 uint64_t Size, uint64_t Align, StringRef Name) {
52 // Pass an empty name to align the text to the correct column.
53 writeInSecLine(OS, Width, Address, Size, Align, "");
54 OS << ' ' << left_justify(Name, 7);
55}
56
57static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address,
58 uint64_t Size, StringRef Name) {
59 // Pass an empty name to align the text to the correct column.
60 writeFileLine(OS, Width, Address, Size, 0, "");
61 OS << ' ' << left_justify(Name, 7);
62}
63
64template <class ELFT>
Rui Ueyamadb540ff2017-01-14 00:37:28 +000065static void writeInputSection(raw_fd_ostream &OS, const InputSection<ELFT> *IS,
66 StringRef &PrevName) {
67 int Width = ELFT::Is64Bits ? 16 : 8;
68 StringRef Name = IS->Name;
69 if (Name != PrevName) {
70 writeInSecLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
71 IS->Alignment, Name);
72 OS << '\n';
73 PrevName = Name;
74 }
75
76 elf::ObjectFile<ELFT> *File = IS->getFile();
77 if (!File)
78 return;
79 writeFileLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
80 IS->Alignment, toString(File));
81 OS << '\n';
82
83 for (SymbolBody *Sym : File->getSymbols()) {
84 auto *DR = dyn_cast<DefinedRegular<ELFT>>(Sym);
85 if (!DR)
86 continue;
87 if (DR->Section != IS)
88 continue;
89 if (DR->isSection())
90 continue;
91 writeSymbolLine(OS, Width, Sym->getVA<ELFT>(), Sym->getSize<ELFT>(),
92 toString(*Sym));
93 OS << '\n';
94 }
95}
96
97template <class ELFT>
Rafael Espindola1ebfc592017-01-13 21:05:46 +000098static void writeMapFile2(int FD,
99 ArrayRef<OutputSectionBase *> OutputSections) {
Rafael Espindola1ebfc592017-01-13 21:05:46 +0000100 raw_fd_ostream OS(FD, true);
101 int Width = ELFT::Is64Bits ? 16 : 8;
Rui Ueyamadb540ff2017-01-14 00:37:28 +0000102
Rafael Espindola1ebfc592017-01-13 21:05:46 +0000103 OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width)
104 << ' ' << left_justify("Align", 5) << ' ' << left_justify("Out", 7) << ' '
105 << left_justify("In", 7) << ' ' << left_justify("File", 7) << " Symbol\n";
Rui Ueyamadb540ff2017-01-14 00:37:28 +0000106
Rafael Espindola1ebfc592017-01-13 21:05:46 +0000107 for (OutputSectionBase *Sec : OutputSections) {
Rui Ueyamadb540ff2017-01-14 00:37:28 +0000108 writeOutSecLine(OS, Width, Sec->Addr, Sec->Size, Sec->Addralign,
109 Sec->getName());
Rafael Espindola1ebfc592017-01-13 21:05:46 +0000110 OS << '\n';
Rui Ueyamadb540ff2017-01-14 00:37:28 +0000111
Rafael Espindola1ebfc592017-01-13 21:05:46 +0000112 StringRef PrevName = "";
113 Sec->forEachInputSection([&](InputSectionData *S) {
Rui Ueyamadb540ff2017-01-14 00:37:28 +0000114 if (const auto *IS = dyn_cast<InputSection<ELFT>>(S))
115 writeInputSection(OS, IS, PrevName);
Rafael Espindola1ebfc592017-01-13 21:05:46 +0000116 });
117 }
118}
119
120template <class ELFT>
121void elf::writeMapFile(ArrayRef<OutputSectionBase *> OutputSections) {
122 StringRef MapFile = Config->MapFile;
123 if (MapFile.empty())
124 return;
125
126 // Create new file in same directory but with random name.
127 SmallString<128> TempPath;
128 int FD;
129 std::error_code EC =
130 sys::fs::createUniqueFile(Twine(MapFile) + ".tmp%%%%%%%", FD, TempPath);
131 if (EC)
132 fatal(EC.message());
133 FileRemover RAII(TempPath);
134 writeMapFile2<ELFT>(FD, OutputSections);
135 EC = sys::fs::rename(TempPath, MapFile);
136 if (EC)
137 fatal(EC.message());
138}
139
140template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSectionBase *>);
141template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSectionBase *>);
142template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSectionBase *>);
143template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSectionBase *>);