1317025Sdim//===- MapFile.cpp --------------------------------------------------------===// 2317025Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317025Sdim// 7317025Sdim//===----------------------------------------------------------------------===// 8317025Sdim// 9317025Sdim// This file implements the -Map option. It shows lists in order and 10317025Sdim// hierarchically the output sections, input sections, input files and 11317025Sdim// symbol: 12317025Sdim// 13317778Sdim// Address Size Align Out In Symbol 14317778Sdim// 00201000 00000015 4 .text 15317778Sdim// 00201000 0000000e 4 test.o:(.text) 16317778Sdim// 0020100e 00000000 0 local 17317778Sdim// 00201005 00000000 0 f(int) 18317025Sdim// 19317025Sdim//===----------------------------------------------------------------------===// 20317025Sdim 21317025Sdim#include "MapFile.h" 22317025Sdim#include "InputFiles.h" 23318681Sdim#include "LinkerScript.h" 24318681Sdim#include "OutputSections.h" 25317778Sdim#include "SymbolTable.h" 26327952Sdim#include "Symbols.h" 27327952Sdim#include "SyntheticSections.h" 28341825Sdim#include "lld/Common/Strings.h" 29327952Sdim#include "lld/Common/Threads.h" 30341825Sdim#include "llvm/ADT/MapVector.h" 31341825Sdim#include "llvm/ADT/SetVector.h" 32317025Sdim#include "llvm/Support/raw_ostream.h" 33317025Sdim 34317025Sdimusing namespace llvm; 35317025Sdimusing namespace llvm::object; 36317025Sdim 37360784Sdimnamespace lld { 38360784Sdimnamespace elf { 39353358Sdimusing SymbolMapTy = DenseMap<const SectionBase *, SmallVector<Defined *, 4>>; 40317025Sdim 41360784Sdimstatic constexpr char indent8[] = " "; // 8 spaces 42360784Sdimstatic constexpr char indent16[] = " "; // 16 spaces 43341825Sdim 44317778Sdim// Print out the first three columns of a line. 45353358Sdimstatic void writeHeader(raw_ostream &os, uint64_t vma, uint64_t lma, 46353358Sdim uint64_t size, uint64_t align) { 47353358Sdim if (config->is64) 48353358Sdim os << format("%16llx %16llx %8llx %5lld ", vma, lma, size, align); 49341825Sdim else 50353358Sdim os << format("%8llx %8llx %8llx %5lld ", vma, lma, size, align); 51317025Sdim} 52317025Sdim 53317778Sdim// Returns a list of all symbols that we want to print out. 54341825Sdimstatic std::vector<Defined *> getSymbols() { 55353358Sdim std::vector<Defined *> v; 56353358Sdim for (InputFile *file : objectFiles) 57353358Sdim for (Symbol *b : file->getSymbols()) 58353358Sdim if (auto *dr = dyn_cast<Defined>(b)) 59353358Sdim if (!dr->isSection() && dr->section && dr->section->isLive() && 60353358Sdim (dr->file == file || dr->needsPltAddr || dr->section->bss)) 61353358Sdim v.push_back(dr); 62353358Sdim return v; 63317025Sdim} 64317025Sdim 65317778Sdim// Returns a map from sections to their symbols. 66353358Sdimstatic SymbolMapTy getSectionSyms(ArrayRef<Defined *> syms) { 67353358Sdim SymbolMapTy ret; 68353358Sdim for (Defined *dr : syms) 69353358Sdim ret[dr->section].push_back(dr); 70317025Sdim 71317778Sdim // Sort symbols by address. We want to print out symbols in the 72317778Sdim // order in the output file rather than the order they appeared 73317778Sdim // in the input files. 74353358Sdim for (auto &it : ret) 75353358Sdim llvm::stable_sort(it.second, [](Defined *a, Defined *b) { 76353358Sdim return a->getVA() < b->getVA(); 77341825Sdim }); 78353358Sdim return ret; 79317025Sdim} 80317025Sdim 81317778Sdim// Construct a map from symbols to their stringified representations. 82317778Sdim// Demangling symbols (which is what toString() does) is slow, so 83317778Sdim// we do that in batch using parallel-for. 84327952Sdimstatic DenseMap<Symbol *, std::string> 85353358SdimgetSymbolStrings(ArrayRef<Defined *> syms) { 86353358Sdim std::vector<std::string> str(syms.size()); 87353358Sdim parallelForEachN(0, syms.size(), [&](size_t i) { 88353358Sdim raw_string_ostream os(str[i]); 89353358Sdim OutputSection *osec = syms[i]->getOutputSection(); 90353358Sdim uint64_t vma = syms[i]->getVA(); 91353358Sdim uint64_t lma = osec ? osec->getLMA() + vma - osec->getVA(0) : 0; 92353358Sdim writeHeader(os, vma, lma, syms[i]->getSize(), 1); 93353358Sdim os << indent16 << toString(*syms[i]); 94317778Sdim }); 95317025Sdim 96353358Sdim DenseMap<Symbol *, std::string> ret; 97353358Sdim for (size_t i = 0, e = syms.size(); i < e; ++i) 98353358Sdim ret[syms[i]] = std::move(str[i]); 99353358Sdim return ret; 100317025Sdim} 101317025Sdim 102341825Sdim// Print .eh_frame contents. Since the section consists of EhSectionPieces, 103341825Sdim// we need a specialized printer for that section. 104341825Sdim// 105341825Sdim// .eh_frame tend to contain a lot of section pieces that are contiguous 106341825Sdim// both in input file and output file. Such pieces are squashed before 107341825Sdim// being displayed to make output compact. 108353358Sdimstatic void printEhFrame(raw_ostream &os, const EhFrameSection *sec) { 109353358Sdim std::vector<EhSectionPiece> pieces; 110341825Sdim 111353358Sdim auto add = [&](const EhSectionPiece &p) { 112341825Sdim // If P is adjacent to Last, squash the two. 113353358Sdim if (!pieces.empty()) { 114353358Sdim EhSectionPiece &last = pieces.back(); 115353358Sdim if (last.sec == p.sec && last.inputOff + last.size == p.inputOff && 116353358Sdim last.outputOff + last.size == p.outputOff) { 117353358Sdim last.size += p.size; 118341825Sdim return; 119341825Sdim } 120341825Sdim } 121353358Sdim pieces.push_back(p); 122341825Sdim }; 123341825Sdim 124341825Sdim // Gather section pieces. 125353358Sdim for (const CieRecord *rec : sec->getCieRecords()) { 126353358Sdim add(*rec->cie); 127353358Sdim for (const EhSectionPiece *fde : rec->fdes) 128353358Sdim add(*fde); 129341825Sdim } 130341825Sdim 131341825Sdim // Print out section pieces. 132353358Sdim const OutputSection *osec = sec->getOutputSection(); 133353358Sdim for (EhSectionPiece &p : pieces) { 134353358Sdim writeHeader(os, osec->addr + p.outputOff, osec->getLMA() + p.outputOff, 135353358Sdim p.size, 1); 136353358Sdim os << indent8 << toString(p.sec->file) << ":(" << p.sec->name << "+0x" 137353358Sdim << Twine::utohexstr(p.inputOff) + ")\n"; 138341825Sdim } 139341825Sdim} 140341825Sdim 141360784Sdimvoid writeMapFile() { 142353358Sdim if (config->mapFile.empty()) 143317025Sdim return; 144317025Sdim 145317778Sdim // Open a map file for writing. 146353358Sdim std::error_code ec; 147360784Sdim raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); 148353358Sdim if (ec) { 149353358Sdim error("cannot open " + config->mapFile + ": " + ec.message()); 150317778Sdim return; 151317778Sdim } 152317778Sdim 153317778Sdim // Collect symbol info that we want to print out. 154353358Sdim std::vector<Defined *> syms = getSymbols(); 155353358Sdim SymbolMapTy sectionSyms = getSectionSyms(syms); 156353358Sdim DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms); 157317778Sdim 158317778Sdim // Print out the header line. 159353358Sdim int w = config->is64 ? 16 : 8; 160353358Sdim os << right_justify("VMA", w) << ' ' << right_justify("LMA", w) 161341825Sdim << " Size Align Out In Symbol\n"; 162317778Sdim 163353358Sdim OutputSection* osec = nullptr; 164353358Sdim for (BaseCommand *base : script->sectionCommands) { 165353358Sdim if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { 166353358Sdim if (cmd->provide && !cmd->sym) 167341825Sdim continue; 168353358Sdim uint64_t lma = osec ? osec->getLMA() + cmd->addr - osec->getVA(0) : 0; 169353358Sdim writeHeader(os, cmd->addr, lma, cmd->size, 1); 170353358Sdim os << cmd->commandString << '\n'; 171341825Sdim continue; 172341825Sdim } 173341825Sdim 174353358Sdim osec = cast<OutputSection>(base); 175353358Sdim writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment); 176353358Sdim os << osec->name << '\n'; 177317778Sdim 178317778Sdim // Dump symbols for each input section. 179353358Sdim for (BaseCommand *base : osec->sectionCommands) { 180353358Sdim if (auto *isd = dyn_cast<InputSectionDescription>(base)) { 181353358Sdim for (InputSection *isec : isd->sections) { 182353358Sdim if (auto *ehSec = dyn_cast<EhFrameSection>(isec)) { 183353358Sdim printEhFrame(os, ehSec); 184341825Sdim continue; 185341825Sdim } 186341825Sdim 187353358Sdim writeHeader(os, isec->getVA(0), osec->getLMA() + isec->getOffset(0), 188353358Sdim isec->getSize(), isec->alignment); 189353358Sdim os << indent8 << toString(isec) << '\n'; 190353358Sdim for (Symbol *sym : sectionSyms[isec]) 191353358Sdim os << symStr[sym] << '\n'; 192341825Sdim } 193319164Sdim continue; 194319164Sdim } 195341825Sdim 196353358Sdim if (auto *cmd = dyn_cast<ByteCommand>(base)) { 197353358Sdim writeHeader(os, osec->addr + cmd->offset, osec->getLMA() + cmd->offset, 198353358Sdim cmd->size, 1); 199353358Sdim os << indent8 << cmd->commandString << '\n'; 200341825Sdim continue; 201341825Sdim } 202341825Sdim 203353358Sdim if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { 204353358Sdim if (cmd->provide && !cmd->sym) 205341825Sdim continue; 206353358Sdim writeHeader(os, cmd->addr, osec->getLMA() + cmd->addr - osec->getVA(0), 207353358Sdim cmd->size, 1); 208353358Sdim os << indent8 << cmd->commandString << '\n'; 209341825Sdim continue; 210341825Sdim } 211317778Sdim } 212317778Sdim } 213317025Sdim} 214341825Sdim 215353358Sdimstatic void print(StringRef a, StringRef b) { 216360784Sdim lld::outs() << left_justify(a, 49) << " " << b << "\n"; 217341825Sdim} 218341825Sdim 219341825Sdim// Output a cross reference table to stdout. This is for --cref. 220341825Sdim// 221341825Sdim// For each global symbol, we print out a file that defines the symbol 222341825Sdim// followed by files that uses that symbol. Here is an example. 223341825Sdim// 224341825Sdim// strlen /lib/x86_64-linux-gnu/libc.so.6 225341825Sdim// tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o 226341825Sdim// lib/libLLVMSupport.a(PrettyStackTrace.cpp.o) 227341825Sdim// 228341825Sdim// In this case, strlen is defined by libc.so.6 and used by other two 229341825Sdim// files. 230360784Sdimvoid writeCrossReferenceTable() { 231353358Sdim if (!config->cref) 232341825Sdim return; 233341825Sdim 234341825Sdim // Collect symbols and files. 235353358Sdim MapVector<Symbol *, SetVector<InputFile *>> map; 236353358Sdim for (InputFile *file : objectFiles) { 237353358Sdim for (Symbol *sym : file->getSymbols()) { 238353358Sdim if (isa<SharedSymbol>(sym)) 239353358Sdim map[sym].insert(file); 240353358Sdim if (auto *d = dyn_cast<Defined>(sym)) 241353358Sdim if (!d->isLocal() && (!d->section || d->section->isLive())) 242353358Sdim map[d].insert(file); 243341825Sdim } 244341825Sdim } 245341825Sdim 246341825Sdim // Print out a header. 247360784Sdim lld::outs() << "Cross Reference Table\n\n"; 248341825Sdim print("Symbol", "File"); 249341825Sdim 250341825Sdim // Print out a table. 251353358Sdim for (auto kv : map) { 252353358Sdim Symbol *sym = kv.first; 253353358Sdim SetVector<InputFile *> &files = kv.second; 254341825Sdim 255353358Sdim print(toString(*sym), toString(sym->file)); 256353358Sdim for (InputFile *file : files) 257353358Sdim if (file != sym->file) 258353358Sdim print("", toString(file)); 259341825Sdim } 260341825Sdim} 261360784Sdim 262360784Sdim} // namespace elf 263360784Sdim} // namespace lld 264