1*fe6060f1SDimitry Andric //===- MapFile.cpp --------------------------------------------------------===// 2*fe6060f1SDimitry Andric // 3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*fe6060f1SDimitry Andric // 7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8*fe6060f1SDimitry Andric // 9*fe6060f1SDimitry Andric // This file implements the -map option. It shows lists in order and 10*fe6060f1SDimitry Andric // hierarchically the outputFile, arch, input files, output sections and 11*fe6060f1SDimitry Andric // symbol: 12*fe6060f1SDimitry Andric // 13*fe6060f1SDimitry Andric // # Path: test 14*fe6060f1SDimitry Andric // # Arch: x86_84 15*fe6060f1SDimitry Andric // # Object files: 16*fe6060f1SDimitry Andric // [ 0] linker synthesized 17*fe6060f1SDimitry Andric // [ 1] a.o 18*fe6060f1SDimitry Andric // # Sections: 19*fe6060f1SDimitry Andric // # Address Size Segment Section 20*fe6060f1SDimitry Andric // 0x1000005C0 0x0000004C __TEXT __text 21*fe6060f1SDimitry Andric // # Symbols: 22*fe6060f1SDimitry Andric // # Address File Name 23*fe6060f1SDimitry Andric // 0x1000005C0 [ 1] _main 24*fe6060f1SDimitry Andric // 25*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 26*fe6060f1SDimitry Andric 27*fe6060f1SDimitry Andric #include "MapFile.h" 28*fe6060f1SDimitry Andric #include "Config.h" 29*fe6060f1SDimitry Andric #include "InputFiles.h" 30*fe6060f1SDimitry Andric #include "InputSection.h" 31*fe6060f1SDimitry Andric #include "OutputSection.h" 32*fe6060f1SDimitry Andric #include "OutputSegment.h" 33*fe6060f1SDimitry Andric #include "Symbols.h" 34*fe6060f1SDimitry Andric #include "Target.h" 35*fe6060f1SDimitry Andric #include "llvm/Support/Parallel.h" 36*fe6060f1SDimitry Andric #include "llvm/Support/TimeProfiler.h" 37*fe6060f1SDimitry Andric 38*fe6060f1SDimitry Andric using namespace llvm; 39*fe6060f1SDimitry Andric using namespace llvm::sys; 40*fe6060f1SDimitry Andric using namespace lld; 41*fe6060f1SDimitry Andric using namespace lld::macho; 42*fe6060f1SDimitry Andric 43*fe6060f1SDimitry Andric using SymbolMapTy = DenseMap<const InputSection *, SmallVector<Defined *, 4>>; 44*fe6060f1SDimitry Andric 45*fe6060f1SDimitry Andric // Returns a map from sections to their symbols. 46*fe6060f1SDimitry Andric static SymbolMapTy getSectionSyms(ArrayRef<Defined *> syms) { 47*fe6060f1SDimitry Andric SymbolMapTy ret; 48*fe6060f1SDimitry Andric for (Defined *dr : syms) 49*fe6060f1SDimitry Andric ret[dr->isec].push_back(dr); 50*fe6060f1SDimitry Andric 51*fe6060f1SDimitry Andric // Sort symbols by address. We want to print out symbols in the order they 52*fe6060f1SDimitry Andric // appear in the output file rather than the order they appeared in the input 53*fe6060f1SDimitry Andric // files. 54*fe6060f1SDimitry Andric for (auto &it : ret) 55*fe6060f1SDimitry Andric parallelSort( 56*fe6060f1SDimitry Andric it.second.begin(), it.second.end(), [](Defined *a, Defined *b) { 57*fe6060f1SDimitry Andric return a->getVA() != b->getVA() ? a->getVA() < b->getVA() 58*fe6060f1SDimitry Andric : a->getName() < b->getName(); 59*fe6060f1SDimitry Andric }); 60*fe6060f1SDimitry Andric return ret; 61*fe6060f1SDimitry Andric } 62*fe6060f1SDimitry Andric 63*fe6060f1SDimitry Andric // Returns a list of all symbols that we want to print out. 64*fe6060f1SDimitry Andric static std::vector<Defined *> getSymbols() { 65*fe6060f1SDimitry Andric std::vector<Defined *> v; 66*fe6060f1SDimitry Andric for (InputFile *file : inputFiles) 67*fe6060f1SDimitry Andric if (isa<ObjFile>(file)) 68*fe6060f1SDimitry Andric for (Symbol *sym : file->symbols) 69*fe6060f1SDimitry Andric if (auto *d = dyn_cast_or_null<Defined>(sym)) 70*fe6060f1SDimitry Andric if (d->isLive() && d->isec && d->getFile() == file) { 71*fe6060f1SDimitry Andric assert(!shouldOmitFromOutput(d->isec)); 72*fe6060f1SDimitry Andric v.push_back(d); 73*fe6060f1SDimitry Andric } 74*fe6060f1SDimitry Andric return v; 75*fe6060f1SDimitry Andric } 76*fe6060f1SDimitry Andric 77*fe6060f1SDimitry Andric // Construct a map from symbols to their stringified representations. 78*fe6060f1SDimitry Andric // Demangling symbols (which is what toString() does) is slow, so 79*fe6060f1SDimitry Andric // we do that in batch using parallel-for. 80*fe6060f1SDimitry Andric static DenseMap<Symbol *, std::string> 81*fe6060f1SDimitry Andric getSymbolStrings(ArrayRef<Defined *> syms) { 82*fe6060f1SDimitry Andric std::vector<std::string> str(syms.size()); 83*fe6060f1SDimitry Andric parallelForEachN(0, syms.size(), [&](size_t i) { 84*fe6060f1SDimitry Andric raw_string_ostream os(str[i]); 85*fe6060f1SDimitry Andric os << toString(*syms[i]); 86*fe6060f1SDimitry Andric }); 87*fe6060f1SDimitry Andric 88*fe6060f1SDimitry Andric DenseMap<Symbol *, std::string> ret; 89*fe6060f1SDimitry Andric for (size_t i = 0, e = syms.size(); i < e; ++i) 90*fe6060f1SDimitry Andric ret[syms[i]] = std::move(str[i]); 91*fe6060f1SDimitry Andric return ret; 92*fe6060f1SDimitry Andric } 93*fe6060f1SDimitry Andric 94*fe6060f1SDimitry Andric void macho::writeMapFile() { 95*fe6060f1SDimitry Andric if (config->mapFile.empty()) 96*fe6060f1SDimitry Andric return; 97*fe6060f1SDimitry Andric 98*fe6060f1SDimitry Andric TimeTraceScope timeScope("Write map file"); 99*fe6060f1SDimitry Andric 100*fe6060f1SDimitry Andric // Open a map file for writing. 101*fe6060f1SDimitry Andric std::error_code ec; 102*fe6060f1SDimitry Andric raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); 103*fe6060f1SDimitry Andric if (ec) { 104*fe6060f1SDimitry Andric error("cannot open " + config->mapFile + ": " + ec.message()); 105*fe6060f1SDimitry Andric return; 106*fe6060f1SDimitry Andric } 107*fe6060f1SDimitry Andric 108*fe6060f1SDimitry Andric // Dump output path. 109*fe6060f1SDimitry Andric os << format("# Path: %s\n", config->outputFile.str().c_str()); 110*fe6060f1SDimitry Andric 111*fe6060f1SDimitry Andric // Dump output architecture. 112*fe6060f1SDimitry Andric os << format("# Arch: %s\n", 113*fe6060f1SDimitry Andric getArchitectureName(config->arch()).str().c_str()); 114*fe6060f1SDimitry Andric 115*fe6060f1SDimitry Andric // Dump table of object files. 116*fe6060f1SDimitry Andric os << "# Object files:\n"; 117*fe6060f1SDimitry Andric os << format("[%3u] %s\n", 0, (const char *)"linker synthesized"); 118*fe6060f1SDimitry Andric uint32_t fileIndex = 1; 119*fe6060f1SDimitry Andric DenseMap<lld::macho::InputFile *, uint32_t> readerToFileOrdinal; 120*fe6060f1SDimitry Andric for (InputFile *file : inputFiles) { 121*fe6060f1SDimitry Andric if (isa<ObjFile>(file)) { 122*fe6060f1SDimitry Andric os << format("[%3u] %s\n", fileIndex, file->getName().str().c_str()); 123*fe6060f1SDimitry Andric readerToFileOrdinal[file] = fileIndex++; 124*fe6060f1SDimitry Andric } 125*fe6060f1SDimitry Andric } 126*fe6060f1SDimitry Andric 127*fe6060f1SDimitry Andric // Collect symbol info that we want to print out. 128*fe6060f1SDimitry Andric std::vector<Defined *> syms = getSymbols(); 129*fe6060f1SDimitry Andric SymbolMapTy sectionSyms = getSectionSyms(syms); 130*fe6060f1SDimitry Andric DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms); 131*fe6060f1SDimitry Andric 132*fe6060f1SDimitry Andric // Dump table of sections 133*fe6060f1SDimitry Andric os << "# Sections:\n"; 134*fe6060f1SDimitry Andric os << "# Address\tSize \tSegment\tSection\n"; 135*fe6060f1SDimitry Andric for (OutputSegment *seg : outputSegments) 136*fe6060f1SDimitry Andric for (OutputSection *osec : seg->getSections()) { 137*fe6060f1SDimitry Andric if (osec->isHidden()) 138*fe6060f1SDimitry Andric continue; 139*fe6060f1SDimitry Andric 140*fe6060f1SDimitry Andric os << format("0x%08llX\t0x%08llX\t%s\t%s\n", osec->addr, osec->getSize(), 141*fe6060f1SDimitry Andric seg->name.str().c_str(), osec->name.str().c_str()); 142*fe6060f1SDimitry Andric } 143*fe6060f1SDimitry Andric 144*fe6060f1SDimitry Andric // Dump table of symbols 145*fe6060f1SDimitry Andric os << "# Symbols:\n"; 146*fe6060f1SDimitry Andric os << "# Address\t File Name\n"; 147*fe6060f1SDimitry Andric for (InputSection *isec : inputSections) { 148*fe6060f1SDimitry Andric auto symsIt = sectionSyms.find(isec); 149*fe6060f1SDimitry Andric assert(!shouldOmitFromOutput(isec) || (symsIt == sectionSyms.end())); 150*fe6060f1SDimitry Andric if (symsIt == sectionSyms.end()) 151*fe6060f1SDimitry Andric continue; 152*fe6060f1SDimitry Andric for (Symbol *sym : symsIt->second) { 153*fe6060f1SDimitry Andric os << format("0x%08llX\t[%3u] %s\n", sym->getVA(), 154*fe6060f1SDimitry Andric readerToFileOrdinal[sym->getFile()], symStr[sym].c_str()); 155*fe6060f1SDimitry Andric } 156*fe6060f1SDimitry Andric } 157*fe6060f1SDimitry Andric 158*fe6060f1SDimitry Andric // TODO: when we implement -dead_strip, we should dump dead stripped symbols 159*fe6060f1SDimitry Andric } 160