1cc2da555SSam Clegg //===- MapFile.cpp --------------------------------------------------------===// 2cc2da555SSam Clegg // 3cc2da555SSam Clegg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4cc2da555SSam Clegg // See https://llvm.org/LICENSE.txt for license information. 5cc2da555SSam Clegg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6cc2da555SSam Clegg // 7cc2da555SSam Clegg //===----------------------------------------------------------------------===// 8cc2da555SSam Clegg // 9cc2da555SSam Clegg // This file implements the -Map option. It shows lists in order and 10cc2da555SSam Clegg // hierarchically the output sections, input sections, input files and 11cc2da555SSam Clegg // symbol: 12cc2da555SSam Clegg // 13cc2da555SSam Clegg // Addr Off Size Out In Symbol 14cc2da555SSam Clegg // - 00000015 10 .text 15cc2da555SSam Clegg // - 0000000e 10 test.o:(.text) 16cc2da555SSam Clegg // - 00000000 5 local 17cc2da555SSam Clegg // - 00000000 5 f(int) 18cc2da555SSam Clegg // 19cc2da555SSam Clegg //===----------------------------------------------------------------------===// 20cc2da555SSam Clegg 21cc2da555SSam Clegg #include "MapFile.h" 22a56e5749SAndy Wingo #include "InputElement.h" 23cc2da555SSam Clegg #include "InputFiles.h" 24cc2da555SSam Clegg #include "OutputSections.h" 25cc2da555SSam Clegg #include "OutputSegment.h" 26cc2da555SSam Clegg #include "SymbolTable.h" 27cc2da555SSam Clegg #include "Symbols.h" 28cc2da555SSam Clegg #include "SyntheticSections.h" 29cc2da555SSam Clegg #include "lld/Common/Strings.h" 30cc2da555SSam Clegg #include "llvm/ADT/MapVector.h" 31cc2da555SSam Clegg #include "llvm/Support/Parallel.h" 32cc2da555SSam Clegg #include "llvm/Support/raw_ostream.h" 33cc2da555SSam Clegg 34cc2da555SSam Clegg using namespace llvm; 35cc2da555SSam Clegg using namespace llvm::object; 36cc2da555SSam Clegg using namespace lld; 37cc2da555SSam Clegg using namespace lld::wasm; 38cc2da555SSam Clegg 39cc2da555SSam Clegg using SymbolMapTy = DenseMap<const InputChunk *, SmallVector<Symbol *, 4>>; 40cc2da555SSam Clegg 41cc2da555SSam Clegg // Print out the first three columns of a line. 42cc2da555SSam Clegg static void writeHeader(raw_ostream &os, int64_t vma, uint64_t lma, 43cc2da555SSam Clegg uint64_t size) { 44cc2da555SSam Clegg // Not all entries in the map has a virtual memory address (e.g. functions) 45cc2da555SSam Clegg if (vma == -1) 46cc2da555SSam Clegg os << format(" - %8llx %8llx ", lma, size); 47cc2da555SSam Clegg else 48cc2da555SSam Clegg os << format("%8llx %8llx %8llx ", vma, lma, size); 49cc2da555SSam Clegg } 50cc2da555SSam Clegg 51cc2da555SSam Clegg // Returns a list of all symbols that we want to print out. 52cc2da555SSam Clegg static std::vector<Symbol *> getSymbols() { 53cc2da555SSam Clegg std::vector<Symbol *> v; 543c584570SSam Clegg for (InputFile *file : ctx.objectFiles) 55cc2da555SSam Clegg for (Symbol *b : file->getSymbols()) 56cc2da555SSam Clegg if (auto *dr = dyn_cast<Symbol>(b)) 57cc2da555SSam Clegg if ((!isa<SectionSymbol>(dr)) && dr->isLive() && 58cc2da555SSam Clegg (dr->getFile() == file)) 59cc2da555SSam Clegg v.push_back(dr); 60cc2da555SSam Clegg return v; 61cc2da555SSam Clegg } 62cc2da555SSam Clegg 63cc2da555SSam Clegg // Returns a map from sections to their symbols. 64cc2da555SSam Clegg static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> syms) { 65cc2da555SSam Clegg SymbolMapTy ret; 66cc2da555SSam Clegg for (Symbol *dr : syms) 67cc2da555SSam Clegg ret[dr->getChunk()].push_back(dr); 68cc2da555SSam Clegg return ret; 69cc2da555SSam Clegg } 70cc2da555SSam Clegg 71cc2da555SSam Clegg // Construct a map from symbols to their stringified representations. 72cc2da555SSam Clegg // Demangling symbols (which is what toString() does) is slow, so 73cc2da555SSam Clegg // we do that in batch using parallel-for. 74cc2da555SSam Clegg static DenseMap<Symbol *, std::string> 75cc2da555SSam Clegg getSymbolStrings(ArrayRef<Symbol *> syms) { 76cc2da555SSam Clegg std::vector<std::string> str(syms.size()); 777effcbdaSNico Weber parallelFor(0, syms.size(), [&](size_t i) { 78cc2da555SSam Clegg raw_string_ostream os(str[i]); 79067f0055SThomas Lively auto *chunk = syms[i]->getChunk(); 80067f0055SThomas Lively if (chunk == nullptr) 81067f0055SThomas Lively return; 820fd5e7b2SThomas Lively uint64_t fileOffset = chunk->outputSec != nullptr 830fd5e7b2SThomas Lively ? chunk->outputSec->getOffset() + chunk->outSecOff 840fd5e7b2SThomas Lively : 0; 85cc2da555SSam Clegg uint64_t vma = -1; 86cc2da555SSam Clegg uint64_t size = 0; 87cc2da555SSam Clegg if (auto *DD = dyn_cast<DefinedData>(syms[i])) { 8814ffbb84SSam Clegg vma = DD->getVA(); 89cc2da555SSam Clegg size = DD->getSize(); 9014ffbb84SSam Clegg fileOffset += DD->value; 91cc2da555SSam Clegg } 92cc2da555SSam Clegg if (auto *DF = dyn_cast<DefinedFunction>(syms[i])) { 93cc2da555SSam Clegg size = DF->function->getSize(); 94cc2da555SSam Clegg } 95cc2da555SSam Clegg writeHeader(os, vma, fileOffset, size); 96cc2da555SSam Clegg os.indent(16) << toString(*syms[i]); 97cc2da555SSam Clegg }); 98cc2da555SSam Clegg 99cc2da555SSam Clegg DenseMap<Symbol *, std::string> ret; 100cc2da555SSam Clegg for (size_t i = 0, e = syms.size(); i < e; ++i) 101cc2da555SSam Clegg ret[syms[i]] = std::move(str[i]); 102cc2da555SSam Clegg return ret; 103cc2da555SSam Clegg } 104cc2da555SSam Clegg 105cc2da555SSam Clegg void lld::wasm::writeMapFile(ArrayRef<OutputSection *> outputSections) { 106*3792b362SFangrui Song if (ctx.arg.mapFile.empty()) 107cc2da555SSam Clegg return; 108cc2da555SSam Clegg 109cc2da555SSam Clegg // Open a map file for writing. 110cc2da555SSam Clegg std::error_code ec; 111*3792b362SFangrui Song raw_fd_ostream os(ctx.arg.mapFile, ec, sys::fs::OF_None); 112cc2da555SSam Clegg if (ec) { 113*3792b362SFangrui Song error("cannot open " + ctx.arg.mapFile + ": " + ec.message()); 114cc2da555SSam Clegg return; 115cc2da555SSam Clegg } 116cc2da555SSam Clegg 117cc2da555SSam Clegg // Collect symbol info that we want to print out. 118cc2da555SSam Clegg std::vector<Symbol *> syms = getSymbols(); 119cc2da555SSam Clegg SymbolMapTy sectionSyms = getSectionSyms(syms); 120cc2da555SSam Clegg DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms); 121cc2da555SSam Clegg 122cc2da555SSam Clegg // Print out the header line. 123cc2da555SSam Clegg os << " Addr Off Size Out In Symbol\n"; 124cc2da555SSam Clegg 125cc2da555SSam Clegg for (OutputSection *osec : outputSections) { 126cc2da555SSam Clegg writeHeader(os, -1, osec->getOffset(), osec->getSize()); 127cc2da555SSam Clegg os << toString(*osec) << '\n'; 128cc2da555SSam Clegg if (auto *code = dyn_cast<CodeSection>(osec)) { 129cc2da555SSam Clegg for (auto *chunk : code->functions) { 13014ffbb84SSam Clegg writeHeader(os, -1, chunk->outputSec->getOffset() + chunk->outSecOff, 131cc2da555SSam Clegg chunk->getSize()); 132cc2da555SSam Clegg os.indent(8) << toString(chunk) << '\n'; 133cc2da555SSam Clegg for (Symbol *sym : sectionSyms[chunk]) 134cc2da555SSam Clegg os << symStr[sym] << '\n'; 135cc2da555SSam Clegg } 136cc2da555SSam Clegg } else if (auto *data = dyn_cast<DataSection>(osec)) { 137cc2da555SSam Clegg for (auto *oseg : data->segments) { 138cc2da555SSam Clegg writeHeader(os, oseg->startVA, data->getOffset() + oseg->sectionOffset, 139cc2da555SSam Clegg oseg->size); 140cc2da555SSam Clegg os << oseg->name << '\n'; 141cc2da555SSam Clegg for (auto *chunk : oseg->inputSegments) { 1420fd5e7b2SThomas Lively uint64_t offset = 1430fd5e7b2SThomas Lively chunk->outputSec != nullptr 1440fd5e7b2SThomas Lively ? chunk->outputSec->getOffset() + chunk->outSecOff 1450fd5e7b2SThomas Lively : 0; 1460fd5e7b2SThomas Lively writeHeader(os, chunk->getVA(), offset, chunk->getSize()); 147cc2da555SSam Clegg os.indent(8) << toString(chunk) << '\n'; 148cc2da555SSam Clegg for (Symbol *sym : sectionSyms[chunk]) 149cc2da555SSam Clegg os << symStr[sym] << '\n'; 150cc2da555SSam Clegg } 151cc2da555SSam Clegg } 152067f0055SThomas Lively } else if (auto *globals = dyn_cast<GlobalSection>(osec)) { 153067f0055SThomas Lively for (auto *global : globals->inputGlobals) { 154a56e5749SAndy Wingo writeHeader(os, global->getAssignedIndex(), 0, 0); 155067f0055SThomas Lively os.indent(8) << global->getName() << '\n'; 156cc2da555SSam Clegg } 157cc2da555SSam Clegg } 158067f0055SThomas Lively // TODO: other section/symbol types 159067f0055SThomas Lively } 160cc2da555SSam Clegg } 161