blob: 89d7f41f68c44d2b33f507f8b34712b5fdd2e326 [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>
65static void writeMapFile2(int FD,
66 ArrayRef<OutputSectionBase *> OutputSections) {
67 typedef typename ELFT::uint uintX_t;
68 raw_fd_ostream OS(FD, true);
69 int Width = ELFT::Is64Bits ? 16 : 8;
70 OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width)
71 << ' ' << left_justify("Align", 5) << ' ' << left_justify("Out", 7) << ' '
72 << left_justify("In", 7) << ' ' << left_justify("File", 7) << " Symbol\n";
73 for (OutputSectionBase *Sec : OutputSections) {
74 uintX_t VA = Sec->Addr;
75 writeOutSecLine(OS, Width, VA, Sec->Size, Sec->Addralign, Sec->getName());
76 OS << '\n';
77 StringRef PrevName = "";
78 Sec->forEachInputSection([&](InputSectionData *S) {
79 const auto *IS = dyn_cast<InputSection<ELFT>>(S);
80 if (!IS)
81 return;
82 StringRef Name = IS->Name;
83 if (Name != PrevName) {
84 writeInSecLine(OS, Width, VA + IS->OutSecOff, IS->getSize(),
85 IS->Alignment, Name);
86 OS << '\n';
87 PrevName = Name;
88 }
89 elf::ObjectFile<ELFT> *File = IS->getFile();
90 if (!File)
91 return;
92 writeFileLine(OS, Width, VA + IS->OutSecOff, IS->getSize(), IS->Alignment,
93 toString(File));
94 OS << '\n';
95 ArrayRef<SymbolBody *> Syms = File->getSymbols();
96 for (SymbolBody *Sym : Syms) {
97 auto *DR = dyn_cast<DefinedRegular<ELFT>>(Sym);
98 if (!DR)
99 continue;
100 if (DR->Section != IS)
101 continue;
102 if (DR->isSection())
103 continue;
104 writeSymbolLine(OS, Width, Sym->getVA<ELFT>(), Sym->getSize<ELFT>(),
105 toString(*Sym));
106 OS << '\n';
107 }
108 });
109 }
110}
111
112template <class ELFT>
113void elf::writeMapFile(ArrayRef<OutputSectionBase *> OutputSections) {
114 StringRef MapFile = Config->MapFile;
115 if (MapFile.empty())
116 return;
117
118 // Create new file in same directory but with random name.
119 SmallString<128> TempPath;
120 int FD;
121 std::error_code EC =
122 sys::fs::createUniqueFile(Twine(MapFile) + ".tmp%%%%%%%", FD, TempPath);
123 if (EC)
124 fatal(EC.message());
125 FileRemover RAII(TempPath);
126 writeMapFile2<ELFT>(FD, OutputSections);
127 EC = sys::fs::rename(TempPath, MapFile);
128 if (EC)
129 fatal(EC.message());
130}
131
132template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSectionBase *>);
133template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSectionBase *>);
134template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSectionBase *>);
135template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSectionBase *>);