//===- MapFile.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the -Map option. It shows lists in order and // hierarchically the output sections, input sections, input files and // symbol: // // Address Size Align Out In Symbol // 00201000 00000015 4 .text // 00201000 0000000e 4 test.o:.text // 0020100e 00000000 0 local // 00201005 00000000 0 f(int) // //===----------------------------------------------------------------------===// #include "MapFile.h" #include "InputFiles.h" #include "Strings.h" #include "SymbolTable.h" #include "Threads.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::object; using namespace lld; using namespace lld::elf; namespace { template class PrettyPrinter { public: PrettyPrinter(); void print(raw_ostream &OS, ArrayRef OutputSections); private: void writeInputSection(raw_ostream &OS, const InputSection *IS); // Maps sections to their symbols. DenseMap> Symbols; // Contains a string like this // // 0020100e 00000000 0 f(int) // // for each symbol. DenseMap SymStr; }; } // namespace // Print out the first three columns of a line. template static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, uint64_t Align) { int W = ELFT::Is64Bits ? 16 : 8; OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align); } static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } template PrettyPrinter::PrettyPrinter() { // Collect all symbols that we want to print out. std::vector Syms; for (elf::ObjectFile *File : Symtab::X->getObjectFiles()) for (SymbolBody *B : File->getSymbols()) if (B->File == File && !B->isSection()) if (auto *Sym = dyn_cast(B)) if (Sym->Section) Syms.push_back(Sym); // Initialize the map from sections to their symbols. for (DefinedRegular *Sym : Syms) Symbols[Sym->Section].push_back(Sym); // Sort symbols by address. We want to print out symbols in the // order in the output file rather than the order they appeared // in the input files. for (auto &It : Symbols) { SmallVectorImpl &V = It.second; std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { return A->getVA() < B->getVA(); }); } // Construct a map from symbols to their stringified representations. // Demangling symbols is slow, so we use the parallel-for. std::vector Str(Syms.size()); parallelFor(0, Syms.size(), [&](size_t I) { raw_string_ostream OS(Str[I]); writeHeader(OS, Syms[I]->getVA(), Syms[I]->template getSize(), 0); OS << indent(2) << toString(*Syms[I]) << '\n'; }); for (size_t I = 0, E = Syms.size(); I < E; ++I) SymStr[Syms[I]] = std::move(Str[I]); } template void PrettyPrinter::writeInputSection(raw_ostream &OS, const InputSection *IS) { // Write a line for each symbol defined in the given section. writeHeader(OS, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), IS->Alignment); OS << indent(1) << toString(IS) << '\n'; for (DefinedRegular *Sym : Symbols[IS]) OS << SymStr[Sym]; } template void PrettyPrinter::print(raw_ostream &OS, ArrayRef OutputSections) { // Print out the header line. int W = ELFT::Is64Bits ? 16 : 8; OS << left_justify("Address", W) << ' ' << left_justify("Size", W) << " Align Out In Symbol\n"; // Print out a mapfile. for (OutputSection *Sec : OutputSections) { writeHeader(OS, Sec->Addr, Sec->Size, Sec->Alignment); OS << Sec->Name << '\n'; for (InputSection *IS : Sec->Sections) writeInputSection(OS, IS); } } template void elf::writeMapFile(ArrayRef OutputSections) { if (Config->MapFile.empty()) return; std::error_code EC; raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); if (EC) error("cannot open " + Config->MapFile + ": " + EC.message()); else PrettyPrinter().print(OS, OutputSections); } template void elf::writeMapFile(ArrayRef); template void elf::writeMapFile(ArrayRef); template void elf::writeMapFile(ArrayRef); template void elf::writeMapFile(ArrayRef);