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 outputFile, arch, input files, output sections and
16 // [ 0] linker synthesized
19 // # Address Size Segment Section
20 // 0x1000005C0 0x0000004C __TEXT __text
22 // # Address File Name
23 // 0x1000005C0 [ 1] _main
25 //===----------------------------------------------------------------------===//
29 #include "InputFiles.h"
30 #include "InputSection.h"
31 #include "OutputSection.h"
32 #include "OutputSegment.h"
35 #include "llvm/Support/Parallel.h"
36 #include "llvm/Support/TimeProfiler.h"
39 using namespace llvm::sys
;
41 using namespace lld::macho
;
43 using SymbolMapTy
= DenseMap
<const InputSection
*, SmallVector
<Defined
*, 4>>;
45 // Returns a map from sections to their symbols.
46 static SymbolMapTy
getSectionSyms(ArrayRef
<Defined
*> syms
) {
48 for (Defined
*dr
: syms
)
49 ret
[dr
->isec
].push_back(dr
);
51 // Sort symbols by address. We want to print out symbols in the order they
52 // appear in the output file rather than the order they appeared in the input
56 it
.second
.begin(), it
.second
.end(), [](Defined
*a
, Defined
*b
) {
57 return a
->getVA() != b
->getVA() ? a
->getVA() < b
->getVA()
58 : a
->getName() < b
->getName();
63 // Returns a list of all symbols that we want to print out.
64 static std::vector
<Defined
*> getSymbols() {
65 std::vector
<Defined
*> v
;
66 for (InputFile
*file
: inputFiles
)
67 if (isa
<ObjFile
>(file
))
68 for (Symbol
*sym
: file
->symbols
)
69 if (auto *d
= dyn_cast_or_null
<Defined
>(sym
))
70 if (d
->isLive() && d
->isec
&& d
->getFile() == file
) {
71 assert(!shouldOmitFromOutput(d
->isec
));
77 // Construct a map from symbols to their stringified representations.
78 // Demangling symbols (which is what toString() does) is slow, so
79 // we do that in batch using parallel-for.
80 static DenseMap
<Symbol
*, std::string
>
81 getSymbolStrings(ArrayRef
<Defined
*> syms
) {
82 std::vector
<std::string
> str(syms
.size());
83 parallelForEachN(0, syms
.size(), [&](size_t i
) {
84 raw_string_ostream
os(str
[i
]);
85 os
<< toString(*syms
[i
]);
88 DenseMap
<Symbol
*, std::string
> ret
;
89 for (size_t i
= 0, e
= syms
.size(); i
< e
; ++i
)
90 ret
[syms
[i
]] = std::move(str
[i
]);
94 void macho::writeMapFile() {
95 if (config
->mapFile
.empty())
98 TimeTraceScope
timeScope("Write map file");
100 // Open a map file for writing.
102 raw_fd_ostream
os(config
->mapFile
, ec
, sys::fs::OF_None
);
104 error("cannot open " + config
->mapFile
+ ": " + ec
.message());
109 os
<< format("# Path: %s\n", config
->outputFile
.str().c_str());
111 // Dump output architecture.
112 os
<< format("# Arch: %s\n",
113 getArchitectureName(config
->arch()).str().c_str());
115 // Dump table of object files.
116 os
<< "# Object files:\n";
117 os
<< format("[%3u] %s\n", 0, (const char *)"linker synthesized");
118 uint32_t fileIndex
= 1;
119 DenseMap
<lld::macho::InputFile
*, uint32_t> readerToFileOrdinal
;
120 for (InputFile
*file
: inputFiles
) {
121 if (isa
<ObjFile
>(file
)) {
122 os
<< format("[%3u] %s\n", fileIndex
, file
->getName().str().c_str());
123 readerToFileOrdinal
[file
] = fileIndex
++;
127 // Collect symbol info that we want to print out.
128 std::vector
<Defined
*> syms
= getSymbols();
129 SymbolMapTy sectionSyms
= getSectionSyms(syms
);
130 DenseMap
<Symbol
*, std::string
> symStr
= getSymbolStrings(syms
);
132 // Dump table of sections
133 os
<< "# Sections:\n";
134 os
<< "# Address\tSize \tSegment\tSection\n";
135 for (OutputSegment
*seg
: outputSegments
)
136 for (OutputSection
*osec
: seg
->getSections()) {
137 if (osec
->isHidden())
140 os
<< format("0x%08llX\t0x%08llX\t%s\t%s\n", osec
->addr
, osec
->getSize(),
141 seg
->name
.str().c_str(), osec
->name
.str().c_str());
144 // Dump table of symbols
145 os
<< "# Symbols:\n";
146 os
<< "# Address\t File Name\n";
147 for (InputSection
*isec
: inputSections
) {
148 auto symsIt
= sectionSyms
.find(isec
);
149 assert(!shouldOmitFromOutput(isec
) || (symsIt
== sectionSyms
.end()));
150 if (symsIt
== sectionSyms
.end())
152 for (Symbol
*sym
: symsIt
->second
) {
153 os
<< format("0x%08llX\t[%3u] %s\n", sym
->getVA(),
154 readerToFileOrdinal
[sym
->getFile()], symStr
[sym
].c_str());
158 // TODO: when we implement -dead_strip, we should dump dead stripped symbols