Index: lld/ELF/MapFile.cpp =================================================================== --- lld/ELF/MapFile.cpp +++ lld/ELF/MapFile.cpp @@ -24,6 +24,7 @@ #include "MapFile.h" #include "InputFiles.h" #include "Strings.h" +#include "Threads.h" #include "llvm/Support/raw_ostream.h" @@ -33,82 +34,145 @@ using namespace lld; using namespace lld::elf; -static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, uint64_t Align, StringRef Name) { - OS << format("%0*llx %0*llx %5lld ", Width, Address, Width, Size, Align) - << left_justify(Name, 7); +namespace { +template class PrettyPrinter { +public: + PrettyPrinter(ArrayRef OutputSections); + void print(raw_ostream &OS); + +private: + void writeInputSection(raw_ostream &OS, const InputSection *IS); + + // All output sections. + ArrayRef OutputSections; + + // Maps sections to their symbols. + DenseMap> Symbols; + + // Contains a string like this + // + // 0020100e 00000000 0 f(int) + // + // for each symbol. Since constructing strings containing demangled + // symbols is slow, we create this map in batch using multiple + // threads. + DenseMap SymStr; + + // Current input section name. We want to print out a line like + // + // Address Size Align Out In File Symbol + // ================================================================= + // 00201000 00000015 4 .text + // 00201000 0000000e 4 .text <----- THIS + // 00201000 0000000e 4 test.o + // + // only once for each input section. + StringRef CurSection; +}; +} // 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 void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, uint64_t Align, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeOutSecLine(OS, Width, Address, Size, Align, ""); - OS << ' ' << left_justify(Name, 7); +// Returns all symbols that we want to print out. +template +static std::vector getSymbols(ArrayRef V) { + DenseSet *> Files; + for (OutputSection *OSec : V) + for (InputSection *ISec : OSec->Sections) + if (elf::ObjectFile *File = ISec->template getFile()) + Files.insert(File); + + std::vector Ret; + for (elf::ObjectFile *File : Files) + for (SymbolBody *B : File->getSymbols()) + if (B->File == File && !B->isSection()) + if (auto *Sym = dyn_cast(B)) + if (Sym->Section) + Ret.push_back(Sym); + return Ret; } -static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, uint64_t Align, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeInSecLine(OS, Width, Address, Size, Align, ""); - OS << ' ' << left_justify(Name, 7); +// Returns a map from sections to their symbols. +template +static DenseMap> +groupSymbols(ArrayRef V) { + DenseMap> Map; + for (DefinedRegular *Sym : getSymbols(V)) + Map[Sym->Section].push_back(Sym); + return Map; } -static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeFileLine(OS, Width, Address, Size, 0, ""); - OS << ' ' << left_justify(Name, 7); +// Construct a map from symbols to their stringified representation. +// Demangling symbols is slow, so we use multi-threads in this function. +template +static DenseMap +formatSymbols(ArrayRef V) { + std::vector Syms = getSymbols(V); + + std::vector Res(Syms.size()); + parallelFor(0, Syms.size(), [&](size_t I) { + raw_string_ostream OS(Res[I]); + writeHeader(OS, Syms[I]->getVA(), Syms[I]->getSize(), 0); + OS << " " + << left_justify(toString(*Syms[I]), 7) << '\n'; + }); + + DenseMap Map; + for (size_t I = 0, E = Syms.size(); I < E; ++I) + Map[Syms[I]] = Res[I]; + return Map; } template -static void writeInputSection(raw_fd_ostream &OS, const InputSection *IS, - StringRef &PrevName) { - int Width = ELFT::Is64Bits ? 16 : 8; +PrettyPrinter::PrettyPrinter(ArrayRef V) + : OutputSections(V), Symbols(groupSymbols(V)), + SymStr(formatSymbols(V)) {} + +template +void PrettyPrinter::writeInputSection(raw_ostream &OS, + const InputSection *IS) { + // Write an input section header line for each new input section. StringRef Name = IS->Name; - if (Name != PrevName) { - writeInSecLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment, Name); - OS << '\n'; - PrevName = Name; + if (Name != CurSection) { + writeHeader(OS, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), + IS->Alignment); + OS << " " << left_justify(Name, 7) << '\n'; + CurSection = Name; } + // Write a line for each symbol in the given section. elf::ObjectFile *File = IS->template getFile(); if (!File) return; - writeFileLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment, toString(File)); - OS << '\n'; - - for (SymbolBody *Sym : File->getSymbols()) { - auto *DR = dyn_cast(Sym); - if (!DR) - continue; - if (DR->Section != IS) - continue; - if (DR->isSection()) - continue; - writeSymbolLine(OS, Width, Sym->getVA(), Sym->getSize(), - toString(*Sym)); - OS << '\n'; - } -} -template -static void writeMapFile2(raw_fd_ostream &OS, - ArrayRef OutputSections) { - int Width = ELFT::Is64Bits ? 16 : 8; + writeHeader(OS, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), + IS->Alignment); + OS << " " << left_justify(toString(File), 7) << '\n'; + + for (SymbolBody *B : Symbols[IS]) + OS << SymStr[B]; +} - OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width) +template void PrettyPrinter::print(raw_ostream &OS) { + // Print out the header line. + int W = ELFT::Is64Bits ? 16 : 8; + OS << left_justify("Address", W) << ' ' << left_justify("Size", W) << " Align Out In File Symbol\n"; + // Print out a mapfile. for (OutputSection *Sec : OutputSections) { - writeOutSecLine(OS, Width, Sec->Addr, Sec->Size, Sec->Alignment, Sec->Name); - OS << '\n'; + writeHeader(OS, Sec->Addr, Sec->Size, Sec->Alignment); + OS << left_justify(Sec->Name, 7) << '\n'; - StringRef PrevName = ""; - for (InputSection *IS : Sec->Sections) { - writeInputSection(OS, IS, PrevName); - } + CurSection = ""; + for (InputSection *IS : Sec->Sections) + writeInputSection(OS, IS); } } @@ -122,7 +186,7 @@ if (EC) error("cannot open " + Config->MapFile + ": " + EC.message()); else - writeMapFile2(OS, OutputSections); + PrettyPrinter(OutputSections).print(OS); } template void elf::writeMapFile(ArrayRef); Index: lld/test/ELF/map-file.s =================================================================== --- lld/test/ELF/map-file.s +++ lld/test/ELF/map-file.s @@ -6,10 +6,10 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file4.s -o %t4.o // RUN: rm -f %t4.a // RUN: llvm-ar rc %t4.a %t4.o -// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -M | FileCheck %s -// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -print-map | FileCheck %s +// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -M | FileCheck -strict-whitespace %s +// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -print-map | FileCheck -strict-whitespace %s // RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -Map=%t.map -// RUN: FileCheck %s < %t.map +// RUN: FileCheck -strict-whitespace %s < %t.map .global _start _start: