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