xref: /openbsd-src/gnu/llvm/lld/COFF/LLDMapFile.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1bb684c34Spatrick //===- LLDMapFile.cpp -----------------------------------------------------===//
2bb684c34Spatrick //
3bb684c34Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bb684c34Spatrick // See https://llvm.org/LICENSE.txt for license information.
5bb684c34Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bb684c34Spatrick //
7bb684c34Spatrick //===----------------------------------------------------------------------===//
8bb684c34Spatrick //
9bb684c34Spatrick // This file implements the /lldmap option. It shows lists in order and
10bb684c34Spatrick // hierarchically the output sections, input sections, input files and
11bb684c34Spatrick // symbol:
12bb684c34Spatrick //
13bb684c34Spatrick //   Address  Size     Align Out     File    Symbol
14bb684c34Spatrick //   00201000 00000015     4 .text
15bb684c34Spatrick //   00201000 0000000e     4         test.o:(.text)
16bb684c34Spatrick //   0020100e 00000000     0                 local
17bb684c34Spatrick //   00201005 00000000     0                 f(int)
18bb684c34Spatrick //
19bb684c34Spatrick //===----------------------------------------------------------------------===//
20bb684c34Spatrick 
21bb684c34Spatrick #include "LLDMapFile.h"
22*dfe94b16Srobert #include "COFFLinkerContext.h"
23bb684c34Spatrick #include "SymbolTable.h"
24bb684c34Spatrick #include "Symbols.h"
25bb684c34Spatrick #include "Writer.h"
26bb684c34Spatrick #include "lld/Common/ErrorHandler.h"
27bb684c34Spatrick #include "llvm/Support/Parallel.h"
28bb684c34Spatrick #include "llvm/Support/raw_ostream.h"
29bb684c34Spatrick 
30bb684c34Spatrick using namespace llvm;
31bb684c34Spatrick using namespace llvm::object;
32bb684c34Spatrick using namespace lld;
33bb684c34Spatrick using namespace lld::coff;
34bb684c34Spatrick 
35bb684c34Spatrick using SymbolMapTy =
36bb684c34Spatrick     DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>;
37bb684c34Spatrick 
38bb684c34Spatrick static constexpr char indent8[] = "        ";          // 8 spaces
39bb684c34Spatrick static constexpr char indent16[] = "                "; // 16 spaces
40bb684c34Spatrick 
41bb684c34Spatrick // Print out the first three columns of a line.
writeHeader(raw_ostream & os,uint64_t addr,uint64_t size,uint64_t align)42bb684c34Spatrick static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
43bb684c34Spatrick                         uint64_t align) {
44bb684c34Spatrick   os << format("%08llx %08llx %5lld ", addr, size, align);
45bb684c34Spatrick }
46bb684c34Spatrick 
47bb684c34Spatrick // Returns a list of all symbols that we want to print out.
getSymbols(const COFFLinkerContext & ctx)48*dfe94b16Srobert static std::vector<DefinedRegular *> getSymbols(const COFFLinkerContext &ctx) {
49bb684c34Spatrick   std::vector<DefinedRegular *> v;
50*dfe94b16Srobert   for (ObjFile *file : ctx.objFileInstances)
51bb684c34Spatrick     for (Symbol *b : file->getSymbols())
52bb684c34Spatrick       if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
53bb684c34Spatrick         if (sym && !sym->getCOFFSymbol().isSectionDefinition())
54bb684c34Spatrick           v.push_back(sym);
55bb684c34Spatrick   return v;
56bb684c34Spatrick }
57bb684c34Spatrick 
58bb684c34Spatrick // Returns a map from sections to their symbols.
getSectionSyms(ArrayRef<DefinedRegular * > syms)59bb684c34Spatrick static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> syms) {
60bb684c34Spatrick   SymbolMapTy ret;
61bb684c34Spatrick   for (DefinedRegular *s : syms)
62bb684c34Spatrick     ret[s->getChunk()].push_back(s);
63bb684c34Spatrick 
64bb684c34Spatrick   // Sort symbols by address.
65bb684c34Spatrick   for (auto &it : ret) {
66bb684c34Spatrick     SmallVectorImpl<DefinedRegular *> &v = it.second;
67bb684c34Spatrick     std::stable_sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) {
68bb684c34Spatrick       return a->getRVA() < b->getRVA();
69bb684c34Spatrick     });
70bb684c34Spatrick   }
71bb684c34Spatrick   return ret;
72bb684c34Spatrick }
73bb684c34Spatrick 
74bb684c34Spatrick // Construct a map from symbols to their stringified representations.
75bb684c34Spatrick static DenseMap<DefinedRegular *, std::string>
getSymbolStrings(const COFFLinkerContext & ctx,ArrayRef<DefinedRegular * > syms)76*dfe94b16Srobert getSymbolStrings(const COFFLinkerContext &ctx,
77*dfe94b16Srobert                  ArrayRef<DefinedRegular *> syms) {
78bb684c34Spatrick   std::vector<std::string> str(syms.size());
79*dfe94b16Srobert   parallelFor((size_t)0, syms.size(), [&](size_t i) {
80bb684c34Spatrick     raw_string_ostream os(str[i]);
81bb684c34Spatrick     writeHeader(os, syms[i]->getRVA(), 0, 0);
82*dfe94b16Srobert     os << indent16 << toString(ctx, *syms[i]);
83bb684c34Spatrick   });
84bb684c34Spatrick 
85bb684c34Spatrick   DenseMap<DefinedRegular *, std::string> ret;
86bb684c34Spatrick   for (size_t i = 0, e = syms.size(); i < e; ++i)
87bb684c34Spatrick     ret[syms[i]] = std::move(str[i]);
88bb684c34Spatrick   return ret;
89bb684c34Spatrick }
90bb684c34Spatrick 
writeLLDMapFile(const COFFLinkerContext & ctx)91*dfe94b16Srobert void lld::coff::writeLLDMapFile(const COFFLinkerContext &ctx) {
92*dfe94b16Srobert   if (ctx.config.lldmapFile.empty())
93bb684c34Spatrick     return;
94bb684c34Spatrick 
95bb684c34Spatrick   std::error_code ec;
96*dfe94b16Srobert   raw_fd_ostream os(ctx.config.lldmapFile, ec, sys::fs::OF_None);
97bb684c34Spatrick   if (ec)
98*dfe94b16Srobert     fatal("cannot open " + ctx.config.lldmapFile + ": " + ec.message());
99bb684c34Spatrick 
100bb684c34Spatrick   // Collect symbol info that we want to print out.
101*dfe94b16Srobert   std::vector<DefinedRegular *> syms = getSymbols(ctx);
102bb684c34Spatrick   SymbolMapTy sectionSyms = getSectionSyms(syms);
103*dfe94b16Srobert   DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(ctx, syms);
104bb684c34Spatrick 
105bb684c34Spatrick   // Print out the header line.
106bb684c34Spatrick   os << "Address  Size     Align Out     In      Symbol\n";
107bb684c34Spatrick 
108bb684c34Spatrick   // Print out file contents.
109*dfe94b16Srobert   for (OutputSection *sec : ctx.outputSections) {
110bb684c34Spatrick     writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize);
111bb684c34Spatrick     os << sec->name << '\n';
112bb684c34Spatrick 
113bb684c34Spatrick     for (Chunk *c : sec->chunks) {
114bb684c34Spatrick       auto *sc = dyn_cast<SectionChunk>(c);
115bb684c34Spatrick       if (!sc)
116bb684c34Spatrick         continue;
117bb684c34Spatrick 
118bb684c34Spatrick       writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment());
119bb684c34Spatrick       os << indent8 << sc->file->getName() << ":(" << sc->getSectionName()
120bb684c34Spatrick          << ")\n";
121bb684c34Spatrick       for (DefinedRegular *sym : sectionSyms[sc])
122bb684c34Spatrick         os << symStr[sym] << '\n';
123bb684c34Spatrick     }
124bb684c34Spatrick   }
125bb684c34Spatrick }
126