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