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/Support/Parallel.h"
32 #include "llvm/Support/raw_ostream.h"
35 using namespace llvm::object
;
37 using namespace lld::wasm
;
39 using SymbolMapTy
= DenseMap
<const InputChunk
*, SmallVector
<Symbol
*, 4>>;
41 // Print out the first three columns of a line.
42 static void writeHeader(raw_ostream
&os
, int64_t vma
, uint64_t lma
,
44 // Not all entries in the map has a virtual memory address (e.g. functions)
46 os
<< format(" - %8llx %8llx ", lma
, size
);
48 os
<< format("%8llx %8llx %8llx ", vma
, lma
, size
);
51 // Returns a list of all symbols that we want to print out.
52 static std::vector
<Symbol
*> getSymbols() {
53 std::vector
<Symbol
*> v
;
54 for (InputFile
*file
: ctx
.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
))
63 // Returns a map from sections to their symbols.
64 static SymbolMapTy
getSectionSyms(ArrayRef
<Symbol
*> syms
) {
66 for (Symbol
*dr
: syms
)
67 ret
[dr
->getChunk()].push_back(dr
);
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.
74 static DenseMap
<Symbol
*, std::string
>
75 getSymbolStrings(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();
82 uint64_t fileOffset
= chunk
->outputSec
!= nullptr
83 ? chunk
->outputSec
->getOffset() + chunk
->outSecOff
87 if (auto *DD
= dyn_cast
<DefinedData
>(syms
[i
])) {
90 fileOffset
+= DD
->value
;
92 if (auto *DF
= dyn_cast
<DefinedFunction
>(syms
[i
])) {
93 size
= DF
->function
->getSize();
95 writeHeader(os
, vma
, fileOffset
, size
);
96 os
.indent(16) << toString(*syms
[i
]);
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
]);
105 void lld::wasm::writeMapFile(ArrayRef
<OutputSection
*> outputSections
) {
106 if (config
->mapFile
.empty())
109 // Open a map file for writing.
111 raw_fd_ostream
os(config
->mapFile
, ec
, sys::fs::OF_None
);
113 error("cannot open " + config
->mapFile
+ ": " + ec
.message());
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
);
122 // Print out the header line.
123 os
<< " Addr Off Size Out In Symbol\n";
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
,
132 os
.indent(8) << toString(chunk
) << '\n';
133 for (Symbol
*sym
: sectionSyms
[chunk
])
134 os
<< symStr
[sym
] << '\n';
136 } else if (auto *data
= dyn_cast
<DataSection
>(osec
)) {
137 for (auto *oseg
: data
->segments
) {
138 writeHeader(os
, oseg
->startVA
, data
->getOffset() + oseg
->sectionOffset
,
140 os
<< oseg
->name
<< '\n';
141 for (auto *chunk
: oseg
->inputSegments
) {
143 chunk
->outputSec
!= nullptr
144 ? chunk
->outputSec
->getOffset() + chunk
->outSecOff
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';
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';
158 // TODO: other section/symbol types