xref: /llvm-project-15.0.7/lld/ELF/MapFile.cpp (revision 17e86794)
1 //===- 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      Symbol
15 //   00201000 00000015     4 .text
16 //   00201000 0000000e     4         test.o:(.text)
17 //   0020100e 00000000     0                 local
18 //   00201005 00000000     0                 f(int)
19 //
20 //===----------------------------------------------------------------------===//
21 
22 #include "MapFile.h"
23 #include "InputFiles.h"
24 #include "LinkerScript.h"
25 #include "OutputSections.h"
26 #include "SymbolTable.h"
27 #include "Symbols.h"
28 #include "SyntheticSections.h"
29 #include "lld/Common/Strings.h"
30 #include "lld/Common/Threads.h"
31 #include "llvm/Support/raw_ostream.h"
32 
33 using namespace llvm;
34 using namespace llvm::object;
35 
36 using namespace lld;
37 using namespace lld::elf;
38 
39 typedef DenseMap<const SectionBase *, SmallVector<Symbol *, 4>> SymbolMapTy;
40 
41 static const std::string Indent8 = "        ";          // 8 spaces
42 static const std::string Indent16 = "                "; // 16 spaces
43 
44 // Print out the first three columns of a line.
45 static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
46                         uint64_t Align) {
47   int W = Config->Is64 ? 16 : 8;
48   OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
49 }
50 
51 // Returns a list of all symbols that we want to print out.
52 static std::vector<Symbol *> getSymbols() {
53   std::vector<Symbol *> V;
54   for (InputFile *File : ObjectFiles) {
55     for (Symbol *B : File->getSymbols()) {
56       if (auto *SS = dyn_cast<SharedSymbol>(B))
57         if (SS->CopyRelSec || SS->NeedsPltAddr)
58           V.push_back(SS);
59       if (auto *DR = dyn_cast<Defined>(B))
60         if (DR->File == File && !DR->isSection() && DR->Section &&
61             DR->Section->Live)
62           V.push_back(DR);
63     }
64   }
65   return V;
66 }
67 
68 // Returns a map from sections to their symbols.
69 static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
70   SymbolMapTy Ret;
71   for (Symbol *S : Syms) {
72     if (auto *DR = dyn_cast<Defined>(S)) {
73       Ret[DR->Section].push_back(S);
74       continue;
75     }
76 
77     SharedSymbol *SS = cast<SharedSymbol>(S);
78     if (SS->CopyRelSec)
79       Ret[SS->CopyRelSec].push_back(S);
80     else
81       Ret[InX::Plt].push_back(S);
82   }
83 
84   // Sort symbols by address. We want to print out symbols in the
85   // order in the output file rather than the order they appeared
86   // in the input files.
87   for (auto &It : Ret) {
88     SmallVectorImpl<Symbol *> &V = It.second;
89     std::sort(V.begin(), V.end(),
90               [](Symbol *A, Symbol *B) { return A->getVA() < B->getVA(); });
91   }
92   return Ret;
93 }
94 
95 // Construct a map from symbols to their stringified representations.
96 // Demangling symbols (which is what toString() does) is slow, so
97 // we do that in batch using parallel-for.
98 static DenseMap<Symbol *, std::string>
99 getSymbolStrings(ArrayRef<Symbol *> Syms) {
100   std::vector<std::string> Str(Syms.size());
101   parallelForEachN(0, Syms.size(), [&](size_t I) {
102     raw_string_ostream OS(Str[I]);
103     writeHeader(OS, Syms[I]->getVA(), Syms[I]->getSize(), 0);
104     OS << Indent16 << toString(*Syms[I]);
105   });
106 
107   DenseMap<Symbol *, std::string> Ret;
108   for (size_t I = 0, E = Syms.size(); I < E; ++I)
109     Ret[Syms[I]] = std::move(Str[I]);
110   return Ret;
111 }
112 
113 void elf::writeMapFile() {
114   if (Config->MapFile.empty())
115     return;
116 
117   // Open a map file for writing.
118   std::error_code EC;
119   raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
120   if (EC) {
121     error("cannot open " + Config->MapFile + ": " + EC.message());
122     return;
123   }
124 
125   // Collect symbol info that we want to print out.
126   std::vector<Symbol *> Syms = getSymbols();
127   SymbolMapTy SectionSyms = getSectionSyms(Syms);
128   DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);
129 
130   // Print out the header line.
131   int W = Config->Is64 ? 16 : 8;
132   OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
133      << " Align Out     In      Symbol\n";
134 
135   // Print out file contents.
136   for (OutputSection *OSec : OutputSections) {
137     writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment);
138     OS << OSec->Name << '\n';
139 
140     // Dump symbols for each input section.
141     for (InputSection *IS : getInputSections(OSec)) {
142       writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), IS->Alignment);
143       OS << Indent8 << toString(IS) << '\n';
144       for (Symbol *Sym : SectionSyms[IS])
145         OS << SymStr[Sym] << '\n';
146     }
147   }
148 }
149