1 //===- MapFile.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the -Map option. It shows lists in order and
10 // hierarchically the output sections, input sections, input files and
13 // Addr Off Size Out In Symbol
14 // - 00000015 10 .text
15 // - 0000000e 10 test.o:(.text)
17 // - 00000000 5 f(int)
19 //===----------------------------------------------------------------------===//
22 #include "InputElement.h"
23 #include "InputFiles.h"
24 #include "OutputSections.h"
25 #include "OutputSegment.h"
26 #include "SymbolTable.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"
36 using namespace llvm::object
;
38 using namespace lld::wasm
;
40 using SymbolMapTy
= DenseMap
<const InputChunk
*, SmallVector
<Symbol
*, 4>>;
42 // Print out the first three columns of a line.
43 static void writeHeader(raw_ostream
&os
, int64_t vma
, uint64_t lma
,
45 // Not all entries in the map has a virtual memory address (e.g. functions)
47 os
<< format(" - %8llx %8llx ", lma
, size
);
49 os
<< format("%8llx %8llx %8llx ", vma
, lma
, size
);
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
))
64 // Returns a map from sections to their symbols.
65 static SymbolMapTy
getSectionSyms(ArrayRef
<Symbol
*> syms
) {
67 for (Symbol
*dr
: syms
)
68 ret
[dr
->getChunk()].push_back(dr
);
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 parallelFor(0, syms
.size(), [&](size_t i
) {
79 raw_string_ostream
os(str
[i
]);
80 auto *chunk
= syms
[i
]->getChunk();
83 uint64_t fileOffset
= chunk
->outputSec
!= nullptr
84 ? chunk
->outputSec
->getOffset() + chunk
->outSecOff
88 if (auto *DD
= dyn_cast
<DefinedData
>(syms
[i
])) {
91 fileOffset
+= DD
->value
;
93 if (auto *DF
= dyn_cast
<DefinedFunction
>(syms
[i
])) {
94 size
= DF
->function
->getSize();
96 writeHeader(os
, vma
, fileOffset
, size
);
97 os
.indent(16) << toString(*syms
[i
]);
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
]);
106 void lld::wasm::writeMapFile(ArrayRef
<OutputSection
*> outputSections
) {
107 if (config
->mapFile
.empty())
110 // Open a map file for writing.
112 raw_fd_ostream
os(config
->mapFile
, ec
, sys::fs::OF_None
);
114 error("cannot open " + config
->mapFile
+ ": " + ec
.message());
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
);
123 // Print out the header line.
124 os
<< " Addr Off Size Out In Symbol\n";
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
,
133 os
.indent(8) << toString(chunk
) << '\n';
134 for (Symbol
*sym
: sectionSyms
[chunk
])
135 os
<< symStr
[sym
] << '\n';
137 } else if (auto *data
= dyn_cast
<DataSection
>(osec
)) {
138 for (auto *oseg
: data
->segments
) {
139 writeHeader(os
, oseg
->startVA
, data
->getOffset() + oseg
->sectionOffset
,
141 os
<< oseg
->name
<< '\n';
142 for (auto *chunk
: oseg
->inputSegments
) {
144 chunk
->outputSec
!= nullptr
145 ? chunk
->outputSec
->getOffset() + chunk
->outSecOff
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';
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';
159 // TODO: other section/symbol types