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 "InputElement.h" 23 #include "InputFiles.h" 24 #include "OutputSections.h" 25 #include "OutputSegment.h" 26 #include "SymbolTable.h" 27 #include "Symbols.h" 28 #include "SyntheticSections.h" 29 #include "lld/Common/Strings.h" 30 #include "llvm/ADT/MapVector.h" 31 #include "llvm/ADT/SetVector.h" 32 #include "llvm/Support/Parallel.h" 33 #include "llvm/Support/raw_ostream.h" 34 35 using namespace llvm; 36 using namespace llvm::object; 37 using namespace lld; 38 using namespace lld::wasm; 39 40 using SymbolMapTy = DenseMap<const InputChunk *, SmallVector<Symbol *, 4>>; 41 42 // Print out the first three columns of a line. 43 static void writeHeader(raw_ostream &os, int64_t vma, uint64_t lma, 44 uint64_t size) { 45 // Not all entries in the map has a virtual memory address (e.g. functions) 46 if (vma == -1) 47 os << format(" - %8llx %8llx ", lma, size); 48 else 49 os << format("%8llx %8llx %8llx ", vma, lma, size); 50 } 51 52 // Returns a list of all symbols that we want to print out. 53 static std::vector<Symbol *> getSymbols() { 54 std::vector<Symbol *> v; 55 for (InputFile *file : symtab->objectFiles) 56 for (Symbol *b : file->getSymbols()) 57 if (auto *dr = dyn_cast<Symbol>(b)) 58 if ((!isa<SectionSymbol>(dr)) && dr->isLive() && 59 (dr->getFile() == file)) 60 v.push_back(dr); 61 return v; 62 } 63 64 // Returns a map from sections to their symbols. 65 static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> syms) { 66 SymbolMapTy ret; 67 for (Symbol *dr : syms) 68 ret[dr->getChunk()].push_back(dr); 69 return ret; 70 } 71 72 // Construct a map from symbols to their stringified representations. 73 // Demangling symbols (which is what toString() does) is slow, so 74 // we do that in batch using parallel-for. 75 static DenseMap<Symbol *, std::string> 76 getSymbolStrings(ArrayRef<Symbol *> syms) { 77 std::vector<std::string> str(syms.size()); 78 parallelForEachN(0, syms.size(), [&](size_t i) { 79 raw_string_ostream os(str[i]); 80 auto *chunk = syms[i]->getChunk(); 81 if (chunk == nullptr) 82 return; 83 uint64_t fileOffset = chunk->outputSec->getOffset() + chunk->outSecOff; 84 uint64_t vma = -1; 85 uint64_t size = 0; 86 if (auto *DD = dyn_cast<DefinedData>(syms[i])) { 87 vma = DD->getVA(); 88 size = DD->getSize(); 89 fileOffset += DD->value; 90 } 91 if (auto *DF = dyn_cast<DefinedFunction>(syms[i])) { 92 size = DF->function->getSize(); 93 } 94 writeHeader(os, vma, fileOffset, size); 95 os.indent(16) << toString(*syms[i]); 96 }); 97 98 DenseMap<Symbol *, std::string> ret; 99 for (size_t i = 0, e = syms.size(); i < e; ++i) 100 ret[syms[i]] = std::move(str[i]); 101 return ret; 102 } 103 104 void lld::wasm::writeMapFile(ArrayRef<OutputSection *> outputSections) { 105 if (config->mapFile.empty()) 106 return; 107 108 // Open a map file for writing. 109 std::error_code ec; 110 raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); 111 if (ec) { 112 error("cannot open " + config->mapFile + ": " + ec.message()); 113 return; 114 } 115 116 // Collect symbol info that we want to print out. 117 std::vector<Symbol *> syms = getSymbols(); 118 SymbolMapTy sectionSyms = getSectionSyms(syms); 119 DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms); 120 121 // Print out the header line. 122 os << " Addr Off Size Out In Symbol\n"; 123 124 for (OutputSection *osec : outputSections) { 125 writeHeader(os, -1, osec->getOffset(), osec->getSize()); 126 os << toString(*osec) << '\n'; 127 if (auto *code = dyn_cast<CodeSection>(osec)) { 128 for (auto *chunk : code->functions) { 129 writeHeader(os, -1, chunk->outputSec->getOffset() + chunk->outSecOff, 130 chunk->getSize()); 131 os.indent(8) << toString(chunk) << '\n'; 132 for (Symbol *sym : sectionSyms[chunk]) 133 os << symStr[sym] << '\n'; 134 } 135 } else if (auto *data = dyn_cast<DataSection>(osec)) { 136 for (auto *oseg : data->segments) { 137 writeHeader(os, oseg->startVA, data->getOffset() + oseg->sectionOffset, 138 oseg->size); 139 os << oseg->name << '\n'; 140 for (auto *chunk : oseg->inputSegments) { 141 writeHeader(os, chunk->getVA(), 142 chunk->outputSec->getOffset() + chunk->outSecOff, 143 chunk->getSize()); 144 os.indent(8) << toString(chunk) << '\n'; 145 for (Symbol *sym : sectionSyms[chunk]) 146 os << symStr[sym] << '\n'; 147 } 148 } 149 } else if (auto *globals = dyn_cast<GlobalSection>(osec)) { 150 for (auto *global : globals->inputGlobals) { 151 writeHeader(os, global->getAssignedIndex(), 0, 0); 152 os.indent(8) << global->getName() << '\n'; 153 } 154 } 155 // TODO: other section/symbol types 156 } 157 } 158