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. 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. 56ab0cce5fSRafael Espindola static std::vector<Defined *> getSymbols() { 573837f427SRui Ueyama std::vector<Defined *> v; 587a54ae9cSFangrui Song for (ELFFileBase *file : 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. 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> 933837f427SRui Ueyama getSymbolStrings(ArrayRef<Defined *> syms) { 941372d536SFangrui Song auto strs = std::make_unique<std::string[]>(syms.size()); 95*7effcbdaSNico 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. 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 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. 2241ce51a5fSFangrui Song static void writeCref(raw_fd_ostream &os) { 225db46a62eSRui Ueyama // Collect symbols and files. 2263837f427SRui Ueyama MapVector<Symbol *, SetVector<InputFile *>> map; 2277a54ae9cSFangrui Song for (ELFFileBase *file : 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 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