xref: /llvm-project-15.0.7/lld/MachO/MapFile.cpp (revision 7effcbda)
1ed8bff13Scaoming.roy //===- MapFile.cpp --------------------------------------------------------===//
2ed8bff13Scaoming.roy //
3ed8bff13Scaoming.roy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ed8bff13Scaoming.roy // See https://llvm.org/LICENSE.txt for license information.
5ed8bff13Scaoming.roy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ed8bff13Scaoming.roy //
7ed8bff13Scaoming.roy //===----------------------------------------------------------------------===//
8ed8bff13Scaoming.roy //
9ed8bff13Scaoming.roy // This file implements the -map option. It shows lists in order and
10ed8bff13Scaoming.roy // hierarchically the outputFile, arch, input files, output sections and
11ed8bff13Scaoming.roy // symbol:
12ed8bff13Scaoming.roy //
13ed8bff13Scaoming.roy // # Path: test
14ed8bff13Scaoming.roy // # Arch: x86_84
15ed8bff13Scaoming.roy // # Object files:
16ed8bff13Scaoming.roy // [  0] linker synthesized
17ed8bff13Scaoming.roy // [  1] a.o
18ed8bff13Scaoming.roy // # Sections:
19ed8bff13Scaoming.roy // # Address  Size      Segment  Section
20ed8bff13Scaoming.roy // 0x1000005C0  0x0000004C  __TEXT  __text
21ed8bff13Scaoming.roy // # Symbols:
22ed8bff13Scaoming.roy // # Address  File  Name
23ed8bff13Scaoming.roy // 0x1000005C0  [  1] _main
24ed8bff13Scaoming.roy //
25ed8bff13Scaoming.roy //===----------------------------------------------------------------------===//
26ed8bff13Scaoming.roy 
27ed8bff13Scaoming.roy #include "MapFile.h"
28ed8bff13Scaoming.roy #include "Config.h"
29ed8bff13Scaoming.roy #include "InputFiles.h"
30ed8bff13Scaoming.roy #include "InputSection.h"
31ed8bff13Scaoming.roy #include "OutputSection.h"
32ed8bff13Scaoming.roy #include "OutputSegment.h"
33ed8bff13Scaoming.roy #include "Symbols.h"
344f2c46c3SRoger Kim #include "SyntheticSections.h"
35ed8bff13Scaoming.roy #include "Target.h"
36ed8bff13Scaoming.roy #include "llvm/Support/Parallel.h"
374bcaafebSJez Ng #include "llvm/Support/TimeProfiler.h"
38ed8bff13Scaoming.roy 
39ed8bff13Scaoming.roy using namespace llvm;
40ed8bff13Scaoming.roy using namespace llvm::sys;
41ed8bff13Scaoming.roy using namespace lld;
42ed8bff13Scaoming.roy using namespace lld::macho;
43ed8bff13Scaoming.roy 
4442208433SRoger Kim using Symbols = std::vector<Defined *>;
4542208433SRoger Kim // Returns a pair where the left element is a container of all live Symbols and
4642208433SRoger Kim // the right element is a container of all dead symbols.
getSymbols()4742208433SRoger Kim static std::pair<Symbols, Symbols> getSymbols() {
4842208433SRoger Kim   Symbols liveSymbols, deadSymbols;
49ed8bff13Scaoming.roy   for (InputFile *file : inputFiles)
50ed8bff13Scaoming.roy     if (isa<ObjFile>(file))
515de7467eSJez Ng       for (Symbol *sym : file->symbols)
52a5645513SNico Weber         if (auto *d = dyn_cast_or_null<Defined>(sym))
5342208433SRoger Kim           if (d->isec && d->getFile() == file) {
5442208433SRoger Kim             if (d->isLive()) {
55b8bbb972SJez Ng               assert(!shouldOmitFromOutput(d->isec));
5642208433SRoger Kim               liveSymbols.push_back(d);
5742208433SRoger Kim             } else {
5842208433SRoger Kim               deadSymbols.push_back(d);
59b8bbb972SJez Ng             }
6042208433SRoger Kim           }
6142208433SRoger Kim   parallelSort(liveSymbols.begin(), liveSymbols.end(),
6242208433SRoger Kim                [](Defined *a, Defined *b) {
6342208433SRoger Kim                  return a->getVA() != b->getVA() ? a->getVA() < b->getVA()
6442208433SRoger Kim                                                  : a->getName() < b->getName();
6542208433SRoger Kim                });
6642208433SRoger Kim   parallelSort(
6742208433SRoger Kim       deadSymbols.begin(), deadSymbols.end(),
6842208433SRoger Kim       [](Defined *a, Defined *b) { return a->getName() < b->getName(); });
6942208433SRoger Kim   return {std::move(liveSymbols), std::move(deadSymbols)};
70ed8bff13Scaoming.roy }
71ed8bff13Scaoming.roy 
72ed8bff13Scaoming.roy // Construct a map from symbols to their stringified representations.
73ed8bff13Scaoming.roy // Demangling symbols (which is what toString() does) is slow, so
74ed8bff13Scaoming.roy // we do that in batch using parallel-for.
75427d3597SGreg McGary static DenseMap<Symbol *, std::string>
getSymbolStrings(ArrayRef<Defined * > syms)76ed8bff13Scaoming.roy getSymbolStrings(ArrayRef<Defined *> syms) {
77ed8bff13Scaoming.roy   std::vector<std::string> str(syms.size());
78*7effcbdaSNico Weber   parallelFor(0, syms.size(), [&](size_t i) {
79ed8bff13Scaoming.roy     raw_string_ostream os(str[i]);
804f2c46c3SRoger Kim     Defined *sym = syms[i];
814f2c46c3SRoger Kim 
824f2c46c3SRoger Kim     switch (sym->isec->kind()) {
834f2c46c3SRoger Kim     case InputSection::CStringLiteralKind: {
844f2c46c3SRoger Kim       // Output "literal string: <string literal>"
854f2c46c3SRoger Kim       const auto *isec = cast<CStringInputSection>(sym->isec);
864f2c46c3SRoger Kim       const StringPiece &piece = isec->getStringPiece(sym->value);
874f2c46c3SRoger Kim       assert(
884f2c46c3SRoger Kim           sym->value == piece.inSecOff &&
894f2c46c3SRoger Kim           "We expect symbols to always point to the start of a StringPiece.");
904f2c46c3SRoger Kim       StringRef str = isec->getStringRef(&piece - &(*isec->pieces.begin()));
914f2c46c3SRoger Kim       assert(str.back() == '\000');
924f2c46c3SRoger Kim       (os << "literal string: ")
934f2c46c3SRoger Kim           // Remove null sequence at the end
944f2c46c3SRoger Kim           .write_escaped(str.substr(0, str.size() - 1));
954f2c46c3SRoger Kim       break;
964f2c46c3SRoger Kim     }
974f2c46c3SRoger Kim     case InputSection::ConcatKind:
984f2c46c3SRoger Kim     case InputSection::WordLiteralKind:
994f2c46c3SRoger Kim       os << toString(*sym);
1004f2c46c3SRoger Kim     }
101ed8bff13Scaoming.roy   });
102ed8bff13Scaoming.roy 
103427d3597SGreg McGary   DenseMap<Symbol *, std::string> ret;
104ed8bff13Scaoming.roy   for (size_t i = 0, e = syms.size(); i < e; ++i)
105ed8bff13Scaoming.roy     ret[syms[i]] = std::move(str[i]);
106ed8bff13Scaoming.roy   return ret;
107ed8bff13Scaoming.roy }
108ed8bff13Scaoming.roy 
writeMapFile()109ed8bff13Scaoming.roy void macho::writeMapFile() {
110ed8bff13Scaoming.roy   if (config->mapFile.empty())
111ed8bff13Scaoming.roy     return;
112ed8bff13Scaoming.roy 
1134bcaafebSJez Ng   TimeTraceScope timeScope("Write map file");
1144bcaafebSJez Ng 
115ed8bff13Scaoming.roy   // Open a map file for writing.
116ed8bff13Scaoming.roy   std::error_code ec;
117ed8bff13Scaoming.roy   raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
118ed8bff13Scaoming.roy   if (ec) {
119ed8bff13Scaoming.roy     error("cannot open " + config->mapFile + ": " + ec.message());
120ed8bff13Scaoming.roy     return;
121ed8bff13Scaoming.roy   }
122ed8bff13Scaoming.roy 
123742f6637SNico Weber   // Dump output path.
124ed8bff13Scaoming.roy   os << format("# Path: %s\n", config->outputFile.str().c_str());
125ed8bff13Scaoming.roy 
126742f6637SNico Weber   // Dump output architecture.
127ed4a4e33SJez Ng   os << format("# Arch: %s\n",
128ed4a4e33SJez Ng                getArchitectureName(config->arch()).str().c_str());
129ed8bff13Scaoming.roy 
130742f6637SNico Weber   // Dump table of object files.
131ed8bff13Scaoming.roy   os << "# Object files:\n";
132ed8bff13Scaoming.roy   os << format("[%3u] %s\n", 0, (const char *)"linker synthesized");
133ed8bff13Scaoming.roy   uint32_t fileIndex = 1;
134ed8bff13Scaoming.roy   DenseMap<lld::macho::InputFile *, uint32_t> readerToFileOrdinal;
135ed8bff13Scaoming.roy   for (InputFile *file : inputFiles) {
136ed8bff13Scaoming.roy     if (isa<ObjFile>(file)) {
137ed8bff13Scaoming.roy       os << format("[%3u] %s\n", fileIndex, file->getName().str().c_str());
138ed8bff13Scaoming.roy       readerToFileOrdinal[file] = fileIndex++;
139ed8bff13Scaoming.roy     }
140ed8bff13Scaoming.roy   }
141ed8bff13Scaoming.roy 
142ed8bff13Scaoming.roy   // Dump table of sections
143ed8bff13Scaoming.roy   os << "# Sections:\n";
144ed8bff13Scaoming.roy   os << "# Address\tSize    \tSegment\tSection\n";
145ed8bff13Scaoming.roy   for (OutputSegment *seg : outputSegments)
146ed8bff13Scaoming.roy     for (OutputSection *osec : seg->getSections()) {
147ed8bff13Scaoming.roy       if (osec->isHidden())
148ed8bff13Scaoming.roy         continue;
149ed8bff13Scaoming.roy 
150ed8bff13Scaoming.roy       os << format("0x%08llX\t0x%08llX\t%s\t%s\n", osec->addr, osec->getSize(),
151ed8bff13Scaoming.roy                    seg->name.str().c_str(), osec->name.str().c_str());
152ed8bff13Scaoming.roy     }
153ed8bff13Scaoming.roy 
154ed8bff13Scaoming.roy   // Dump table of symbols
15542208433SRoger Kim   Symbols liveSymbols, deadSymbols;
15642208433SRoger Kim   std::tie(liveSymbols, deadSymbols) = getSymbols();
15742208433SRoger Kim 
15842208433SRoger Kim   DenseMap<Symbol *, std::string> liveSymbolStrings =
15942208433SRoger Kim       getSymbolStrings(liveSymbols);
160ed8bff13Scaoming.roy   os << "# Symbols:\n";
161ed8bff13Scaoming.roy   os << "# Address\t    File  Name\n";
16242208433SRoger Kim   for (Symbol *sym : liveSymbols) {
16342208433SRoger Kim     assert(sym->isLive());
164ed8bff13Scaoming.roy     os << format("0x%08llX\t[%3u] %s\n", sym->getVA(),
16542208433SRoger Kim                  readerToFileOrdinal[sym->getFile()],
16642208433SRoger Kim                  liveSymbolStrings[sym].c_str());
167ed8bff13Scaoming.roy   }
168ed8bff13Scaoming.roy 
16942208433SRoger Kim   if (config->deadStrip) {
17042208433SRoger Kim     DenseMap<Symbol *, std::string> deadSymbolStrings =
17142208433SRoger Kim         getSymbolStrings(deadSymbols);
17242208433SRoger Kim     os << "# Dead Stripped Symbols:\n";
17342208433SRoger Kim     os << "# Address\t    File  Name\n";
17442208433SRoger Kim     for (Symbol *sym : deadSymbols) {
17542208433SRoger Kim       assert(!sym->isLive());
17642208433SRoger Kim       os << format("<<dead>>\t[%3u] %s\n", readerToFileOrdinal[sym->getFile()],
17742208433SRoger Kim                    deadSymbolStrings[sym].c_str());
17842208433SRoger Kim     }
17942208433SRoger Kim   }
180ed8bff13Scaoming.roy }
181