#include "MapFile.h"
#include "Config.h"
#include "InputFiles.h"
#include "InputSection.h"
#include "OutputSection.h"
#include "OutputSegment.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
using namespace llvm::sys;
using namespace lld;
using namespace lld::macho;
using Symbols = std::vector<Defined *>;
static std::pair<Symbols, Symbols> getSymbols() {
Symbols liveSymbols, deadSymbols;
for (InputFile *file : inputFiles)
if (isa<ObjFile>(file))
for (Symbol *sym : file->symbols)
if (auto *d = dyn_cast_or_null<Defined>(sym))
if (d->isec && d->getFile() == file) {
if (d->isLive()) {
assert(!shouldOmitFromOutput(d->isec));
liveSymbols.push_back(d);
} else {
deadSymbols.push_back(d);
}
}
parallelSort(liveSymbols.begin(), liveSymbols.end(),
[](Defined *a, Defined *b) {
return a->getVA() != b->getVA() ? a->getVA() < b->getVA()
: a->getName() < b->getName();
});
parallelSort(
deadSymbols.begin(), deadSymbols.end(),
[](Defined *a, Defined *b) { return a->getName() < b->getName(); });
return {std::move(liveSymbols), std::move(deadSymbols)};
}
static DenseMap<Symbol *, std::string>
getSymbolStrings(ArrayRef<Defined *> syms) {
std::vector<std::string> str(syms.size());
parallelFor(0, syms.size(), [&](size_t i) {
raw_string_ostream os(str[i]);
Defined *sym = syms[i];
switch (sym->isec->kind()) {
case InputSection::CStringLiteralKind: {
const auto *isec = cast<CStringInputSection>(sym->isec);
const StringPiece &piece = isec->getStringPiece(sym->value);
assert(
sym->value == piece.inSecOff &&
"We expect symbols to always point to the start of a StringPiece.");
StringRef str = isec->getStringRef(&piece - &(*isec->pieces.begin()));
assert(str.back() == '\000');
(os << "literal string: ")
.write_escaped(str.substr(0, str.size() - 1));
break;
}
case InputSection::ConcatKind:
case InputSection::WordLiteralKind:
os << toString(*sym);
}
});
DenseMap<Symbol *, std::string> ret;
for (size_t i = 0, e = syms.size(); i < e; ++i)
ret[syms[i]] = std::move(str[i]);
return ret;
}
void macho::writeMapFile() {
if (config->mapFile.empty())
return;
TimeTraceScope timeScope("Write map file");
std::error_code ec;
raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
if (ec) {
error("cannot open " + config->mapFile + ": " + ec.message());
return;
}
os << format("# Path: %s\n", config->outputFile.str().c_str());
os << format("# Arch: %s\n",
getArchitectureName(config->arch()).str().c_str());
os << "# Object files:\n";
os << format("[%3u] %s\n", 0, (const char *)"linker synthesized");
uint32_t fileIndex = 1;
DenseMap<lld::macho::InputFile *, uint32_t> readerToFileOrdinal;
for (InputFile *file : inputFiles) {
if (isa<ObjFile>(file)) {
os << format("[%3u] %s\n", fileIndex, file->getName().str().c_str());
readerToFileOrdinal[file] = fileIndex++;
}
}
os << "# Sections:\n";
os << "# Address\tSize \tSegment\tSection\n";
for (OutputSegment *seg : outputSegments)
for (OutputSection *osec : seg->getSections()) {
if (osec->isHidden())
continue;
os << format("0x%08llX\t0x%08llX\t%s\t%s\n", osec->addr, osec->getSize(),
seg->name.str().c_str(), osec->name.str().c_str());
}
Symbols liveSymbols, deadSymbols;
std::tie(liveSymbols, deadSymbols) = getSymbols();
DenseMap<Symbol *, std::string> liveSymbolStrings =
getSymbolStrings(liveSymbols);
os << "# Symbols:\n";
os << "# Address\t File Name\n";
for (Symbol *sym : liveSymbols) {
assert(sym->isLive());
os << format("0x%08llX\t[%3u] %s\n", sym->getVA(),
readerToFileOrdinal[sym->getFile()],
liveSymbolStrings[sym].c_str());
}
if (config->deadStrip) {
DenseMap<Symbol *, std::string> deadSymbolStrings =
getSymbolStrings(deadSymbols);
os << "# Dead Stripped Symbols:\n";
os << "# Address\t File Name\n";
for (Symbol *sym : deadSymbols) {
assert(!sym->isLive());
os << format("<<dead>>\t[%3u] %s\n", readerToFileOrdinal[sym->getFile()],
deadSymbolStrings[sym].c_str());
}
}
}