xref: /freebsd/contrib/llvm-project/lld/MachO/MapFile.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
1*fe6060f1SDimitry Andric //===- MapFile.cpp --------------------------------------------------------===//
2*fe6060f1SDimitry Andric //
3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fe6060f1SDimitry Andric //
7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8*fe6060f1SDimitry Andric //
9*fe6060f1SDimitry Andric // This file implements the -map option. It shows lists in order and
10*fe6060f1SDimitry Andric // hierarchically the outputFile, arch, input files, output sections and
11*fe6060f1SDimitry Andric // symbol:
12*fe6060f1SDimitry Andric //
13*fe6060f1SDimitry Andric // # Path: test
14*fe6060f1SDimitry Andric // # Arch: x86_84
15*fe6060f1SDimitry Andric // # Object files:
16*fe6060f1SDimitry Andric // [  0] linker synthesized
17*fe6060f1SDimitry Andric // [  1] a.o
18*fe6060f1SDimitry Andric // # Sections:
19*fe6060f1SDimitry Andric // # Address  Size      Segment  Section
20*fe6060f1SDimitry Andric // 0x1000005C0  0x0000004C  __TEXT  __text
21*fe6060f1SDimitry Andric // # Symbols:
22*fe6060f1SDimitry Andric // # Address  File  Name
23*fe6060f1SDimitry Andric // 0x1000005C0  [  1] _main
24*fe6060f1SDimitry Andric //
25*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
26*fe6060f1SDimitry Andric 
27*fe6060f1SDimitry Andric #include "MapFile.h"
28*fe6060f1SDimitry Andric #include "Config.h"
29*fe6060f1SDimitry Andric #include "InputFiles.h"
30*fe6060f1SDimitry Andric #include "InputSection.h"
31*fe6060f1SDimitry Andric #include "OutputSection.h"
32*fe6060f1SDimitry Andric #include "OutputSegment.h"
33*fe6060f1SDimitry Andric #include "Symbols.h"
34*fe6060f1SDimitry Andric #include "Target.h"
35*fe6060f1SDimitry Andric #include "llvm/Support/Parallel.h"
36*fe6060f1SDimitry Andric #include "llvm/Support/TimeProfiler.h"
37*fe6060f1SDimitry Andric 
38*fe6060f1SDimitry Andric using namespace llvm;
39*fe6060f1SDimitry Andric using namespace llvm::sys;
40*fe6060f1SDimitry Andric using namespace lld;
41*fe6060f1SDimitry Andric using namespace lld::macho;
42*fe6060f1SDimitry Andric 
43*fe6060f1SDimitry Andric using SymbolMapTy = DenseMap<const InputSection *, SmallVector<Defined *, 4>>;
44*fe6060f1SDimitry Andric 
45*fe6060f1SDimitry Andric // Returns a map from sections to their symbols.
46*fe6060f1SDimitry Andric static SymbolMapTy getSectionSyms(ArrayRef<Defined *> syms) {
47*fe6060f1SDimitry Andric   SymbolMapTy ret;
48*fe6060f1SDimitry Andric   for (Defined *dr : syms)
49*fe6060f1SDimitry Andric     ret[dr->isec].push_back(dr);
50*fe6060f1SDimitry Andric 
51*fe6060f1SDimitry Andric   // Sort symbols by address. We want to print out symbols in the order they
52*fe6060f1SDimitry Andric   // appear in the output file rather than the order they appeared in the input
53*fe6060f1SDimitry Andric   // files.
54*fe6060f1SDimitry Andric   for (auto &it : ret)
55*fe6060f1SDimitry Andric     parallelSort(
56*fe6060f1SDimitry Andric         it.second.begin(), it.second.end(), [](Defined *a, Defined *b) {
57*fe6060f1SDimitry Andric           return a->getVA() != b->getVA() ? a->getVA() < b->getVA()
58*fe6060f1SDimitry Andric                                           : a->getName() < b->getName();
59*fe6060f1SDimitry Andric         });
60*fe6060f1SDimitry Andric   return ret;
61*fe6060f1SDimitry Andric }
62*fe6060f1SDimitry Andric 
63*fe6060f1SDimitry Andric // Returns a list of all symbols that we want to print out.
64*fe6060f1SDimitry Andric static std::vector<Defined *> getSymbols() {
65*fe6060f1SDimitry Andric   std::vector<Defined *> v;
66*fe6060f1SDimitry Andric   for (InputFile *file : inputFiles)
67*fe6060f1SDimitry Andric     if (isa<ObjFile>(file))
68*fe6060f1SDimitry Andric       for (Symbol *sym : file->symbols)
69*fe6060f1SDimitry Andric         if (auto *d = dyn_cast_or_null<Defined>(sym))
70*fe6060f1SDimitry Andric           if (d->isLive() && d->isec && d->getFile() == file) {
71*fe6060f1SDimitry Andric             assert(!shouldOmitFromOutput(d->isec));
72*fe6060f1SDimitry Andric             v.push_back(d);
73*fe6060f1SDimitry Andric           }
74*fe6060f1SDimitry Andric   return v;
75*fe6060f1SDimitry Andric }
76*fe6060f1SDimitry Andric 
77*fe6060f1SDimitry Andric // Construct a map from symbols to their stringified representations.
78*fe6060f1SDimitry Andric // Demangling symbols (which is what toString() does) is slow, so
79*fe6060f1SDimitry Andric // we do that in batch using parallel-for.
80*fe6060f1SDimitry Andric static DenseMap<Symbol *, std::string>
81*fe6060f1SDimitry Andric getSymbolStrings(ArrayRef<Defined *> syms) {
82*fe6060f1SDimitry Andric   std::vector<std::string> str(syms.size());
83*fe6060f1SDimitry Andric   parallelForEachN(0, syms.size(), [&](size_t i) {
84*fe6060f1SDimitry Andric     raw_string_ostream os(str[i]);
85*fe6060f1SDimitry Andric     os << toString(*syms[i]);
86*fe6060f1SDimitry Andric   });
87*fe6060f1SDimitry Andric 
88*fe6060f1SDimitry Andric   DenseMap<Symbol *, std::string> ret;
89*fe6060f1SDimitry Andric   for (size_t i = 0, e = syms.size(); i < e; ++i)
90*fe6060f1SDimitry Andric     ret[syms[i]] = std::move(str[i]);
91*fe6060f1SDimitry Andric   return ret;
92*fe6060f1SDimitry Andric }
93*fe6060f1SDimitry Andric 
94*fe6060f1SDimitry Andric void macho::writeMapFile() {
95*fe6060f1SDimitry Andric   if (config->mapFile.empty())
96*fe6060f1SDimitry Andric     return;
97*fe6060f1SDimitry Andric 
98*fe6060f1SDimitry Andric   TimeTraceScope timeScope("Write map file");
99*fe6060f1SDimitry Andric 
100*fe6060f1SDimitry Andric   // Open a map file for writing.
101*fe6060f1SDimitry Andric   std::error_code ec;
102*fe6060f1SDimitry Andric   raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
103*fe6060f1SDimitry Andric   if (ec) {
104*fe6060f1SDimitry Andric     error("cannot open " + config->mapFile + ": " + ec.message());
105*fe6060f1SDimitry Andric     return;
106*fe6060f1SDimitry Andric   }
107*fe6060f1SDimitry Andric 
108*fe6060f1SDimitry Andric   // Dump output path.
109*fe6060f1SDimitry Andric   os << format("# Path: %s\n", config->outputFile.str().c_str());
110*fe6060f1SDimitry Andric 
111*fe6060f1SDimitry Andric   // Dump output architecture.
112*fe6060f1SDimitry Andric   os << format("# Arch: %s\n",
113*fe6060f1SDimitry Andric                getArchitectureName(config->arch()).str().c_str());
114*fe6060f1SDimitry Andric 
115*fe6060f1SDimitry Andric   // Dump table of object files.
116*fe6060f1SDimitry Andric   os << "# Object files:\n";
117*fe6060f1SDimitry Andric   os << format("[%3u] %s\n", 0, (const char *)"linker synthesized");
118*fe6060f1SDimitry Andric   uint32_t fileIndex = 1;
119*fe6060f1SDimitry Andric   DenseMap<lld::macho::InputFile *, uint32_t> readerToFileOrdinal;
120*fe6060f1SDimitry Andric   for (InputFile *file : inputFiles) {
121*fe6060f1SDimitry Andric     if (isa<ObjFile>(file)) {
122*fe6060f1SDimitry Andric       os << format("[%3u] %s\n", fileIndex, file->getName().str().c_str());
123*fe6060f1SDimitry Andric       readerToFileOrdinal[file] = fileIndex++;
124*fe6060f1SDimitry Andric     }
125*fe6060f1SDimitry Andric   }
126*fe6060f1SDimitry Andric 
127*fe6060f1SDimitry Andric   // Collect symbol info that we want to print out.
128*fe6060f1SDimitry Andric   std::vector<Defined *> syms = getSymbols();
129*fe6060f1SDimitry Andric   SymbolMapTy sectionSyms = getSectionSyms(syms);
130*fe6060f1SDimitry Andric   DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms);
131*fe6060f1SDimitry Andric 
132*fe6060f1SDimitry Andric   // Dump table of sections
133*fe6060f1SDimitry Andric   os << "# Sections:\n";
134*fe6060f1SDimitry Andric   os << "# Address\tSize    \tSegment\tSection\n";
135*fe6060f1SDimitry Andric   for (OutputSegment *seg : outputSegments)
136*fe6060f1SDimitry Andric     for (OutputSection *osec : seg->getSections()) {
137*fe6060f1SDimitry Andric       if (osec->isHidden())
138*fe6060f1SDimitry Andric         continue;
139*fe6060f1SDimitry Andric 
140*fe6060f1SDimitry Andric       os << format("0x%08llX\t0x%08llX\t%s\t%s\n", osec->addr, osec->getSize(),
141*fe6060f1SDimitry Andric                    seg->name.str().c_str(), osec->name.str().c_str());
142*fe6060f1SDimitry Andric     }
143*fe6060f1SDimitry Andric 
144*fe6060f1SDimitry Andric   // Dump table of symbols
145*fe6060f1SDimitry Andric   os << "# Symbols:\n";
146*fe6060f1SDimitry Andric   os << "# Address\t    File  Name\n";
147*fe6060f1SDimitry Andric   for (InputSection *isec : inputSections) {
148*fe6060f1SDimitry Andric     auto symsIt = sectionSyms.find(isec);
149*fe6060f1SDimitry Andric     assert(!shouldOmitFromOutput(isec) || (symsIt == sectionSyms.end()));
150*fe6060f1SDimitry Andric     if (symsIt == sectionSyms.end())
151*fe6060f1SDimitry Andric       continue;
152*fe6060f1SDimitry Andric     for (Symbol *sym : symsIt->second) {
153*fe6060f1SDimitry Andric       os << format("0x%08llX\t[%3u] %s\n", sym->getVA(),
154*fe6060f1SDimitry Andric                    readerToFileOrdinal[sym->getFile()], symStr[sym].c_str());
155*fe6060f1SDimitry Andric     }
156*fe6060f1SDimitry Andric   }
157*fe6060f1SDimitry Andric 
158*fe6060f1SDimitry Andric   // TODO: when we implement -dead_strip, we should dump dead stripped symbols
159*fe6060f1SDimitry Andric }
160