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