1 //===- LLDMapFile.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 /lldmap option. It shows lists in order and
10 // hierarchically the output sections, input sections, input files and
13 // Address Size Align Out File Symbol
14 // 00201000 00000015 4 .text
15 // 00201000 0000000e 4 test.o:(.text)
16 // 0020100e 00000000 0 local
17 // 00201005 00000000 0 f(int)
19 //===----------------------------------------------------------------------===//
21 #include "LLDMapFile.h"
22 #include "COFFLinkerContext.h"
23 #include "SymbolTable.h"
26 #include "lld/Common/ErrorHandler.h"
27 #include "llvm/Support/Parallel.h"
28 #include "llvm/Support/TimeProfiler.h"
29 #include "llvm/Support/raw_ostream.h"
32 using namespace llvm::object
;
34 using namespace lld::coff
;
37 DenseMap
<const SectionChunk
*, SmallVector
<DefinedRegular
*, 4>>;
39 static constexpr char indent8
[] = " "; // 8 spaces
40 static constexpr char indent16
[] = " "; // 16 spaces
42 // Print out the first three columns of a line.
43 static void writeHeader(raw_ostream
&os
, uint64_t addr
, uint64_t size
,
45 os
<< format("%08llx %08llx %5lld ", addr
, size
, align
);
48 // Returns a list of all symbols that we want to print out.
49 static std::vector
<DefinedRegular
*> getSymbols(const COFFLinkerContext
&ctx
) {
50 std::vector
<DefinedRegular
*> v
;
51 for (ObjFile
*file
: ctx
.objFileInstances
)
52 for (Symbol
*b
: file
->getSymbols())
53 if (auto *sym
= dyn_cast_or_null
<DefinedRegular
>(b
))
54 if (sym
&& !sym
->getCOFFSymbol().isSectionDefinition())
59 // Returns a map from sections to their symbols.
60 static SymbolMapTy
getSectionSyms(ArrayRef
<DefinedRegular
*> syms
) {
62 for (DefinedRegular
*s
: syms
)
63 ret
[s
->getChunk()].push_back(s
);
65 // Sort symbols by address.
66 for (auto &it
: ret
) {
67 SmallVectorImpl
<DefinedRegular
*> &v
= it
.second
;
68 std::stable_sort(v
.begin(), v
.end(), [](DefinedRegular
*a
, DefinedRegular
*b
) {
69 return a
->getRVA() < b
->getRVA();
75 // Construct a map from symbols to their stringified representations.
76 static DenseMap
<DefinedRegular
*, std::string
>
77 getSymbolStrings(const COFFLinkerContext
&ctx
,
78 ArrayRef
<DefinedRegular
*> syms
) {
79 std::vector
<std::string
> str(syms
.size());
80 parallelFor((size_t)0, syms
.size(), [&](size_t i
) {
81 raw_string_ostream
os(str
[i
]);
82 writeHeader(os
, syms
[i
]->getRVA(), 0, 0);
83 os
<< indent16
<< toString(ctx
, *syms
[i
]);
86 DenseMap
<DefinedRegular
*, std::string
> ret
;
87 for (size_t i
= 0, e
= syms
.size(); i
< e
; ++i
)
88 ret
[syms
[i
]] = std::move(str
[i
]);
92 void lld::coff::writeLLDMapFile(const COFFLinkerContext
&ctx
) {
93 if (ctx
.config
.lldmapFile
.empty())
96 llvm::TimeTraceScope
timeScope(".lldmap file");
98 raw_fd_ostream
os(ctx
.config
.lldmapFile
, ec
, sys::fs::OF_None
);
100 fatal("cannot open " + ctx
.config
.lldmapFile
+ ": " + ec
.message());
102 // Collect symbol info that we want to print out.
103 std::vector
<DefinedRegular
*> syms
= getSymbols(ctx
);
104 SymbolMapTy sectionSyms
= getSectionSyms(syms
);
105 DenseMap
<DefinedRegular
*, std::string
> symStr
= getSymbolStrings(ctx
, syms
);
107 // Print out the header line.
108 os
<< "Address Size Align Out In Symbol\n";
110 // Print out file contents.
111 for (OutputSection
*sec
: ctx
.outputSections
) {
112 writeHeader(os
, sec
->getRVA(), sec
->getVirtualSize(), /*align=*/pageSize
);
113 os
<< sec
->name
<< '\n';
115 for (Chunk
*c
: sec
->chunks
) {
116 auto *sc
= dyn_cast
<SectionChunk
>(c
);
120 writeHeader(os
, sc
->getRVA(), sc
->getSize(), sc
->getAlignment());
121 os
<< indent8
<< sc
->file
->getName() << ":(" << sc
->getSectionName()
123 for (DefinedRegular
*sym
: sectionSyms
[sc
])
124 os
<< symStr
[sym
] << '\n';