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 != nullptr 84 ? chunk->outputSec->getOffset() + chunk->outSecOff 85 : 0; 86 uint64_t vma = -1; 87 uint64_t size = 0; 88 if (auto *DD = dyn_cast<DefinedData>(syms[i])) { 89 vma = DD->getVA(); 90 size = DD->getSize(); 91 fileOffset += DD->value; 92 } 93 if (auto *DF = dyn_cast<DefinedFunction>(syms[i])) { 94 size = DF->function->getSize(); 95 } 96 writeHeader(os, vma, fileOffset, size); 97 os.indent(16) << toString(*syms[i]); 98 }); 99 100 DenseMap<Symbol *, std::string> ret; 101 for (size_t i = 0, e = syms.size(); i < e; ++i) 102 ret[syms[i]] = std::move(str[i]); 103 return ret; 104 } 105 106 void lld::wasm::writeMapFile(ArrayRef<OutputSection *> outputSections) { 107 if (config->mapFile.empty()) 108 return; 109 110 // Open a map file for writing. 111 std::error_code ec; 112 raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); 113 if (ec) { 114 error("cannot open " + config->mapFile + ": " + ec.message()); 115 return; 116 } 117 118 // Collect symbol info that we want to print out. 119 std::vector<Symbol *> syms = getSymbols(); 120 SymbolMapTy sectionSyms = getSectionSyms(syms); 121 DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms); 122 123 // Print out the header line. 124 os << " Addr Off Size Out In Symbol\n"; 125 126 for (OutputSection *osec : outputSections) { 127 writeHeader(os, -1, osec->getOffset(), osec->getSize()); 128 os << toString(*osec) << '\n'; 129 if (auto *code = dyn_cast<CodeSection>(osec)) { 130 for (auto *chunk : code->functions) { 131 writeHeader(os, -1, chunk->outputSec->getOffset() + chunk->outSecOff, 132 chunk->getSize()); 133 os.indent(8) << toString(chunk) << '\n'; 134 for (Symbol *sym : sectionSyms[chunk]) 135 os << symStr[sym] << '\n'; 136 } 137 } else if (auto *data = dyn_cast<DataSection>(osec)) { 138 for (auto *oseg : data->segments) { 139 writeHeader(os, oseg->startVA, data->getOffset() + oseg->sectionOffset, 140 oseg->size); 141 os << oseg->name << '\n'; 142 for (auto *chunk : oseg->inputSegments) { 143 uint64_t offset = 144 chunk->outputSec != nullptr 145 ? chunk->outputSec->getOffset() + chunk->outSecOff 146 : 0; 147 writeHeader(os, chunk->getVA(), offset, chunk->getSize()); 148 os.indent(8) << toString(chunk) << '\n'; 149 for (Symbol *sym : sectionSyms[chunk]) 150 os << symStr[sym] << '\n'; 151 } 152 } 153 } else if (auto *globals = dyn_cast<GlobalSection>(osec)) { 154 for (auto *global : globals->inputGlobals) { 155 writeHeader(os, global->getAssignedIndex(), 0, 0); 156 os.indent(8) << global->getName() << '\n'; 157 } 158 } 159 // TODO: other section/symbol types 160 } 161 } 162