1fe6060f1SDimitry Andric //===- MapFile.cpp --------------------------------------------------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This file implements the -map option. It shows lists in order and 10fe6060f1SDimitry Andric // hierarchically the outputFile, arch, input files, output sections and 11fe6060f1SDimitry Andric // symbol: 12fe6060f1SDimitry Andric // 13fe6060f1SDimitry Andric // # Path: test 14fe6060f1SDimitry Andric // # Arch: x86_84 15fe6060f1SDimitry Andric // # Object files: 16fe6060f1SDimitry Andric // [ 0] linker synthesized 17fe6060f1SDimitry Andric // [ 1] a.o 18fe6060f1SDimitry Andric // # Sections: 19fe6060f1SDimitry Andric // # Address Size Segment Section 20fe6060f1SDimitry Andric // 0x1000005C0 0x0000004C __TEXT __text 21fe6060f1SDimitry Andric // # Symbols: 22fe6060f1SDimitry Andric // # Address File Name 23fe6060f1SDimitry Andric // 0x1000005C0 [ 1] _main 24fe6060f1SDimitry Andric // 25fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 26fe6060f1SDimitry Andric 27fe6060f1SDimitry Andric #include "MapFile.h" 28fe6060f1SDimitry Andric #include "Config.h" 29fe6060f1SDimitry Andric #include "InputFiles.h" 30fe6060f1SDimitry Andric #include "InputSection.h" 31fe6060f1SDimitry Andric #include "OutputSection.h" 32fe6060f1SDimitry Andric #include "OutputSegment.h" 33fe6060f1SDimitry Andric #include "Symbols.h" 34*81ad6265SDimitry Andric #include "SyntheticSections.h" 35fe6060f1SDimitry Andric #include "Target.h" 36fe6060f1SDimitry Andric #include "llvm/Support/Parallel.h" 37fe6060f1SDimitry Andric #include "llvm/Support/TimeProfiler.h" 38fe6060f1SDimitry Andric 39fe6060f1SDimitry Andric using namespace llvm; 40fe6060f1SDimitry Andric using namespace llvm::sys; 41fe6060f1SDimitry Andric using namespace lld; 42fe6060f1SDimitry Andric using namespace lld::macho; 43fe6060f1SDimitry Andric 441fd87a68SDimitry Andric using Symbols = std::vector<Defined *>; 451fd87a68SDimitry Andric // Returns a pair where the left element is a container of all live Symbols and 461fd87a68SDimitry Andric // the right element is a container of all dead symbols. 471fd87a68SDimitry Andric static std::pair<Symbols, Symbols> getSymbols() { 481fd87a68SDimitry Andric Symbols liveSymbols, deadSymbols; 49fe6060f1SDimitry Andric for (InputFile *file : inputFiles) 50fe6060f1SDimitry Andric if (isa<ObjFile>(file)) 51fe6060f1SDimitry Andric for (Symbol *sym : file->symbols) 52fe6060f1SDimitry Andric if (auto *d = dyn_cast_or_null<Defined>(sym)) 531fd87a68SDimitry Andric if (d->isec && d->getFile() == file) { 541fd87a68SDimitry Andric if (d->isLive()) { 55fe6060f1SDimitry Andric assert(!shouldOmitFromOutput(d->isec)); 561fd87a68SDimitry Andric liveSymbols.push_back(d); 571fd87a68SDimitry Andric } else { 581fd87a68SDimitry Andric deadSymbols.push_back(d); 59fe6060f1SDimitry Andric } 601fd87a68SDimitry Andric } 611fd87a68SDimitry Andric parallelSort(liveSymbols.begin(), liveSymbols.end(), 621fd87a68SDimitry Andric [](Defined *a, Defined *b) { 631fd87a68SDimitry Andric return a->getVA() != b->getVA() ? a->getVA() < b->getVA() 641fd87a68SDimitry Andric : a->getName() < b->getName(); 651fd87a68SDimitry Andric }); 661fd87a68SDimitry Andric parallelSort( 671fd87a68SDimitry Andric deadSymbols.begin(), deadSymbols.end(), 681fd87a68SDimitry Andric [](Defined *a, Defined *b) { return a->getName() < b->getName(); }); 691fd87a68SDimitry Andric return {std::move(liveSymbols), std::move(deadSymbols)}; 70fe6060f1SDimitry Andric } 71fe6060f1SDimitry Andric 72fe6060f1SDimitry Andric // Construct a map from symbols to their stringified representations. 73fe6060f1SDimitry Andric // Demangling symbols (which is what toString() does) is slow, so 74fe6060f1SDimitry Andric // we do that in batch using parallel-for. 75fe6060f1SDimitry Andric static DenseMap<Symbol *, std::string> 76fe6060f1SDimitry Andric getSymbolStrings(ArrayRef<Defined *> syms) { 77fe6060f1SDimitry Andric std::vector<std::string> str(syms.size()); 78*81ad6265SDimitry Andric parallelFor(0, syms.size(), [&](size_t i) { 79fe6060f1SDimitry Andric raw_string_ostream os(str[i]); 80*81ad6265SDimitry Andric Defined *sym = syms[i]; 81*81ad6265SDimitry Andric 82*81ad6265SDimitry Andric switch (sym->isec->kind()) { 83*81ad6265SDimitry Andric case InputSection::CStringLiteralKind: { 84*81ad6265SDimitry Andric // Output "literal string: <string literal>" 85*81ad6265SDimitry Andric const auto *isec = cast<CStringInputSection>(sym->isec); 86*81ad6265SDimitry Andric const StringPiece &piece = isec->getStringPiece(sym->value); 87*81ad6265SDimitry Andric assert( 88*81ad6265SDimitry Andric sym->value == piece.inSecOff && 89*81ad6265SDimitry Andric "We expect symbols to always point to the start of a StringPiece."); 90*81ad6265SDimitry Andric StringRef str = isec->getStringRef(&piece - &(*isec->pieces.begin())); 91*81ad6265SDimitry Andric assert(str.back() == '\000'); 92*81ad6265SDimitry Andric (os << "literal string: ") 93*81ad6265SDimitry Andric // Remove null sequence at the end 94*81ad6265SDimitry Andric .write_escaped(str.substr(0, str.size() - 1)); 95*81ad6265SDimitry Andric break; 96*81ad6265SDimitry Andric } 97*81ad6265SDimitry Andric case InputSection::ConcatKind: 98*81ad6265SDimitry Andric case InputSection::WordLiteralKind: 99*81ad6265SDimitry Andric os << toString(*sym); 100*81ad6265SDimitry Andric } 101fe6060f1SDimitry Andric }); 102fe6060f1SDimitry Andric 103fe6060f1SDimitry Andric DenseMap<Symbol *, std::string> ret; 104fe6060f1SDimitry Andric for (size_t i = 0, e = syms.size(); i < e; ++i) 105fe6060f1SDimitry Andric ret[syms[i]] = std::move(str[i]); 106fe6060f1SDimitry Andric return ret; 107fe6060f1SDimitry Andric } 108fe6060f1SDimitry Andric 109fe6060f1SDimitry Andric void macho::writeMapFile() { 110fe6060f1SDimitry Andric if (config->mapFile.empty()) 111fe6060f1SDimitry Andric return; 112fe6060f1SDimitry Andric 113fe6060f1SDimitry Andric TimeTraceScope timeScope("Write map file"); 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric // Open a map file for writing. 116fe6060f1SDimitry Andric std::error_code ec; 117fe6060f1SDimitry Andric raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); 118fe6060f1SDimitry Andric if (ec) { 119fe6060f1SDimitry Andric error("cannot open " + config->mapFile + ": " + ec.message()); 120fe6060f1SDimitry Andric return; 121fe6060f1SDimitry Andric } 122fe6060f1SDimitry Andric 123fe6060f1SDimitry Andric // Dump output path. 124fe6060f1SDimitry Andric os << format("# Path: %s\n", config->outputFile.str().c_str()); 125fe6060f1SDimitry Andric 126fe6060f1SDimitry Andric // Dump output architecture. 127fe6060f1SDimitry Andric os << format("# Arch: %s\n", 128fe6060f1SDimitry Andric getArchitectureName(config->arch()).str().c_str()); 129fe6060f1SDimitry Andric 130fe6060f1SDimitry Andric // Dump table of object files. 131fe6060f1SDimitry Andric os << "# Object files:\n"; 132fe6060f1SDimitry Andric os << format("[%3u] %s\n", 0, (const char *)"linker synthesized"); 133fe6060f1SDimitry Andric uint32_t fileIndex = 1; 134fe6060f1SDimitry Andric DenseMap<lld::macho::InputFile *, uint32_t> readerToFileOrdinal; 135fe6060f1SDimitry Andric for (InputFile *file : inputFiles) { 136fe6060f1SDimitry Andric if (isa<ObjFile>(file)) { 137fe6060f1SDimitry Andric os << format("[%3u] %s\n", fileIndex, file->getName().str().c_str()); 138fe6060f1SDimitry Andric readerToFileOrdinal[file] = fileIndex++; 139fe6060f1SDimitry Andric } 140fe6060f1SDimitry Andric } 141fe6060f1SDimitry Andric 142fe6060f1SDimitry Andric // Dump table of sections 143fe6060f1SDimitry Andric os << "# Sections:\n"; 144fe6060f1SDimitry Andric os << "# Address\tSize \tSegment\tSection\n"; 145fe6060f1SDimitry Andric for (OutputSegment *seg : outputSegments) 146fe6060f1SDimitry Andric for (OutputSection *osec : seg->getSections()) { 147fe6060f1SDimitry Andric if (osec->isHidden()) 148fe6060f1SDimitry Andric continue; 149fe6060f1SDimitry Andric 150fe6060f1SDimitry Andric os << format("0x%08llX\t0x%08llX\t%s\t%s\n", osec->addr, osec->getSize(), 151fe6060f1SDimitry Andric seg->name.str().c_str(), osec->name.str().c_str()); 152fe6060f1SDimitry Andric } 153fe6060f1SDimitry Andric 154fe6060f1SDimitry Andric // Dump table of symbols 1551fd87a68SDimitry Andric Symbols liveSymbols, deadSymbols; 1561fd87a68SDimitry Andric std::tie(liveSymbols, deadSymbols) = getSymbols(); 1571fd87a68SDimitry Andric 1581fd87a68SDimitry Andric DenseMap<Symbol *, std::string> liveSymbolStrings = 1591fd87a68SDimitry Andric getSymbolStrings(liveSymbols); 160fe6060f1SDimitry Andric os << "# Symbols:\n"; 161fe6060f1SDimitry Andric os << "# Address\t File Name\n"; 1621fd87a68SDimitry Andric for (Symbol *sym : liveSymbols) { 1631fd87a68SDimitry Andric assert(sym->isLive()); 164fe6060f1SDimitry Andric os << format("0x%08llX\t[%3u] %s\n", sym->getVA(), 1651fd87a68SDimitry Andric readerToFileOrdinal[sym->getFile()], 1661fd87a68SDimitry Andric liveSymbolStrings[sym].c_str()); 167fe6060f1SDimitry Andric } 168fe6060f1SDimitry Andric 1691fd87a68SDimitry Andric if (config->deadStrip) { 1701fd87a68SDimitry Andric DenseMap<Symbol *, std::string> deadSymbolStrings = 1711fd87a68SDimitry Andric getSymbolStrings(deadSymbols); 1721fd87a68SDimitry Andric os << "# Dead Stripped Symbols:\n"; 1731fd87a68SDimitry Andric os << "# Address\t File Name\n"; 1741fd87a68SDimitry Andric for (Symbol *sym : deadSymbols) { 1751fd87a68SDimitry Andric assert(!sym->isLive()); 1761fd87a68SDimitry Andric os << format("<<dead>>\t[%3u] %s\n", readerToFileOrdinal[sym->getFile()], 1771fd87a68SDimitry Andric deadSymbolStrings[sym].c_str()); 1781fd87a68SDimitry Andric } 1791fd87a68SDimitry Andric } 180fe6060f1SDimitry Andric } 181