Index: lld/ELF/MapFile.cpp =================================================================== --- lld/ELF/MapFile.cpp +++ lld/ELF/MapFile.cpp @@ -24,6 +24,8 @@ #include "MapFile.h" #include "InputFiles.h" #include "Strings.h" +#include "SymbolTable.h" +#include "Threads.h" #include "llvm/Support/raw_ostream.h" @@ -33,82 +35,125 @@ 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); -} - -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); +namespace { +template class PrettyPrinter { +public: + PrettyPrinter(); + void print(raw_ostream &OS, ArrayRef OutputSections); + +private: + void writeInputSection(raw_ostream &OS, const InputSection *IS, + StringRef &CurSection); + + // 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 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); -} +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 instead of 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(); + }); + } -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 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(3) << left_justify(toString(*Syms[I]), 7) << '\n'; + }); + for (size_t I = 0, E = Syms.size(); I < E; ++I) + SymStr[Syms[I]] = Str[I]; } template -static void writeInputSection(raw_fd_ostream &OS, const InputSection *IS, - StringRef &PrevName) { - int Width = ELFT::Is64Bits ? 16 : 8; +void PrettyPrinter::writeInputSection(raw_ostream &OS, + const InputSection *IS, + StringRef &CurSection) { + // 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 + // + // once 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 << indent(1) << left_justify(Name, 7) << '\n'; + CurSection = Name; } + // Write a line for each symbol defined 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'; - } + + writeHeader(OS, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), + IS->Alignment); + OS << indent(2) << left_justify(toString(File), 7) << '\n'; + + for (DefinedRegular *Sym : Symbols[IS]) + OS << SymStr[Sym]; } template -static void writeMapFile2(raw_fd_ostream &OS, - ArrayRef OutputSections) { - int Width = ELFT::Is64Bits ? 16 : 8; - - OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width) +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 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); - } + StringRef CurSection; + for (InputSection *IS : Sec->Sections) + writeInputSection(OS, IS, CurSection); } } @@ -122,7 +167,7 @@ if (EC) error("cannot open " + Config->MapFile + ": " + EC.message()); else - writeMapFile2(OS, OutputSections); + PrettyPrinter().print(OS, OutputSections); } 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: @@ -32,9 +32,9 @@ // CHECK-NEXT: 0000000000201000 0000000000000015 4 .text // CHECK-NEXT: 0000000000201000 000000000000000e 4 .text // CHECK-NEXT: 0000000000201000 000000000000000e 4 {{.*}}{{/|\\}}map-file.s.tmp1.o -// CHECK-NEXT: 000000000020100e 0000000000000000 0 local -// CHECK-NEXT: 0000000000201005 0000000000000000 0 f(int) // CHECK-NEXT: 0000000000201000 0000000000000000 0 _start +// CHECK-NEXT: 0000000000201005 0000000000000000 0 f(int) +// CHECK-NEXT: 000000000020100e 0000000000000000 0 local // CHECK-NEXT: 0000000000201010 0000000000000002 4 {{.*}}{{/|\\}}map-file.s.tmp2.o // CHECK-NEXT: 0000000000201010 0000000000000000 0 foo // CHECK-NEXT: 0000000000201011 0000000000000000 0 bar