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