xref: /llvm-project-15.0.7/lld/ELF/MapFile.cpp (revision 9a572164)
11ebfc59cSRafael Espindola //===- MapFile.cpp --------------------------------------------------------===//
21ebfc59cSRafael Espindola //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61ebfc59cSRafael Espindola //
71ebfc59cSRafael Espindola //===----------------------------------------------------------------------===//
81ebfc59cSRafael Espindola //
91ebfc59cSRafael Espindola // This file implements the -Map option. It shows lists in order and
101ebfc59cSRafael Espindola // hierarchically the output sections, input sections, input files and
111ebfc59cSRafael Espindola // symbol:
121ebfc59cSRafael Espindola //
133012b371SRui Ueyama //   Address  Size     Align Out     In      Symbol
141ebfc59cSRafael Espindola //   00201000 00000015     4 .text
1537811379SRui Ueyama //   00201000 0000000e     4         test.o:(.text)
161ebfc59cSRafael Espindola //   0020100e 00000000     0                 local
171ebfc59cSRafael Espindola //   00201005 00000000     0                 f(int)
181ebfc59cSRafael Espindola //
191ebfc59cSRafael Espindola //===----------------------------------------------------------------------===//
201ebfc59cSRafael Espindola 
211ebfc59cSRafael Espindola #include "MapFile.h"
221ebfc59cSRafael Espindola #include "InputFiles.h"
23a46f688eSRafael Espindola #include "LinkerScript.h"
241b414090SRafael Espindola #include "OutputSections.h"
25d26b52fdSRafael Espindola #include "Symbols.h"
26f2fe963dSGeorge Rimar #include "SyntheticSections.h"
27db46a62eSRui Ueyama #include "llvm/ADT/MapVector.h"
28db46a62eSRui Ueyama #include "llvm/ADT/SetVector.h"
2927bb7990SFangrui Song #include "llvm/ADT/SmallPtrSet.h"
3027bb7990SFangrui Song #include "llvm/Support/FileSystem.h"
31932f0276SReid Kleckner #include "llvm/Support/Parallel.h"
32439341b9SJames Henderson #include "llvm/Support/TimeProfiler.h"
33543731f9SRui Ueyama #include "llvm/Support/raw_ostream.h"
341ebfc59cSRafael Espindola 
351ebfc59cSRafael Espindola using namespace llvm;
361ebfc59cSRafael Espindola using namespace llvm::object;
3707837b8fSFangrui Song using namespace lld;
3807837b8fSFangrui Song using namespace lld::elf;
391ebfc59cSRafael Espindola 
40afeb4a66SFangrui Song using SymbolMapTy = DenseMap<const SectionBase *,
41afeb4a66SFangrui Song                              SmallVector<std::pair<Defined *, uint64_t>, 0>>;
42b882e591SRui Ueyama 
43b3a991dfSBenjamin Kramer static constexpr char indent8[] = "        ";          // 8 spaces
44b3a991dfSBenjamin Kramer static constexpr char indent16[] = "                "; // 16 spaces
459e0171fbSRui Ueyama 
46b882e591SRui Ueyama // 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)473837f427SRui Ueyama static void writeHeader(raw_ostream &os, uint64_t vma, uint64_t lma,
483837f427SRui Ueyama                         uint64_t size, uint64_t align) {
493837f427SRui Ueyama   if (config->is64)
503837f427SRui Ueyama     os << format("%16llx %16llx %8llx %5lld ", vma, lma, size, align);
5116a130bcSRui Ueyama   else
523837f427SRui Ueyama     os << format("%8llx %8llx %8llx %5lld ", vma, lma, size, align);
531ebfc59cSRafael Espindola }
541ebfc59cSRafael Espindola 
553151958cSRui Ueyama // Returns a list of all symbols that we want to print out.
getSymbols()56ab0cce5fSRafael Espindola static std::vector<Defined *> getSymbols() {
573837f427SRui Ueyama   std::vector<Defined *> v;
58*9a572164SFangrui Song   for (ELFFileBase *file : ctx->objectFiles)
593837f427SRui Ueyama     for (Symbol *b : file->getSymbols())
603837f427SRui Ueyama       if (auto *dr = dyn_cast<Defined>(b))
613837f427SRui Ueyama         if (!dr->isSection() && dr->section && dr->section->isLive() &&
62cf783be8SFangrui Song             (dr->file == file || dr->needsCopy || dr->section->bss))
633837f427SRui Ueyama           v.push_back(dr);
643837f427SRui Ueyama   return v;
653151958cSRui Ueyama }
66b882e591SRui Ueyama 
673151958cSRui Ueyama // Returns a map from sections to their symbols.
getSectionSyms(ArrayRef<Defined * > syms)683837f427SRui Ueyama static SymbolMapTy getSectionSyms(ArrayRef<Defined *> syms) {
693837f427SRui Ueyama   SymbolMapTy ret;
703837f427SRui Ueyama   for (Defined *dr : syms)
71afeb4a66SFangrui Song     ret[dr->section].emplace_back(dr, dr->getVA());
72b882e591SRui Ueyama 
73b882e591SRui Ueyama   // Sort symbols by address. We want to print out symbols in the
74b882e591SRui Ueyama   // order in the output file rather than the order they appeared
75b882e591SRui Ueyama   // in the input files.
766a44013bSFangrui Song   SmallPtrSet<Defined *, 4> set;
776a44013bSFangrui Song   for (auto &it : ret) {
786a44013bSFangrui Song     // Deduplicate symbols which need a canonical PLT entry/copy relocation.
796a44013bSFangrui Song     set.clear();
80afeb4a66SFangrui Song     llvm::erase_if(it.second, [&](std::pair<Defined *, uint64_t> a) {
81afeb4a66SFangrui Song       return !set.insert(a.first).second;
82de83cbf3SGeorge Rimar     });
83afeb4a66SFangrui Song 
84afeb4a66SFangrui Song     llvm::stable_sort(it.second, llvm::less_second());
856a44013bSFangrui Song   }
863837f427SRui Ueyama   return ret;
873151958cSRui Ueyama }
881ebfc59cSRafael Espindola 
89b882e591SRui Ueyama // Construct a map from symbols to their stringified representations.
903151958cSRui Ueyama // Demangling symbols (which is what toString() does) is slow, so
913151958cSRui Ueyama // we do that in batch using parallel-for.
9231cd5da5SGeorge Rimar static DenseMap<Symbol *, std::string>
getSymbolStrings(ArrayRef<Defined * > syms)933837f427SRui Ueyama getSymbolStrings(ArrayRef<Defined *> syms) {
941372d536SFangrui Song   auto strs = std::make_unique<std::string[]>(syms.size());
957effcbdaSNico Weber   parallelFor(0, syms.size(), [&](size_t i) {
961372d536SFangrui Song     raw_string_ostream os(strs[i]);
973837f427SRui Ueyama     OutputSection *osec = syms[i]->getOutputSection();
983837f427SRui Ueyama     uint64_t vma = syms[i]->getVA();
993837f427SRui Ueyama     uint64_t lma = osec ? osec->getLMA() + vma - osec->getVA(0) : 0;
1003837f427SRui Ueyama     writeHeader(os, vma, lma, syms[i]->getSize(), 1);
1013837f427SRui Ueyama     os << indent16 << toString(*syms[i]);
102b882e591SRui Ueyama   });
1033151958cSRui Ueyama 
1043837f427SRui Ueyama   DenseMap<Symbol *, std::string> ret;
1053837f427SRui Ueyama   for (size_t i = 0, e = syms.size(); i < e; ++i)
1061372d536SFangrui Song     ret[syms[i]] = std::move(strs[i]);
1073837f427SRui Ueyama   return ret;
1081ebfc59cSRafael Espindola }
1091ebfc59cSRafael Espindola 
110a5c1ed34SRui Ueyama // Print .eh_frame contents. Since the section consists of EhSectionPieces,
111a5c1ed34SRui Ueyama // we need a specialized printer for that section.
112a5c1ed34SRui Ueyama //
113a5c1ed34SRui Ueyama // .eh_frame tend to contain a lot of section pieces that are contiguous
114a5c1ed34SRui Ueyama // both in input file and output file. Such pieces are squashed before
115a5c1ed34SRui Ueyama // being displayed to make output compact.
printEhFrame(raw_ostream & os,const EhFrameSection * sec)1163837f427SRui Ueyama static void printEhFrame(raw_ostream &os, const EhFrameSection *sec) {
1173837f427SRui Ueyama   std::vector<EhSectionPiece> pieces;
118a5c1ed34SRui Ueyama 
1193837f427SRui Ueyama   auto add = [&](const EhSectionPiece &p) {
120a5c1ed34SRui Ueyama     // If P is adjacent to Last, squash the two.
1213837f427SRui Ueyama     if (!pieces.empty()) {
1223837f427SRui Ueyama       EhSectionPiece &last = pieces.back();
1233837f427SRui Ueyama       if (last.sec == p.sec && last.inputOff + last.size == p.inputOff &&
1243837f427SRui Ueyama           last.outputOff + last.size == p.outputOff) {
1253837f427SRui Ueyama         last.size += p.size;
126a5c1ed34SRui Ueyama         return;
127a5c1ed34SRui Ueyama       }
128a5c1ed34SRui Ueyama     }
1293837f427SRui Ueyama     pieces.push_back(p);
130a5c1ed34SRui Ueyama   };
131a5c1ed34SRui Ueyama 
132a5c1ed34SRui Ueyama   // Gather section pieces.
1333837f427SRui Ueyama   for (const CieRecord *rec : sec->getCieRecords()) {
1343837f427SRui Ueyama     add(*rec->cie);
1353837f427SRui Ueyama     for (const EhSectionPiece *fde : rec->fdes)
1363837f427SRui Ueyama       add(*fde);
137a5c1ed34SRui Ueyama   }
138a5c1ed34SRui Ueyama 
139a5c1ed34SRui Ueyama   // Print out section pieces.
1403837f427SRui Ueyama   const OutputSection *osec = sec->getOutputSection();
1413837f427SRui Ueyama   for (EhSectionPiece &p : pieces) {
1423837f427SRui Ueyama     writeHeader(os, osec->addr + p.outputOff, osec->getLMA() + p.outputOff,
1433837f427SRui Ueyama                 p.size, 1);
1443837f427SRui Ueyama     os << indent8 << toString(p.sec->file) << ":(" << p.sec->name << "+0x"
1453837f427SRui Ueyama        << Twine::utohexstr(p.inputOff) + ")\n";
146a5c1ed34SRui Ueyama   }
147a5c1ed34SRui Ueyama }
148a5c1ed34SRui Ueyama 
writeMapFile(raw_fd_ostream & os)1491ce51a5fSFangrui Song static void writeMapFile(raw_fd_ostream &os) {
1503151958cSRui Ueyama   // Collect symbol info that we want to print out.
1513837f427SRui Ueyama   std::vector<Defined *> syms = getSymbols();
1523837f427SRui Ueyama   SymbolMapTy sectionSyms = getSectionSyms(syms);
1533837f427SRui Ueyama   DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms);
1543151958cSRui Ueyama 
1553151958cSRui Ueyama   // Print out the header line.
1563837f427SRui Ueyama   int w = config->is64 ? 16 : 8;
1573837f427SRui Ueyama   os << right_justify("VMA", w) << ' ' << right_justify("LMA", w)
1584e150c4cSRui Ueyama      << "     Size Align Out     In      Symbol\n";
1593151958cSRui Ueyama 
1603837f427SRui Ueyama   OutputSection* osec = nullptr;
1617051aeefSFangrui Song   for (SectionCommand *cmd : script->sectionCommands) {
1627051aeefSFangrui Song     if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) {
1637051aeefSFangrui Song       if (assign->provide && !assign->sym)
164e88b76a9SGeorge Rimar         continue;
1657051aeefSFangrui Song       uint64_t lma = osec ? osec->getLMA() + assign->addr - osec->getVA(0) : 0;
1667051aeefSFangrui Song       writeHeader(os, assign->addr, lma, assign->size, 1);
1677051aeefSFangrui Song       os << assign->commandString << '\n';
168e88b76a9SGeorge Rimar       continue;
169e88b76a9SGeorge Rimar     }
170e88b76a9SGeorge Rimar 
1716c814931SFangrui Song     osec = &cast<OutputDesc>(cmd)->osec;
1723837f427SRui Ueyama     writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment);
1733837f427SRui Ueyama     os << osec->name << '\n';
1743151958cSRui Ueyama 
1753151958cSRui Ueyama     // Dump symbols for each input section.
1767051aeefSFangrui Song     for (SectionCommand *subCmd : osec->commands) {
1777051aeefSFangrui Song       if (auto *isd = dyn_cast<InputSectionDescription>(subCmd)) {
1783837f427SRui Ueyama         for (InputSection *isec : isd->sections) {
1793837f427SRui Ueyama           if (auto *ehSec = dyn_cast<EhFrameSection>(isec)) {
1803837f427SRui Ueyama             printEhFrame(os, ehSec);
181a5c1ed34SRui Ueyama             continue;
182a5c1ed34SRui Ueyama           }
183a5c1ed34SRui Ueyama 
18485e50c10SFangrui Song           writeHeader(os, isec->getVA(), osec->getLMA() + isec->outSecOff,
1853837f427SRui Ueyama                       isec->getSize(), isec->alignment);
1863837f427SRui Ueyama           os << indent8 << toString(isec) << '\n';
187afeb4a66SFangrui Song           for (Symbol *sym : llvm::make_first_range(sectionSyms[isec]))
1883837f427SRui Ueyama             os << symStr[sym] << '\n';
1893151958cSRui Ueyama         }
19084bcabcbSGeorge Rimar         continue;
19184bcabcbSGeorge Rimar       }
19284bcabcbSGeorge Rimar 
1937051aeefSFangrui Song       if (auto *data = dyn_cast<ByteCommand>(subCmd)) {
1947051aeefSFangrui Song         writeHeader(os, osec->addr + data->offset,
1957051aeefSFangrui Song                     osec->getLMA() + data->offset, data->size, 1);
1967051aeefSFangrui Song         os << indent8 << data->commandString << '\n';
19784bcabcbSGeorge Rimar         continue;
19884bcabcbSGeorge Rimar       }
19984bcabcbSGeorge Rimar 
2007051aeefSFangrui Song       if (auto *assign = dyn_cast<SymbolAssignment>(subCmd)) {
2017051aeefSFangrui Song         if (assign->provide && !assign->sym)
202e88b76a9SGeorge Rimar           continue;
2037051aeefSFangrui Song         writeHeader(os, assign->addr,
2047051aeefSFangrui Song                     osec->getLMA() + assign->addr - osec->getVA(0),
2057051aeefSFangrui Song                     assign->size, 1);
2067051aeefSFangrui Song         os << indent8 << assign->commandString << '\n';
20784bcabcbSGeorge Rimar         continue;
20884bcabcbSGeorge Rimar       }
20984bcabcbSGeorge Rimar     }
2103151958cSRui Ueyama   }
2111ebfc59cSRafael Espindola }
212db46a62eSRui Ueyama 
213db46a62eSRui Ueyama // Output a cross reference table to stdout. This is for --cref.
214db46a62eSRui Ueyama //
215db46a62eSRui Ueyama // For each global symbol, we print out a file that defines the symbol
216db46a62eSRui Ueyama // followed by files that uses that symbol. Here is an example.
217db46a62eSRui Ueyama //
218db46a62eSRui Ueyama //     strlen     /lib/x86_64-linux-gnu/libc.so.6
219db46a62eSRui Ueyama //                tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
220db46a62eSRui Ueyama //                lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
221db46a62eSRui Ueyama //
222db46a62eSRui Ueyama // In this case, strlen is defined by libc.so.6 and used by other two
223db46a62eSRui Ueyama // files.
writeCref(raw_fd_ostream & os)2241ce51a5fSFangrui Song static void writeCref(raw_fd_ostream &os) {
225db46a62eSRui Ueyama   // Collect symbols and files.
2263837f427SRui Ueyama   MapVector<Symbol *, SetVector<InputFile *>> map;
227*9a572164SFangrui Song   for (ELFFileBase *file : ctx->objectFiles) {
2283837f427SRui Ueyama     for (Symbol *sym : file->getSymbols()) {
2293837f427SRui Ueyama       if (isa<SharedSymbol>(sym))
2303837f427SRui Ueyama         map[sym].insert(file);
2313837f427SRui Ueyama       if (auto *d = dyn_cast<Defined>(sym))
2323837f427SRui Ueyama         if (!d->isLocal() && (!d->section || d->section->isLive()))
2333837f427SRui Ueyama           map[d].insert(file);
234db46a62eSRui Ueyama     }
235db46a62eSRui Ueyama   }
236db46a62eSRui Ueyama 
2371ce51a5fSFangrui Song   auto print = [&](StringRef a, StringRef b) {
2381ce51a5fSFangrui Song     os << left_justify(a, 49) << ' ' << b << '\n';
2391ce51a5fSFangrui Song   };
2401ce51a5fSFangrui Song 
2411ce51a5fSFangrui Song   // Print a blank line and a header. The format matches GNU ld.
2421ce51a5fSFangrui Song   os << "\nCross Reference Table\n\n";
243db46a62eSRui Ueyama   print("Symbol", "File");
244db46a62eSRui Ueyama 
245db46a62eSRui Ueyama   // Print out a table.
2463837f427SRui Ueyama   for (auto kv : map) {
2473837f427SRui Ueyama     Symbol *sym = kv.first;
2483837f427SRui Ueyama     SetVector<InputFile *> &files = kv.second;
249db46a62eSRui Ueyama 
2503837f427SRui Ueyama     print(toString(*sym), toString(sym->file));
2513837f427SRui Ueyama     for (InputFile *file : files)
2523837f427SRui Ueyama       if (file != sym->file)
2533837f427SRui Ueyama         print("", toString(file));
254db46a62eSRui Ueyama   }
255db46a62eSRui Ueyama }
256bd8cfe65SFangrui Song 
writeMapAndCref()2571ce51a5fSFangrui Song void elf::writeMapAndCref() {
2581ce51a5fSFangrui Song   if (config->mapFile.empty() && !config->cref)
2591ce51a5fSFangrui Song     return;
2601ce51a5fSFangrui Song 
2611ce51a5fSFangrui Song   llvm::TimeTraceScope timeScope("Write map file");
2621ce51a5fSFangrui Song 
2631ce51a5fSFangrui Song   // Open a map file for writing.
2641ce51a5fSFangrui Song   std::error_code ec;
2651ce51a5fSFangrui Song   StringRef mapFile = config->mapFile.empty() ? "-" : config->mapFile;
2661ce51a5fSFangrui Song   raw_fd_ostream os(mapFile, ec, sys::fs::OF_None);
2671ce51a5fSFangrui Song   if (ec) {
2681ce51a5fSFangrui Song     error("cannot open " + mapFile + ": " + ec.message());
2691ce51a5fSFangrui Song     return;
2701ce51a5fSFangrui Song   }
2711ce51a5fSFangrui Song 
2721ce51a5fSFangrui Song   if (!config->mapFile.empty())
2731ce51a5fSFangrui Song     writeMapFile(os);
2741ce51a5fSFangrui Song   if (config->cref)
2751ce51a5fSFangrui Song     writeCref(os);
2761ce51a5fSFangrui Song }
277