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