1//===- MapFile.cpp --------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the -Map option. It shows lists in order and
10// hierarchically the output sections, input sections, input files and
11// symbol:
12//
13// Address Size Align Out In Symbol
14// 00201000 00000015 4 .text
15// 00201000 0000000e 4 test.o:(.text)
16// 0020100e 00000000 0 local
17// 00201005 00000000 0 f(int)
18//
19//===----------------------------------------------------------------------===//
20
21#include "MapFile.h"
22#include "InputFiles.h"
23#include "LinkerScript.h"
24#include "OutputSections.h"
25#include "Symbols.h"
26#include "SyntheticSections.h"
27#include "llvm/ADT/MapVector.h"
28#include "llvm/ADT/SetVector.h"
29#include "llvm/ADT/SmallPtrSet.h"
30#include "llvm/Support/Parallel.h"
31#include "llvm/Support/TimeProfiler.h"
32#include "llvm/Support/raw_ostream.h"
33
34using namespace llvm;
35using namespace llvm::object;
36using namespace lld;
37using namespace lld::elf;
38
39using SymbolMapTy = DenseMap<const SectionBase *,
40 SmallVector<std::pair<Defined *, uint64_t>, 0>>;
41
42static constexpr char indent8[] = " "; // 8 spaces
43static constexpr char indent16[] = " "; // 16 spaces
44
45// Print out the first three columns of a line.
46static void writeHeader(Ctx &ctx, raw_ostream &os, uint64_t vma, uint64_t lma,
47 uint64_t size, uint64_t align) {
48 if (ctx.arg.is64)
49 os << format(Fmt: "%16llx %16llx %8llx %5lld ", Vals: vma, Vals: lma, Vals: size, Vals: align);
50 else
51 os << format(Fmt: "%8llx %8llx %8llx %5lld ", Vals: vma, Vals: lma, Vals: size, Vals: align);
52}
53
54// Returns a list of all symbols that we want to print out.
55static std::vector<Defined *> getSymbols(Ctx &ctx) {
56 std::vector<Defined *> v;
57 for (ELFFileBase *file : ctx.objectFiles)
58 for (Symbol *b : file->getSymbols())
59 if (auto *dr = dyn_cast<Defined>(Val: b))
60 if (!dr->isSection() && dr->section && dr->section->isLive() &&
61 (dr->file == file || dr->hasFlag(bit: NEEDS_COPY) ||
62 (isa<SyntheticSection>(Val: dr->section) &&
63 cast<SyntheticSection>(Val: dr->section)->bss)))
64 v.push_back(x: dr);
65 return v;
66}
67
68// Returns a map from sections to their symbols.
69static SymbolMapTy getSectionSyms(Ctx &ctx, ArrayRef<Defined *> syms) {
70 SymbolMapTy ret;
71 for (Defined *dr : syms)
72 ret[dr->section].emplace_back(Args&: dr, Args: dr->getVA(ctx));
73
74 // Sort symbols by address. We want to print out symbols in the
75 // order in the output file rather than the order they appeared
76 // in the input files.
77 SmallPtrSet<Defined *, 4> set;
78 for (auto &it : ret) {
79 // Deduplicate symbols which need a canonical PLT entry/copy relocation.
80 set.clear();
81 llvm::erase_if(C&: it.second, P: [&](std::pair<Defined *, uint64_t> a) {
82 return !set.insert(Ptr: a.first).second;
83 });
84
85 llvm::stable_sort(Range&: it.second, C: llvm::less_second());
86 }
87 return ret;
88}
89
90// Construct a map from symbols to their stringified representations.
91// Demangling symbols (which is what toStr(ctx, ) does) is slow, so
92// we do that in batch using parallel-for.
93static DenseMap<Symbol *, std::string>
94getSymbolStrings(Ctx &ctx, ArrayRef<Defined *> syms) {
95 auto strs = std::make_unique<std::string[]>(num: syms.size());
96 parallelFor(Begin: 0, End: syms.size(), Fn: [&](size_t i) {
97 raw_string_ostream os(strs[i]);
98 OutputSection *osec = syms[i]->getOutputSection();
99 uint64_t vma = syms[i]->getVA(ctx);
100 uint64_t lma = osec ? osec->getLMA() + vma - osec->getVA(offset: 0) : 0;
101 writeHeader(ctx, os, vma, lma, size: syms[i]->getSize(), align: 1);
102 os << indent16 << toStr(ctx, *syms[i]);
103 });
104
105 DenseMap<Symbol *, std::string> ret;
106 for (size_t i = 0, e = syms.size(); i < e; ++i)
107 ret[syms[i]] = std::move(strs[i]);
108 return ret;
109}
110
111// Print .eh_frame contents. Since the section consists of EhSectionPieces,
112// we need a specialized printer for that section.
113//
114// .eh_frame tend to contain a lot of section pieces that are contiguous
115// both in input file and output file. Such pieces are squashed before
116// being displayed to make output compact.
117static void printEhFrame(Ctx &ctx, raw_ostream &os, const EhFrameSection *sec) {
118 std::vector<EhSectionPiece> pieces;
119
120 auto add = [&](const EhSectionPiece &p) {
121 // If P is adjacent to Last, squash the two.
122 if (!pieces.empty()) {
123 EhSectionPiece &last = pieces.back();
124 if (last.sec == p.sec && last.inputOff + last.size == p.inputOff &&
125 last.outputOff + last.size == (unsigned)p.outputOff) {
126 last.size += p.size;
127 return;
128 }
129 }
130 pieces.push_back(x: p);
131 };
132
133 // Gather section pieces.
134 for (const CieRecord *rec : sec->getCieRecords()) {
135 add(*rec->cie);
136 for (const EhSectionPiece *fde : rec->fdes)
137 add(*fde);
138 }
139
140 // Print out section pieces.
141 const OutputSection *osec = sec->getOutputSection();
142 for (EhSectionPiece &p : pieces) {
143 writeHeader(ctx, os, vma: osec->addr + p.outputOff, lma: osec->getLMA() + p.outputOff,
144 size: p.size, align: 1);
145 os << indent8 << toStr(ctx, f: p.sec->file) << ":(" << p.sec->name << "+0x"
146 << Twine::utohexstr(Val: p.inputOff) + ")\n";
147 }
148}
149
150static void writeMapFile(Ctx &ctx, raw_fd_ostream &os) {
151 // Collect symbol info that we want to print out.
152 std::vector<Defined *> syms = getSymbols(ctx);
153 SymbolMapTy sectionSyms = getSectionSyms(ctx, syms);
154 DenseMap<Symbol *, std::string> symStr = getSymbolStrings(ctx, syms);
155
156 // Print out the header line.
157 int w = ctx.arg.is64 ? 16 : 8;
158 os << right_justify(Str: "VMA", Width: w) << ' ' << right_justify(Str: "LMA", Width: w)
159 << " Size Align Out In Symbol\n";
160
161 OutputSection *osec = nullptr;
162 for (SectionCommand *cmd : ctx.script->sectionCommands) {
163 if (auto *assign = dyn_cast<SymbolAssignment>(Val: cmd)) {
164 if (assign->provide && !assign->sym)
165 continue;
166 uint64_t lma = osec ? osec->getLMA() + assign->addr - osec->getVA(offset: 0) : 0;
167 writeHeader(ctx, os, vma: assign->addr, lma, size: assign->size, align: 1);
168 os << assign->commandString << '\n';
169 continue;
170 }
171 if (isa<SectionClassDesc>(Val: cmd))
172 continue;
173
174 osec = &cast<OutputDesc>(Val: cmd)->osec;
175 writeHeader(ctx, os, vma: osec->addr, lma: osec->getLMA(), size: osec->size,
176 align: osec->addralign);
177 os << osec->name << '\n';
178
179 // Dump symbols for each input section.
180 for (SectionCommand *subCmd : osec->commands) {
181 if (auto *isd = dyn_cast<InputSectionDescription>(Val: subCmd)) {
182 for (InputSection *isec : isd->sections) {
183 if (auto *ehSec = dyn_cast<EhFrameSection>(Val: isec)) {
184 printEhFrame(ctx, os, sec: ehSec);
185 continue;
186 }
187
188 writeHeader(ctx, os, vma: isec->getVA(), lma: osec->getLMA() + isec->outSecOff,
189 size: isec->getSize(), align: isec->addralign);
190 os << indent8 << toStr(ctx, isec) << '\n';
191 for (Symbol *sym : llvm::make_first_range(c&: sectionSyms[isec]))
192 os << symStr[sym] << '\n';
193 }
194 continue;
195 }
196
197 if (auto *data = dyn_cast<ByteCommand>(Val: subCmd)) {
198 writeHeader(ctx, os, vma: osec->addr + data->offset,
199 lma: osec->getLMA() + data->offset, size: data->size, align: 1);
200 os << indent8 << data->commandString << '\n';
201 continue;
202 }
203
204 if (auto *assign = dyn_cast<SymbolAssignment>(Val: subCmd)) {
205 if (assign->provide && !assign->sym)
206 continue;
207 writeHeader(ctx, os, vma: assign->addr,
208 lma: osec->getLMA() + assign->addr - osec->getVA(offset: 0),
209 size: assign->size, align: 1);
210 os << indent8 << assign->commandString << '\n';
211 continue;
212 }
213 }
214 }
215}
216
217// Output a cross reference table to stdout. This is for --cref.
218//
219// For each global symbol, we print out a file that defines the symbol
220// followed by files that uses that symbol. Here is an example.
221//
222// strlen /lib/x86_64-linux-gnu/libc.so.6
223// tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
224// lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
225//
226// In this case, strlen is defined by libc.so.6 and used by other two
227// files.
228static void writeCref(Ctx &ctx, raw_fd_ostream &os) {
229 // Collect symbols and files.
230 MapVector<Symbol *, SetVector<InputFile *>> map;
231 for (ELFFileBase *file : ctx.objectFiles) {
232 for (Symbol *sym : file->getSymbols()) {
233 if (isa<SharedSymbol>(Val: sym))
234 map[sym].insert(X: file);
235 if (auto *d = dyn_cast<Defined>(Val: sym))
236 if (!d->isLocal())
237 map[d].insert(X: file);
238 }
239 }
240
241 auto print = [&](StringRef a, StringRef b) {
242 os << left_justify(Str: a, Width: 49) << ' ' << b << '\n';
243 };
244
245 // Print a blank line and a header. The format matches GNU ld.
246 os << "\nCross Reference Table\n\n";
247 print("Symbol", "File");
248
249 // Print out a table.
250 for (auto kv : map) {
251 Symbol *sym = kv.first;
252 SetVector<InputFile *> &files = kv.second;
253
254 print(toStr(ctx, *sym), toStr(ctx, f: sym->file));
255 for (InputFile *file : files)
256 if (file != sym->file)
257 print("", toStr(ctx, f: file));
258 }
259}
260
261void elf::writeMapAndCref(Ctx &ctx) {
262 if (ctx.arg.mapFile.empty() && !ctx.arg.cref)
263 return;
264
265 llvm::TimeTraceScope timeScope("Write map file");
266
267 // Open a map file for writing.
268 std::error_code ec;
269 StringRef mapFile = ctx.arg.mapFile.empty() ? "-" : ctx.arg.mapFile;
270 raw_fd_ostream os = ctx.openAuxiliaryFile(mapFile, ec);
271 if (ec) {
272 ErrAlways(ctx) << "cannot open " << mapFile << ": " << ec.message();
273 return;
274 }
275
276 if (!ctx.arg.mapFile.empty())
277 writeMapFile(ctx, os);
278 if (ctx.arg.cref)
279 writeCref(ctx, os);
280}
281

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of lld/ELF/MapFile.cpp