aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lld/MachO/SyntheticSections.cpp')
-rw-r--r--lld/MachO/SyntheticSections.cpp104
1 files changed, 100 insertions, 4 deletions
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 5d603d6f90d3..feaa4b5d3e22 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -20,7 +20,9 @@
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/LEB128.h"
+#include "llvm/Support/Path.h"
using namespace llvm;
using namespace llvm::support;
@@ -574,17 +576,100 @@ SymtabSection::SymtabSection(StringTableSection &stringTableSection)
stringTableSection(stringTableSection) {}
uint64_t SymtabSection::getRawSize() const {
- return symbols.size() * sizeof(structs::nlist_64);
+ return getNumSymbols() * sizeof(structs::nlist_64);
+}
+
+void SymtabSection::emitBeginSourceStab(DWARFUnit *compileUnit) {
+ StabsEntry stab(MachO::N_SO);
+ SmallString<261> dir(compileUnit->getCompilationDir());
+ StringRef sep = sys::path::get_separator();
+ // We don't use `path::append` here because we want an empty `dir` to result
+ // in an absolute path. `append` would give us a relative path for that case.
+ if (!dir.endswith(sep))
+ dir += sep;
+ stab.strx = stringTableSection.addString(
+ saver.save(dir + compileUnit->getUnitDIE().getShortName()));
+ stabs.emplace_back(std::move(stab));
+}
+
+void SymtabSection::emitEndSourceStab() {
+ StabsEntry stab(MachO::N_SO);
+ stab.sect = 1;
+ stabs.emplace_back(std::move(stab));
+}
+
+void SymtabSection::emitObjectFileStab(ObjFile *file) {
+ StabsEntry stab(MachO::N_OSO);
+ stab.sect = target->cpuSubtype;
+ SmallString<261> path(file->getName());
+ std::error_code ec = sys::fs::make_absolute(path);
+ if (ec)
+ fatal("failed to get absolute path for " + file->getName());
+
+ stab.strx = stringTableSection.addString(saver.save(path.str()));
+ stab.desc = 1;
+ stabs.emplace_back(std::move(stab));
+}
+
+void SymtabSection::emitFunStabs(Defined *defined) {
+ {
+ StabsEntry stab(MachO::N_FUN);
+ stab.sect = 1;
+ stab.strx = stringTableSection.addString(defined->getName());
+ stab.value = defined->getVA();
+ stabs.emplace_back(std::move(stab));
+ }
+
+ {
+ StabsEntry stab(MachO::N_FUN);
+ // FIXME this should be the size of the symbol. Using the section size in
+ // lieu is only correct if .subsections_via_symbols is set.
+ stab.value = defined->isec->getSize();
+ stabs.emplace_back(std::move(stab));
+ }
}
void SymtabSection::finalizeContents() {
- // TODO support other symbol types
+ InputFile *lastFile = nullptr;
for (Symbol *sym : symtab->getSymbols()) {
+ // TODO support other symbol types
if (isa<Defined>(sym) || sym->isInGot() || sym->isInStubs()) {
sym->symtabIndex = symbols.size();
symbols.push_back({sym, stringTableSection.addString(sym->getName())});
}
+
+ // Emit STABS symbols so that dsymutil and/or the debugger can map address
+ // regions in the final binary to the source and object files from which
+ // they originated.
+ if (auto *defined = dyn_cast<Defined>(sym)) {
+ if (defined->isAbsolute())
+ continue;
+
+ InputSection *isec = defined->isec;
+ // XXX is it right to assume that all symbols in __text are function
+ // symbols?
+ if (isec->name == "__text") {
+ ObjFile *file = dyn_cast<ObjFile>(isec->file);
+ assert(file);
+ if (!file->compileUnit)
+ continue;
+
+ if (lastFile == nullptr || lastFile != file) {
+ if (lastFile != nullptr)
+ emitEndSourceStab();
+ lastFile = file;
+
+ emitBeginSourceStab(file->compileUnit);
+ emitObjectFileStab(file);
+ }
+ emitFunStabs(defined);
+ }
+ // TODO emit stabs for non-function symbols too
+ }
}
+
+ if (!stabs.empty())
+ emitEndSourceStab();
}
void SymtabSection::writeTo(uint8_t *buf) const {
@@ -602,12 +687,23 @@ void SymtabSection::writeTo(uint8_t *buf) const {
nList->n_type = MachO::N_EXT | MachO::N_SECT;
nList->n_sect = defined->isec->parent->index;
// For the N_SECT symbol type, n_value is the address of the symbol
- nList->n_value = defined->value + defined->isec->getVA();
+ nList->n_value = defined->getVA();
}
nList->n_desc |= defined->isWeakDef() ? MachO::N_WEAK_DEF : 0;
}
++nList;
}
+
+ // Emit the stabs entries after the "real" symbols. We cannot emit them
+ // before as that would render Symbol::symtabIndex inaccurate.
+ for (const StabsEntry &entry : stabs) {
+ nList->n_strx = entry.strx;
+ nList->n_type = entry.type;
+ nList->n_sect = entry.sect;
+ nList->n_desc = entry.desc;
+ nList->n_value = entry.value;
+ ++nList;
+ }
}
IndirectSymtabSection::IndirectSymtabSection()
@@ -656,7 +752,7 @@ StringTableSection::StringTableSection()
uint32_t StringTableSection::addString(StringRef str) {
uint32_t strx = size;
- strings.push_back(str);
+ strings.push_back(str); // TODO: consider deduplicating strings
size += str.size() + 1; // account for null terminator
return strx;
}