diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:19:15 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:19:15 +0000 |
commit | d93e1dfac8711cfed1a9d9cd1876a788b83945cd (patch) | |
tree | 5896fa6c02a262a6148b215487e545d937de58b7 /lib | |
parent | 8d43286d630f9224de07809ea253e83ebb9cdee6 (diff) | |
download | src-d93e1dfac8711cfed1a9d9cd1876a788b83945cd.tar.gz src-d93e1dfac8711cfed1a9d9cd1876a788b83945cd.zip |
Vendor import of lld trunk r290819:vendor/lld/lld-trunk-r290819
Notes
Notes:
svn path=/vendor/lld/dist/; revision=311125
svn path=/vendor/lld/lld-trunk-r290819/; revision=311126; tag=vendor/lld/lld-trunk-r290819
Diffstat (limited to 'lib')
36 files changed, 1102 insertions, 361 deletions
diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp index 60687b9d8940..25544756f8be 100644 --- a/lib/Config/Version.cpp +++ b/lib/Config/Version.cpp @@ -12,46 +12,32 @@ //===----------------------------------------------------------------------===// #include "lld/Config/Version.h" -#include "llvm/Support/raw_ostream.h" using namespace llvm; -namespace lld { - -StringRef getLLDRepositoryPath() { -#ifdef LLD_REPOSITORY_STRING - return LLD_REPOSITORY_STRING; -#else - return ""; -#endif +// Returns an SVN repository path, which is usually "trunk". +static std::string getRepositoryPath() { + StringRef S = LLD_REPOSITORY_STRING; + size_t Pos = S.find("lld/"); + if (Pos != StringRef::npos) + return S.substr(Pos + 4); + return S; } -StringRef getLLDRevision() { -#ifdef LLD_REVISION_STRING - return LLD_REVISION_STRING; -#else - return ""; -#endif -} +// Returns an SVN repository name, e.g., " (trunk 284614)" +// or an empty string if no repository info is available. +static std::string getRepository() { + std::string Repo = getRepositoryPath(); + std::string Rev = LLD_REVISION_STRING; -std::string getLLDRepositoryVersion() { - std::string S = getLLDRepositoryPath(); - std::string T = getLLDRevision(); - if (S.empty() && T.empty()) + if (Repo.empty() && Rev.empty()) return ""; - if (!S.empty() && !T.empty()) - return "(" + S + " " + T + ")"; - if (!S.empty()) - return "(" + S + ")"; - return "(" + T + ")"; + if (!Repo.empty() && !Rev.empty()) + return " (" + Repo + " " + Rev + ")"; + return " (" + Repo + Rev + ")"; } -StringRef getLLDVersion() { -#ifdef LLD_VERSION_STRING - return LLD_VERSION_STRING; -#else - return ""; -#endif +// Returns a version string, e.g., "LLD 4.0 (lld/trunk 284614)". +std::string lld::getLLDVersion() { + return "LLD " + std::string(LLD_VERSION_STRING) + getRepository(); } - -} // end namespace lld diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt index 41e0e7661b9c..d89ca4a63d72 100644 --- a/lib/Core/CMakeLists.txt +++ b/lib/Core/CMakeLists.txt @@ -4,6 +4,7 @@ add_lld_library(lldCore File.cpp LinkingContext.cpp Reader.cpp + Reproduce.cpp Resolver.cpp SymbolTable.cpp Writer.cpp diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp index 8dc4d4a16f96..177cae7fcbf0 100644 --- a/lib/Core/DefinedAtom.cpp +++ b/lib/Core/DefinedAtom.cpp @@ -79,16 +79,4 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { llvm_unreachable("unknown content type"); } -bool DefinedAtom::compareByPosition(const DefinedAtom *lhs, - const DefinedAtom *rhs) { - if (lhs == rhs) - return false; - const File *lhsFile = &lhs->file(); - const File *rhsFile = &rhs->file(); - if (lhsFile->ordinal() != rhsFile->ordinal()) - return lhsFile->ordinal() < rhsFile->ordinal(); - assert(lhs->ordinal() != rhs->ordinal()); - return lhs->ordinal() < rhs->ordinal(); -} - } // namespace diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp index 4df1ce120bd9..6fc76f7ca3d0 100644 --- a/lib/Core/Error.cpp +++ b/lib/Core/Error.cpp @@ -16,9 +16,10 @@ using namespace lld; +namespace { class _YamlReaderErrorCategory : public std::error_category { public: - const char* name() const LLVM_NOEXCEPT override { + const char* name() const noexcept override { return "lld.yaml.reader"; } @@ -33,6 +34,7 @@ public: "message defined."); } }; +} // end anonymous namespace const std::error_category &lld::YamlReaderCategory() { static _YamlReaderErrorCategory o; @@ -48,7 +50,7 @@ class dynamic_error_category : public std::error_category { public: ~dynamic_error_category() override = default; - const char *name() const LLVM_NOEXCEPT override { + const char *name() const noexcept override { return "lld.dynamic_error"; } diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp index b84132bfecd5..30ded091a92a 100644 --- a/lib/Core/File.cpp +++ b/lib/Core/File.cpp @@ -8,12 +8,11 @@ //===----------------------------------------------------------------------===// #include "lld/Core/File.h" -#include "lld/Core/LLVM.h" #include <mutex> namespace lld { -File::~File() { } +File::~File() = default; File::AtomVector<DefinedAtom> File::_noDefinedAtoms; File::AtomVector<UndefinedAtom> File::_noUndefinedAtoms; @@ -27,4 +26,4 @@ std::error_code File::parse() { return _lastError.getValue(); } -} // namespace lld +} // end namespace lld diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp index 2732543d306e..5de863aa7f37 100644 --- a/lib/Core/LinkingContext.cpp +++ b/lib/Core/LinkingContext.cpp @@ -8,16 +8,17 @@ //===----------------------------------------------------------------------===// #include "lld/Core/LinkingContext.h" -#include "lld/Core/Resolver.h" +#include "lld/Core/File.h" +#include "lld/Core/Node.h" #include "lld/Core/Simple.h" #include "lld/Core/Writer.h" -#include "llvm/ADT/Triple.h" +#include <algorithm> namespace lld { -LinkingContext::LinkingContext() {} +LinkingContext::LinkingContext() = default; -LinkingContext::~LinkingContext() {} +LinkingContext::~LinkingContext() = default; bool LinkingContext::validate(raw_ostream &diagnostics) { return validateImpl(diagnostics); @@ -59,7 +60,7 @@ LinkingContext::createUndefinedSymbolFile(StringRef filename) const { } void LinkingContext::createInternalFiles( - std::vector<std::unique_ptr<File> > &result) const { + std::vector<std::unique_ptr<File>> &result) const { if (std::unique_ptr<File> file = createEntrySymbolFile()) result.push_back(std::move(file)); if (std::unique_ptr<File> file = createUndefinedSymbolFile()) diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp index 107db07891da..24652abec688 100644 --- a/lib/Core/Reader.cpp +++ b/lib/Core/Reader.cpp @@ -7,18 +7,19 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/File.h" #include "lld/Core/Reader.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Errc.h" -#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include <algorithm> #include <memory> -#include <system_error> namespace lld { -YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() {} +YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default; void Registry::add(std::unique_ptr<Reader> reader) { _readers.push_back(std::move(reader)); @@ -63,7 +64,6 @@ bool Registry::handleTaggedDoc(llvm::yaml::IO &io, return false; } - void Registry::addKindTable(Reference::KindNamespace ns, Reference::KindArch arch, const KindStrings array[]) { diff --git a/lib/Core/Reproduce.cpp b/lib/Core/Reproduce.cpp new file mode 100644 index 000000000000..39b0e41c44e5 --- /dev/null +++ b/lib/Core/Reproduce.cpp @@ -0,0 +1,128 @@ +//===- Reproduce.cpp - Utilities for creating reproducers -----------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Reproduce.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Option/Arg.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Path.h" + +using namespace lld; +using namespace llvm; +using namespace sys; + +CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S) + : OS(std::move(OS)), Basename(S) {} + +ErrorOr<CpioFile *> CpioFile::create(StringRef OutputPath) { + std::string Path = (OutputPath + ".cpio").str(); + std::error_code EC; + auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None); + if (EC) + return EC; + return new CpioFile(std::move(OS), path::filename(OutputPath)); +} + +static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) { + // The c_dev/c_ino pair should be unique according to the spec, + // but no one seems to care. + OS << "070707"; // c_magic + OS << "000000"; // c_dev + OS << "000000"; // c_ino + OS << "100664"; // c_mode: C_ISREG | rw-rw-r-- + OS << "000000"; // c_uid + OS << "000000"; // c_gid + OS << "000001"; // c_nlink + OS << "000000"; // c_rdev + OS << "00000000000"; // c_mtime + OS << format("%06o", Path.size() + 1); // c_namesize + OS << format("%011o", Data.size()); // c_filesize + OS << Path << '\0'; // c_name + OS << Data; // c_filedata +} + +void CpioFile::append(StringRef Path, StringRef Data) { + if (!Seen.insert(Path).second) + return; + + // Construct an in-archive filename so that /home/foo/bar is stored + // as baz/home/foo/bar where baz is the basename of the output file. + // (i.e. in that case we are creating baz.cpio.) + SmallString<128> Fullpath; + path::append(Fullpath, Basename, Path); + + writeMember(*OS, convertToUnixPathSeparator(Fullpath), Data); + + // Print the trailer and seek back. + // This way we have a valid archive if we crash. + uint64_t Pos = OS->tell(); + writeMember(*OS, "TRAILER!!!", ""); + OS->seek(Pos); +} + +// Makes a given pathname an absolute path first, and then remove +// beginning /. For example, "../foo.o" is converted to "home/john/foo.o", +// assuming that the current directory is "/home/john/bar". +// Returned string is a forward slash separated path even on Windows to avoid +// a mess with backslash-as-escape and backslash-as-path-separator. +std::string lld::relativeToRoot(StringRef Path) { + SmallString<128> Abs = Path; + if (sys::fs::make_absolute(Abs)) + return Path; + path::remove_dots(Abs, /*remove_dot_dot=*/true); + + // This is Windows specific. root_name() returns a drive letter + // (e.g. "c:") or a UNC name (//net). We want to keep it as part + // of the result. + SmallString<128> Res; + StringRef Root = path::root_name(Abs); + if (Root.endswith(":")) + Res = Root.drop_back(); + else if (Root.startswith("//")) + Res = Root.substr(2); + + path::append(Res, path::relative_path(Abs)); + return convertToUnixPathSeparator(Res); +} + +// Quote a given string if it contains a space character. +std::string lld::quote(StringRef S) { + if (S.find(' ') == StringRef::npos) + return S; + return ("\"" + S + "\"").str(); +} + +std::string lld::rewritePath(StringRef S) { + if (fs::exists(S)) + return relativeToRoot(S); + return S; +} + +std::string lld::stringize(opt::Arg *Arg) { + std::string K = Arg->getSpelling(); + if (Arg->getNumValues() == 0) + return K; + std::string V = quote(Arg->getValue()); + if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) + return K + V; + return K + " " + V; +} + +std::string lld::convertToUnixPathSeparator(StringRef S) { +#ifdef LLVM_ON_WIN32 + std::string Ret = S.str(); + std::replace(Ret.begin(), Ret.end(), '\\', '/'); + return Ret; +#else + return S; +#endif +} diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp index ef694fd972fc..e7cfaaac7835 100644 --- a/lib/Core/Resolver.cpp +++ b/lib/Core/Resolver.cpp @@ -100,7 +100,7 @@ llvm::Error Resolver::handleSharedLibrary(File &file) { if (auto ec = undefAddedOrError.takeError()) return ec; - return llvm::Error(); + return llvm::Error::success(); } bool Resolver::doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom) { diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp index 44631a5d40dc..cacea5f30847 100644 --- a/lib/Core/SymbolTable.cpp +++ b/lib/Core/SymbolTable.cpp @@ -223,13 +223,9 @@ bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l, const DefinedAtom * const r) { if (l == r) return true; - if (l == getEmptyKey()) + if (l == getEmptyKey() || r == getEmptyKey()) return false; - if (r == getEmptyKey()) - return false; - if (l == getTombstoneKey()) - return false; - if (r == getTombstoneKey()) + if (l == getTombstoneKey() || r == getTombstoneKey()) return false; if (l->contentType() != r->contentType()) return false; @@ -265,17 +261,6 @@ const Atom *SymbolTable::findByName(StringRef sym) { return pos->second; } -bool SymbolTable::isDefined(StringRef sym) { - if (const Atom *atom = findByName(sym)) - return !isa<UndefinedAtom>(atom); - return false; -} - -void SymbolTable::addReplacement(const Atom *replaced, - const Atom *replacement) { - _replacedAtoms[replaced] = replacement; -} - const Atom *SymbolTable::replacement(const Atom *atom) { // Find the replacement for a given atom. Atoms in _replacedAtoms // may be chained, so find the last one. @@ -303,17 +288,4 @@ std::vector<const UndefinedAtom *> SymbolTable::undefines() { return ret; } -std::vector<StringRef> SymbolTable::tentativeDefinitions() { - std::vector<StringRef> ret; - for (auto entry : _nameTable) { - const Atom *atom = entry.second; - StringRef name = entry.first; - assert(atom != nullptr); - if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) - if (defAtom->merge() == DefinedAtom::mergeAsTentative) - ret.push_back(name); - } - return ret; -} - } // namespace lld diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp index 93e6438a28f5..51f95bc5053a 100644 --- a/lib/Core/Writer.cpp +++ b/lib/Core/Writer.cpp @@ -7,13 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/File.h" #include "lld/Core/Writer.h" namespace lld { -Writer::Writer() { -} -Writer::~Writer() { -} +Writer::Writer() = default; + +Writer::~Writer() = default; + } // end namespace lld diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp index 496b651bab4f..9b4aede19aa2 100644 --- a/lib/Driver/DarwinLdDriver.cpp +++ b/lib/Driver/DarwinLdDriver.cpp @@ -14,24 +14,45 @@ //===----------------------------------------------------------------------===// #include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/Error.h" #include "lld/Core/File.h" #include "lld/Core/Instrumentation.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/Node.h" #include "lld/Core/PassManager.h" #include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryFile.h" -#include "lld/Driver/Driver.h" +#include "lld/Core/Simple.h" +#include "lld/Core/LinkingContext.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Triple.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" #include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MachO.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdint> +#include <memory> +#include <string> +#include <system_error> +#include <utility> +#include <vector> using namespace lld; @@ -116,7 +137,7 @@ loadFile(MachOLinkingContext &ctx, StringRef path, return files; } -} // anonymous namespace +} // end anonymous namespace // Test may be running on Windows. Canonicalize the path // separator to '/' to get consistent outputs for tests. @@ -166,8 +187,6 @@ static std::error_code parseExportsList(StringRef exportFilePath, return std::error_code(); } - - /// Order files are one symbol per line. Blank lines are ignored. /// Trailing comments start with #. Symbol names can be prefixed with an /// architecture name and/or .o leaf name. Examples: @@ -270,7 +289,7 @@ static llvm::Error loadFileList(StringRef fileListPath, addFile(path, ctx, forceLoad, false, diagnostics); buffer = lineAndRest.second; } - return llvm::Error(); + return llvm::Error::success(); } /// Parse number assuming it is base 16, but allow 0x prefix. @@ -739,9 +758,10 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, } break; case MachOLinkingContext::OS::iOS_simulator: - if (pie->getOption().getID() == OPT_no_pie) + if (pie->getOption().getID() == OPT_no_pie) { diagnostics << "iOS simulator programs must be built PIE\n"; return false; + } break; case MachOLinkingContext::OS::unknown: break; @@ -759,7 +779,6 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, diagnostics << pie->getSpelling() << " can only used when linking main executables\n"; return false; - break; } } @@ -1136,6 +1155,18 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, return ctx.validate(diagnostics); } +static void createFiles(MachOLinkingContext &ctx, bool Implicit) { + std::vector<std::unique_ptr<File>> Files; + if (Implicit) + ctx.createImplicitFiles(Files); + else + ctx.createInternalFiles(Files); + for (auto i = Files.rbegin(), e = Files.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); + } +} + /// This is where the link is actually performed. bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { MachOLinkingContext ctx; @@ -1150,20 +1181,10 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { if (FileNode *node = dyn_cast<FileNode>(ie.get())) node->getFile()->parse(); - std::vector<std::unique_ptr<File>> internalFiles; - ctx.createInternalFiles(internalFiles); - for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); - } + createFiles(ctx, false /* Implicit */); - // Give target a chance to add files. - std::vector<std::unique_ptr<File>> implicitFiles; - ctx.createImplicitFiles(implicitFiles); - for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); - } + // Give target a chance to add files + createFiles(ctx, true /* Implicit */); // Give target a chance to postprocess input files. // Mach-O uses this chance to move all object files before library files. @@ -1211,5 +1232,6 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { return true; } -} // namespace mach_o -} // namespace lld + +} // end namespace mach_o +} // end namespace lld diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp index eb7e7fb1837b..799f947a8c82 100644 --- a/lib/ReaderWriter/FileArchive.cpp +++ b/lib/ReaderWriter/FileArchive.cpp @@ -52,9 +52,12 @@ public: Archive::Child c = member->second; // Don't return a member already returned - ErrorOr<StringRef> buf = c.getBuffer(); - if (!buf) + Expected<StringRef> buf = c.getBuffer(); + if (!buf) { + // TODO: Actually report errors helpfully. + consumeError(buf.takeError()); return nullptr; + } const char *memberStart = buf->data(); if (_membersInstantiated.count(memberStart)) return nullptr; @@ -76,7 +79,7 @@ public: parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { if (std::error_code ec = parse()) return ec; - llvm::Error err; + llvm::Error err = llvm::Error::success(); for (auto mf = _archive->child_begin(err), me = _archive->child_end(); mf != me; ++mf) { std::unique_ptr<File> file; @@ -119,7 +122,7 @@ public: protected: std::error_code doParse() override { // Make Archive object which will be owned by FileArchive object. - llvm::Error Err; + llvm::Error Err = llvm::Error::success(); _archive.reset(new Archive(_mb->getMemBufferRef(), Err)); if (Err) return errorToErrorCode(std::move(Err)); @@ -132,9 +135,9 @@ protected: private: std::error_code instantiateMember(Archive::Child member, std::unique_ptr<File> &result) const { - ErrorOr<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef(); - if (std::error_code ec = mbOrErr.getError()) - return ec; + Expected<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef(); + if (!mbOrErr) + return errorToErrorCode(mbOrErr.takeError()); llvm::MemoryBufferRef mb = mbOrErr.get(); std::string memberPath = (_archive->getFileName() + "(" + mb.getBufferIdentifier() + ")").str(); @@ -166,9 +169,9 @@ private: << _archive->getFileName() << "':\n"); for (const Archive::Symbol &sym : _archive->symbols()) { StringRef name = sym.getName(); - ErrorOr<Archive::Child> memberOrErr = sym.getMember(); - if (std::error_code ec = memberOrErr.getError()) - return ec; + Expected<Archive::Child> memberOrErr = sym.getMember(); + if (!memberOrErr) + return errorToErrorCode(memberOrErr.takeError()); Archive::Child member = memberOrErr.get(); DEBUG_WITH_TYPE("FileArchive", llvm::dbgs() diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp index 3286fe064535..7d1544854cf1 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -540,7 +540,7 @@ llvm::Error ArchHandler_arm::getReferenceInfo( // Instruction contains branch to addend. displacement = getDisplacementFromThumbBranch(instruction, fixupAddress); *addend = fixupAddress + 4 + displacement; - return llvm::Error(); + return llvm::Error::success(); case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4: // ex: bl _foo (and _foo is defined) if ((instruction & 0xD000F800) == 0x9000F000) @@ -563,7 +563,7 @@ llvm::Error ArchHandler_arm::getReferenceInfo( // reloc.value is target atom's address. Instruction contains branch // to atom+addend. *addend += (targetAddress - reloc.value); - return llvm::Error(); + return llvm::Error::success(); case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4: // ex: bl _foo (and _foo is undefined) if (((instruction & 0x0F000000) == 0x0A000000) @@ -576,7 +576,7 @@ llvm::Error ArchHandler_arm::getReferenceInfo( // Instruction contains branch to addend. displacement = getDisplacementFromArmBranch(instruction); *addend = fixupAddress + 8 + displacement; - return llvm::Error(); + return llvm::Error::success(); case ARM_RELOC_BR24 | rPcRel | rLength4: // ex: bl _foo (and _foo is defined) if (((instruction & 0x0F000000) == 0x0A000000) @@ -601,32 +601,32 @@ llvm::Error ArchHandler_arm::getReferenceInfo( // reloc.value is target atom's address. Instruction contains branch // to atom+addend. *addend += (targetAddress - reloc.value); - return llvm::Error(); + return llvm::Error::success(); case ARM_RELOC_VANILLA | rExtern | rLength4: // ex: .long _foo (and _foo is undefined) *kind = pointer32; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = instruction; - return llvm::Error(); + return llvm::Error::success(); case ARM_RELOC_VANILLA | rLength4: // ex: .long _foo (and _foo is defined) *kind = pointer32; if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend)) return ec; *addend = clearThumbBit((uint32_t) * addend, *target); - return llvm::Error(); + return llvm::Error::success(); case ARM_RELOC_VANILLA | rScattered | rLength4: // ex: .long _foo+a (and _foo is defined) *kind = pointer32; if (auto ec = atomFromAddress(0, reloc.value, target, addend)) return ec; *addend += (clearThumbBit(instruction, *target) - reloc.value); - return llvm::Error(); + return llvm::Error::success(); default: return llvm::make_error<GenericError>("unsupported arm relocation type"); } - return llvm::Error(); + return llvm::Error::success(); } llvm::Error @@ -847,7 +847,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, value = clearThumbBit(value, *target); int64_t ta = (int64_t) value - (toAddress - fromAddress); *addend = ta - offsetInFrom; - return llvm::Error(); + return llvm::Error::success(); } else { uint32_t sectIndex; if (thumbReloc) { @@ -895,7 +895,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, } } - return llvm::Error(); + return llvm::Error::success(); } void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc, diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp index a61f6aac05e1..392a1be5b3d0 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp @@ -275,8 +275,8 @@ const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = { // GOT pointer to dyld_stub_binder { Reference::KindArch::AArch64, pointer64, 0, 0 }, - // arm64 code alignment 2^2 - 2, + // arm64 code alignment 2^1 + 1, // Stub size and code 12, @@ -389,56 +389,56 @@ llvm::Error ArchHandler_arm64::getReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4: // ex: adrp x1, _foo@PAGE *kind = page21; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4: // ex: ldr x0, [x1, _foo@PAGEOFF] *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent); if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4: // ex: adrp x1, _foo@GOTPAGE *kind = gotPage21; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4: // ex: ldr x0, [x1, _foo@GOTPAGEOFF] *kind = gotOffset12; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4: // ex: adrp x1, _foo@TLVPAGE *kind = tlvPage21; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4: // ex: ldr x0, [x1, _foo@TLVPAGEOFF] *kind = tlvOffset12; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_UNSIGNED | rExtern | rLength8: // ex: .quad _foo + N *kind = pointer64; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little64_t *)fixupContent; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_UNSIGNED | rLength8: // ex: .quad Lfoo + N *kind = pointer64; @@ -450,7 +450,7 @@ llvm::Error ArchHandler_arm64::getReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4: // ex: .long _foo@GOT - . @@ -464,7 +464,7 @@ llvm::Error ArchHandler_arm64::getReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return llvm::Error(); + return llvm::Error::success(); default: return llvm::make_error<GenericError>("unsupported arm64 relocation type"); } @@ -485,7 +485,7 @@ llvm::Error ArchHandler_arm64::getPairReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = reloc1.symbol; - return llvm::Error(); + return llvm::Error::success(); case ((ARM64_RELOC_ADDEND | rLength4) << 16 | ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4): // ex: adrp x1, _foo@PAGE @@ -493,7 +493,7 @@ llvm::Error ArchHandler_arm64::getPairReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = reloc1.symbol; - return llvm::Error(); + return llvm::Error::success(); case ((ARM64_RELOC_ADDEND | rLength4) << 16 | ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): { // ex: ldr w0, [x1, _foo@PAGEOFF] @@ -502,7 +502,7 @@ llvm::Error ArchHandler_arm64::getPairReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = reloc1.symbol; - return llvm::Error(); + return llvm::Error::success(); } case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | ARM64_RELOC_UNSIGNED | rExtern | rLength8): @@ -522,7 +522,7 @@ llvm::Error ArchHandler_arm64::getPairReferenceInfo( return llvm::make_error<GenericError>( "paired relocs must have the same offset"); *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom; - return llvm::Error(); + return llvm::Error::success(); case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | ARM64_RELOC_UNSIGNED | rExtern | rLength4): // ex: .quad _foo - . @@ -530,7 +530,7 @@ llvm::Error ArchHandler_arm64::getPairReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom; - return llvm::Error(); + return llvm::Error::success(); default: return llvm::make_error<GenericError>("unsupported arm64 relocation pair"); } diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp index 15f1f793b5d7..c940ea542ee4 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp @@ -345,7 +345,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc, default: return llvm::make_error<GenericError>("unsupported i386 relocation type"); } - return llvm::Error(); + return llvm::Error::success(); } llvm::Error @@ -403,7 +403,7 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, *addend = fromAddress + value - toAddress; } } - return llvm::Error(); + return llvm::Error::success(); break; default: return llvm::make_error<GenericError>("unsupported i386 relocation type"); diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index c36982a77b13..d687ca5de5b4 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -382,22 +382,22 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little32_t *)fixupContent; - return llvm::Error(); + return llvm::Error::success(); case ripRel32Minus1: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 1; - return llvm::Error(); + return llvm::Error::success(); case ripRel32Minus2: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 2; - return llvm::Error(); + return llvm::Error::success(); case ripRel32Minus4: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 4; - return llvm::Error(); + return llvm::Error::success(); case ripRel32Anon: targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); @@ -416,7 +416,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little32_t *)fixupContent; - return llvm::Error(); + return llvm::Error::success(); case tlvInitSectionOffset: case pointer64: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) @@ -429,7 +429,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, assert(*addend == 0 && "TLV-init has non-zero addend?"); } else *addend = *(const little64_t *)fixupContent; - return llvm::Error(); + return llvm::Error::success(); case pointer64Anon: targetAddress = *(const little64_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); @@ -463,7 +463,10 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, return ec; uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent; if (inAtom == fromTarget) { - *kind = delta64; + if (inAtom->contentType() == DefinedAtom::typeCFI) + *kind = unwindFDEToFunction; + else + *kind = delta64; *addend = encodedAddend + offsetInAtom; } else if (inAtom == *target) { *kind = negDelta64; @@ -471,7 +474,7 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, *target = fromTarget; } else return llvm::make_error<GenericError>("Invalid pointer diff"); - return llvm::Error(); + return llvm::Error::success(); } case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | X86_64_RELOC_UNSIGNED | rExtern | rLength4): { @@ -487,7 +490,7 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, *target = fromTarget; } else return llvm::make_error<GenericError>("Invalid pointer diff"); - return llvm::Error(); + return llvm::Error::success(); } case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | X86_64_RELOC_UNSIGNED | rLength8): diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt index 70f451c997b3..6a1064d6dfb5 100644 --- a/lib/ReaderWriter/MachO/CMakeLists.txt +++ b/lib/ReaderWriter/MachO/CMakeLists.txt @@ -21,8 +21,10 @@ add_lld_library(lldMachO LINK_LIBS lldCore lldYAML + LLVMDebugInfoDWARF LLVMObject LLVMSupport + LLVMDemangle ${PTHREAD_LIB} ) diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp index 6f5ab83dbda6..49d518456a45 100644 --- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp +++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp @@ -298,7 +298,7 @@ private: // Skip rest of pass if no unwind info. if (unwindLocs.empty() && dwarfFrames.empty()) - return llvm::Error(); + return llvm::Error::success(); // FIXME: if there are more than 4 personality functions then we need to // defer to DWARF info for the ones we don't put in the list. They should @@ -353,7 +353,7 @@ private: return atom->contentType() == DefinedAtom::typeCompactUnwindInfo; }); - return llvm::Error(); + return llvm::Error::success(); } void collectCompactUnwindEntries( diff --git a/lib/ReaderWriter/MachO/DebugInfo.h b/lib/ReaderWriter/MachO/DebugInfo.h new file mode 100644 index 000000000000..28e41bf4263c --- /dev/null +++ b/lib/ReaderWriter/MachO/DebugInfo.h @@ -0,0 +1,106 @@ +//===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_MACHO_DEBUGINFO_H +#define LLD_READER_WRITER_MACHO_DEBUGINFO_H + +#include "lld/Core/Atom.h" +#include <vector> + +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + + +namespace lld { +namespace mach_o { + +class DebugInfo { +public: + enum class Kind { + Dwarf, + Stabs + }; + + Kind kind() const { return _kind; } + + void setAllocator(std::unique_ptr<llvm::BumpPtrAllocator> allocator) { + _allocator = std::move(allocator); + } + +protected: + DebugInfo(Kind kind) : _kind(kind) {} + +private: + std::unique_ptr<llvm::BumpPtrAllocator> _allocator; + Kind _kind; +}; + +struct TranslationUnitSource { + StringRef name; + StringRef path; +}; + +class DwarfDebugInfo : public DebugInfo { +public: + DwarfDebugInfo(TranslationUnitSource tu) + : DebugInfo(Kind::Dwarf), _tu(std::move(tu)) {} + + static inline bool classof(const DebugInfo *di) { + return di->kind() == Kind::Dwarf; + } + + const TranslationUnitSource &translationUnitSource() const { return _tu; } + +private: + TranslationUnitSource _tu; +}; + +struct Stab { + Stab(const Atom* atom, uint8_t type, uint8_t other, uint16_t desc, + uint32_t value, StringRef str) + : atom(atom), type(type), other(other), desc(desc), value(value), + str(str) {} + + const class Atom* atom; + uint8_t type; + uint8_t other; + uint16_t desc; + uint32_t value; + StringRef str; +}; + +inline raw_ostream& operator<<(raw_ostream &os, Stab &s) { + os << "Stab -- atom: " << llvm::format("%p", s.atom) << ", type: " << (uint32_t)s.type + << ", other: " << (uint32_t)s.other << ", desc: " << s.desc << ", value: " << s.value + << ", str: '" << s.str << "'"; + return os; +} + +class StabsDebugInfo : public DebugInfo { +public: + + typedef std::vector<Stab> StabsList; + + StabsDebugInfo(StabsList stabs) + : DebugInfo(Kind::Stabs), _stabs(std::move(stabs)) {} + + static inline bool classof(const DebugInfo *di) { + return di->kind() == Kind::Stabs; + } + + const StabsList& stabs() const { return _stabs; } + +public: + StabsList _stabs; +}; + +} // end namespace mach_o +} // end namespace lld + +#endif // LLD_READER_WRITER_MACHO_DEBUGINFO_H diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h index 64a0fcf82844..2bdd6342b477 100644 --- a/lib/ReaderWriter/MachO/File.h +++ b/lib/ReaderWriter/MachO/File.h @@ -11,11 +11,13 @@ #define LLD_READER_WRITER_MACHO_FILE_H #include "Atoms.h" +#include "DebugInfo.h" #include "MachONormalizedFile.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Core/Simple.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/Format.h" #include <unordered_map> namespace lld { @@ -25,11 +27,15 @@ using lld::mach_o::normalized::Section; class MachOFile : public SimpleFile { public: + + /// Real file constructor - for on-disk files. MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx) : SimpleFile(mb->getBufferIdentifier(), File::kindMachObject), _mb(std::move(mb)), _ctx(ctx) {} - MachOFile(StringRef path) : SimpleFile(path, File::kindMachObject) {} + /// Dummy file constructor - for virtual files. + MachOFile(StringRef path) + : SimpleFile(path, File::kindMachObject) {} void addDefinedAtom(StringRef name, Atom::Scope scope, DefinedAtom::ContentType type, DefinedAtom::Merge merge, @@ -225,6 +231,13 @@ public: return F->kind() == File::kindMachObject; } + void setDebugInfo(std::unique_ptr<DebugInfo> debugInfo) { + _debugInfo = std::move(debugInfo); + } + + DebugInfo* debugInfo() const { return _debugInfo.get(); } + std::unique_ptr<DebugInfo> takeDebugInfo() { return std::move(_debugInfo); } + protected: std::error_code doParse() override { // Convert binary file to normalized mach-o. @@ -265,6 +278,7 @@ private: MachOLinkingContext::objc_unknown; uint32_t _swiftVersion = 0; normalized::FileFlags _flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS; + std::unique_ptr<DebugInfo> _debugInfo; }; class MachODylibFile : public SharedLibraryFile { @@ -297,7 +311,7 @@ public: _reExportedDylibs.emplace_back(dylibPath); } - StringRef installName() { return _installName; } + StringRef installName() const { return _installName; } uint32_t currentVersion() { return _currentVersion; } uint32_t compatVersion() { return _compatVersion; } diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp index 6cdca0a9e055..8458a1c79282 100644 --- a/lib/ReaderWriter/MachO/GOTPass.cpp +++ b/lib/ReaderWriter/MachO/GOTPass.cpp @@ -134,7 +134,7 @@ private: for (const GOTEntryAtom *slot : entries) mergedFile.addAtom(*slot); - return llvm::Error(); + return llvm::Error::success(); } bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) { diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp index dd2ee8567ec9..24dbf79d3e3b 100644 --- a/lib/ReaderWriter/MachO/LayoutPass.cpp +++ b/lib/ReaderWriter/MachO/LayoutPass.cpp @@ -474,7 +474,7 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) { }); DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n"); - return llvm::Error(); + return llvm::Error::success(); } void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) { diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 05375f145d34..db4a96823e74 100644 --- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -22,7 +22,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" -#include "llvm/Config/config.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Host.h" @@ -30,10 +30,6 @@ #include "llvm/Support/Path.h" #include <algorithm> -#if defined(HAVE_CXXABI_H) -#include <cxxabi.h> -#endif - using lld::mach_o::ArchHandler; using lld::mach_o::MachOFile; using lld::mach_o::MachODylibFile; @@ -734,7 +730,7 @@ uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const { if (pos != _pathToDylibMap.end()) return pos->second->currentVersion(); else - return 0x1000; // 1.0 + return 0x10000; // 1.0 } uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const { @@ -742,7 +738,7 @@ uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const { if (pos != _pathToDylibMap.end()) return pos->second->compatVersion(); else - return 0x1000; // 1.0 + return 0x10000; // 1.0 } void MachOLinkingContext::createImplicitFiles( @@ -772,7 +768,10 @@ void MachOLinkingContext::createImplicitFiles( void MachOLinkingContext::registerDylib(MachODylibFile *dylib, bool upward) const { std::lock_guard<std::mutex> lock(_dylibsMutex); - _allDylibs.insert(dylib); + + if (std::find(_allDylibs.begin(), + _allDylibs.end(), dylib) == _allDylibs.end()) + _allDylibs.push_back(dylib); _pathToDylibMap[dylib->installName()] = dylib; // If path is different than install name, register path too. if (!dylib->path().equals(dylib->installName())) @@ -873,24 +872,32 @@ std::string MachOLinkingContext::demangle(StringRef symbolName) const { if (!symbolName.startswith("__Z")) return symbolName; -#if defined(HAVE_CXXABI_H) SmallString<256> symBuff; StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff); // Mach-O has extra leading underscore that needs to be removed. const char *cstr = nullTermSym.data() + 1; int status; - char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status); + char *demangled = llvm::itaniumDemangle(cstr, nullptr, nullptr, &status); if (demangled) { std::string result(demangled); // __cxa_demangle() always uses a malloc'ed buffer to return the result. free(demangled); return result; } -#endif return symbolName; } +static void addDependencyInfoHelper(llvm::raw_fd_ostream *DepInfo, + char Opcode, StringRef Path) { + if (!DepInfo) + return; + + *DepInfo << Opcode; + *DepInfo << Path; + *DepInfo << '\0'; +} + std::error_code MachOLinkingContext::createDependencyFile(StringRef path) { std::error_code ec; _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(new @@ -900,42 +907,20 @@ std::error_code MachOLinkingContext::createDependencyFile(StringRef path) { return ec; } - char linkerVersionOpcode = 0x00; - *_dependencyInfo << linkerVersionOpcode; - *_dependencyInfo << "lld"; // FIXME - *_dependencyInfo << '\0'; - + addDependencyInfoHelper(_dependencyInfo.get(), 0x00, "lld" /*FIXME*/); return std::error_code(); } void MachOLinkingContext::addInputFileDependency(StringRef path) const { - if (!_dependencyInfo) - return; - - char inputFileOpcode = 0x10; - *_dependencyInfo << inputFileOpcode; - *_dependencyInfo << path; - *_dependencyInfo << '\0'; + addDependencyInfoHelper(_dependencyInfo.get(), 0x10, path); } void MachOLinkingContext::addInputFileNotFound(StringRef path) const { - if (!_dependencyInfo) - return; - - char inputFileOpcode = 0x11; - *_dependencyInfo << inputFileOpcode; - *_dependencyInfo << path; - *_dependencyInfo << '\0'; + addDependencyInfoHelper(_dependencyInfo.get(), 0x11, path); } void MachOLinkingContext::addOutputFileDependency(StringRef path) const { - if (!_dependencyInfo) - return; - - char outputFileOpcode = 0x40; - *_dependencyInfo << outputFileOpcode; - *_dependencyInfo << path; - *_dependencyInfo << '\0'; + addDependencyInfoHelper(_dependencyInfo.get(), 0x40, path); } void MachOLinkingContext::appendOrderedSymbol(StringRef symbol, @@ -1044,7 +1029,7 @@ void MachOLinkingContext::finalizeInputFiles() { llvm::Error MachOLinkingContext::handleLoadedFile(File &file) { auto *machoFile = dyn_cast<MachOFile>(&file); if (!machoFile) - return llvm::Error(); + return llvm::Error::success(); // Check that the arch of the context matches that of the file. // Also set the arch of the context if it didn't have one. @@ -1111,7 +1096,7 @@ llvm::Error MachOLinkingContext::handleLoadedFile(File &file) { return llvm::make_error<GenericError>("different swift versions"); } - return llvm::Error(); + return llvm::Error::success(); } } // end namespace lld diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h index 92a21f7ef83d..60d76d4b5c9b 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFile.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -42,6 +42,7 @@ #ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H #define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H +#include "DebugInfo.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "lld/ReaderWriter/MachOLinkingContext.h" @@ -226,7 +227,6 @@ struct DataInCode { DataRegionType kind; }; - /// A typedef so that YAML I/O can encode/decode mach_header.flags. LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags) @@ -242,6 +242,7 @@ struct NormalizedFile { std::vector<Symbol> localSymbols; std::vector<Symbol> globalSymbols; std::vector<Symbol> undefinedSymbols; + std::vector<Symbol> stabsSymbols; // Maps to load commands with no LINKEDIT content (final linked images only). std::vector<DependentDylib> dependentDylibs; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index a17de5be1742..23c7ea17f7e7 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -70,12 +70,12 @@ static llvm::Error forEachLoadCommand( return llvm::make_error<GenericError>("Load command exceeds range"); if (func(slc->cmd, slc->cmdsize, p)) - return llvm::Error(); + return llvm::Error::success(); p += slc->cmdsize; } - return llvm::Error(); + return llvm::Error::success(); } static std::error_code appendRelocations(Relocations &relocs, StringRef buffer, @@ -390,12 +390,14 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, if (sin->n_strx > strSize) return true; sout.name = &strings[sin->n_strx]; - sout.type = (NListType)(sin->n_type & N_TYPE); + sout.type = static_cast<NListType>(sin->n_type & (N_STAB|N_TYPE)); sout.scope = (sin->n_type & (N_PEXT|N_EXT)); sout.sect = sin->n_sect; sout.desc = sin->n_desc; sout.value = sin->n_value; - if (sout.type == N_UNDF) + if (sin->n_type & N_STAB) + f->stabsSymbols.push_back(sout); + else if (sout.type == N_UNDF) f->undefinedSymbols.push_back(sout); else if (sin->n_type & N_EXT) f->globalSymbols.push_back(sout); @@ -429,6 +431,8 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, f->undefinedSymbols.push_back(sout); else if (sout.scope == (SymbolScope)N_EXT) f->globalSymbols.push_back(sout); + else if (sin->n_type & N_STAB) + f->stabsSymbols.push_back(sout); else f->localSymbols.push_back(sout); } @@ -535,7 +539,7 @@ public: loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry) const override { std::unique_ptr<File> ret = - llvm::make_unique<MachOFile>(std::move(mb), &_ctx); + llvm::make_unique<MachOFile>(std::move(mb), &_ctx); return std::move(ret); } diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h index 86823efa33c9..d69c5389e9d6 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h @@ -71,22 +71,19 @@ using llvm::sys::getSwappedBytes; template<typename T> static inline uint16_t read16(const T *loc, bool isBig) { - assert((uint64_t)loc % llvm::alignOf<T>() == 0 && - "invalid pointer alignment"); + assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); return isBig ? read16be(loc) : read16le(loc); } template<typename T> static inline uint32_t read32(const T *loc, bool isBig) { - assert((uint64_t)loc % llvm::alignOf<T>() == 0 && - "invalid pointer alignment"); + assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); return isBig ? read32be(loc) : read32le(loc); } template<typename T> static inline uint64_t read64(const T *loc, bool isBig) { - assert((uint64_t)loc % llvm::alignOf<T>() == 0 && - "invalid pointer alignment"); + assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); return isBig ? read64be(loc) : read64le(loc); } diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index f3e159684e15..e853faf9112e 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -66,26 +66,9 @@ struct TrieEdge : public llvm::ilist_node<TrieEdge> { namespace llvm { - using lld::mach_o::normalized::TrieEdge; - template <> - struct ilist_traits<TrieEdge> - : public ilist_default_traits<TrieEdge> { - private: - mutable ilist_half_node<TrieEdge> Sentinel; - public: - TrieEdge *createSentinel() const { - return static_cast<TrieEdge*>(&Sentinel); - } - void destroySentinel(TrieEdge *) const {} - - TrieEdge *provideInitialHead() const { return createSentinel(); } - TrieEdge *ensureHead(TrieEdge*) const { return createSentinel(); } - static void noteHead(TrieEdge*, TrieEdge*) {} - void deleteNode(TrieEdge *N) {} - - private: - void createNode(const TrieEdge &); - }; +using lld::mach_o::normalized::TrieEdge; +template <> +struct ilist_alloc_traits<TrieEdge> : ilist_noalloc_traits<TrieEdge> {}; } // namespace llvm @@ -103,6 +86,9 @@ struct TrieNode { void addSymbol(const Export &entry, BumpPtrAllocator &allocator, std::vector<TrieNode *> &allNodes); + + void addOrderedNodes(const Export &entry, + std::vector<TrieNode *> &allNodes); bool updateOffset(uint32_t &offset); void appendToByteBuffer(ByteBuffer &out); @@ -115,6 +101,7 @@ private: StringRef _importedName; uint32_t _trieOffset; bool _hasExportInfo; + bool _ordered = false; }; /// Utility class for writing a mach-o binary file given an in-memory @@ -639,7 +626,9 @@ llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) { seg->vmsize = _file.sections.back().address + _file.sections.back().content.size(); seg->fileoff = _endOfLoadCommands; - seg->filesize = seg->vmsize; + seg->filesize = _sectInfo[&_file.sections.back()].fileOffset + + _file.sections.back().content.size() - + _sectInfo[&_file.sections.front()].fileOffset; seg->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE; seg->initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE; seg->nsects = _file.sections.size(); @@ -668,7 +657,7 @@ llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) { ++sout; } lc = next; - return llvm::Error(); + return llvm::Error::success(); } template <typename T> @@ -738,7 +727,7 @@ llvm::Error MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) { } lc = reinterpret_cast<uint8_t*>(next); } - return llvm::Error(); + return llvm::Error::success(); } static void writeVersionMinLoadCommand(const NormalizedFile &_file, @@ -789,8 +778,8 @@ llvm::Error MachOFileLayout::writeLoadCommands() { st->cmd = LC_SYMTAB; st->cmdsize = sizeof(symtab_command); st->symoff = _startOfSymbols; - st->nsyms = _file.localSymbols.size() + _file.globalSymbols.size() - + _file.undefinedSymbols.size(); + st->nsyms = _file.stabsSymbols.size() + _file.localSymbols.size() + + _file.globalSymbols.size() + _file.undefinedSymbols.size(); st->stroff = _startOfSymbolStrings; st->strsize = _endOfSymbolStrings - _startOfSymbolStrings; if (_swap) @@ -876,8 +865,8 @@ llvm::Error MachOFileLayout::writeLoadCommands() { st->cmd = LC_SYMTAB; st->cmdsize = sizeof(symtab_command); st->symoff = _startOfSymbols; - st->nsyms = _file.localSymbols.size() + _file.globalSymbols.size() - + _file.undefinedSymbols.size(); + st->nsyms = _file.stabsSymbols.size() + _file.localSymbols.size() + + _file.globalSymbols.size() + _file.undefinedSymbols.size(); st->stroff = _startOfSymbolStrings; st->strsize = _endOfSymbolStrings - _startOfSymbolStrings; if (_swap) @@ -890,7 +879,8 @@ llvm::Error MachOFileLayout::writeLoadCommands() { dst->cmd = LC_DYSYMTAB; dst->cmdsize = sizeof(dysymtab_command); dst->ilocalsym = _symbolTableLocalsStartIndex; - dst->nlocalsym = _file.localSymbols.size(); + dst->nlocalsym = _file.stabsSymbols.size() + + _file.localSymbols.size(); dst->iextdefsym = _symbolTableGlobalsStartIndex; dst->nextdefsym = _file.globalSymbols.size(); dst->iundefsym = _symbolTableUndefinesStartIndex; @@ -1017,7 +1007,7 @@ llvm::Error MachOFileLayout::writeLoadCommands() { lc += sizeof(linkedit_data_command); } } - return llvm::Error(); + return llvm::Error::success(); } void MachOFileLayout::writeSectionContent() { @@ -1101,7 +1091,10 @@ void MachOFileLayout::writeSymbolTable() { // Write symbol table and symbol strings in parallel. uint32_t symOffset = _startOfSymbols; uint32_t strOffset = _startOfSymbolStrings; - _buffer[strOffset++] = '\0'; // Reserve n_strx offset of zero to mean no name. + // Reserve n_strx offset of zero to mean no name. + _buffer[strOffset++] = ' '; + _buffer[strOffset++] = '\0'; + appendSymbols(_file.stabsSymbols, symOffset, strOffset); appendSymbols(_file.localSymbols, symOffset, strOffset); appendSymbols(_file.globalSymbols, symOffset, strOffset); appendSymbols(_file.undefinedSymbols, symOffset, strOffset); @@ -1182,19 +1175,44 @@ void MachOFileLayout::buildRebaseInfo() { void MachOFileLayout::buildBindInfo() { // TODO: compress bind info. uint64_t lastAddend = 0; + int lastOrdinal = 0x80000000; + StringRef lastSymbolName; + BindType lastType = (BindType)0; + Hex32 lastSegOffset = ~0U; + uint8_t lastSegIndex = (uint8_t)~0U; for (const BindLocation& entry : _file.bindingInfo) { - _bindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind); - _bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB - | entry.segIndex); - _bindingInfo.append_uleb128(entry.segOffset); - if (entry.ordinal > 0) - _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | - (entry.ordinal & 0xF)); - else - _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | - (entry.ordinal & 0xF)); - _bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); - _bindingInfo.append_string(entry.symbolName); + if (entry.ordinal != lastOrdinal) { + if (entry.ordinal <= 0) + _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | + (entry.ordinal & BIND_IMMEDIATE_MASK)); + else if (entry.ordinal <= BIND_IMMEDIATE_MASK) + _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | + entry.ordinal); + else { + _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); + _bindingInfo.append_uleb128(entry.ordinal); + } + lastOrdinal = entry.ordinal; + } + + if (lastSymbolName != entry.symbolName) { + _bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); + _bindingInfo.append_string(entry.symbolName); + lastSymbolName = entry.symbolName; + } + + if (lastType != entry.kind) { + _bindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind); + lastType = entry.kind; + } + + if (lastSegIndex != entry.segIndex || lastSegOffset != entry.segOffset) { + _bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB + | entry.segIndex); + _bindingInfo.append_uleb128(entry.segOffset); + lastSegIndex = entry.segIndex; + lastSegOffset = entry.segOffset; + } if (entry.addend != lastAddend) { _bindingInfo.append_byte(BIND_OPCODE_SET_ADDEND_SLEB); _bindingInfo.append_sleb128(entry.addend); @@ -1208,22 +1226,25 @@ void MachOFileLayout::buildBindInfo() { void MachOFileLayout::buildLazyBindInfo() { for (const BindLocation& entry : _file.lazyBindingInfo) { - _lazyBindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind); _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | entry.segIndex); - _lazyBindingInfo.append_uleb128Fixed(entry.segOffset, 5); - if (entry.ordinal > 0) - _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | - (entry.ordinal & 0xF)); - else + _lazyBindingInfo.append_uleb128(entry.segOffset); + if (entry.ordinal <= 0) _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | - (entry.ordinal & 0xF)); + (entry.ordinal & BIND_IMMEDIATE_MASK)); + else if (entry.ordinal <= BIND_IMMEDIATE_MASK) + _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | + entry.ordinal); + else { + _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); + _lazyBindingInfo.append_uleb128(entry.ordinal); + } + // FIXME: We need to | the opcode here with flags. _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); _lazyBindingInfo.append_string(entry.symbolName); _lazyBindingInfo.append_byte(BIND_OPCODE_DO_BIND); _lazyBindingInfo.append_byte(BIND_OPCODE_DONE); } - _lazyBindingInfo.append_byte(BIND_OPCODE_DONE); _lazyBindingInfo.align(_is64 ? 8 : 4); } @@ -1287,6 +1308,24 @@ void TrieNode::addSymbol(const Export& entry, allNodes.push_back(newNode); } +void TrieNode::addOrderedNodes(const Export& entry, + std::vector<TrieNode*> &orderedNodes) { + if (!_ordered) { + orderedNodes.push_back(this); + _ordered = true; + } + + StringRef partialStr = entry.name.drop_front(_cummulativeString.size()); + for (TrieEdge &edge : _children) { + StringRef edgeStr = edge._subString; + if (partialStr.startswith(edgeStr)) { + // Already have matching edge, go down that path. + edge._child->addOrderedNodes(entry, orderedNodes); + return; + } + } +} + bool TrieNode::updateOffset(uint32_t& offset) { uint32_t nodeSize = 1; // Length when no export info if (_hasExportInfo) { @@ -1392,20 +1431,26 @@ void MachOFileLayout::buildExportTrie() { rootNode->addSymbol(entry, allocator, allNodes); } + std::vector<TrieNode*> orderedNodes; + orderedNodes.reserve(allNodes.size()); + + for (const Export& entry : _file.exportInfo) + rootNode->addOrderedNodes(entry, orderedNodes); + // Assign each node in the vector an offset in the trie stream, iterating // until all uleb128 sizes have stabilized. bool more; do { uint32_t offset = 0; more = false; - for (TrieNode* node : allNodes) { + for (TrieNode* node : orderedNodes) { if (node->updateOffset(offset)) more = true; } } while (more); // Serialize trie to ByteBuffer. - for (TrieNode* node : allNodes) { + for (TrieNode* node : orderedNodes) { node->appendToByteBuffer(_exportTrie); } _exportTrie.align(_is64 ? 8 : 4); @@ -1414,10 +1459,15 @@ void MachOFileLayout::buildExportTrie() { void MachOFileLayout::computeSymbolTableSizes() { // MachO symbol tables have three ranges: locals, globals, and undefines const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist)); - _symbolTableSize = nlistSize * (_file.localSymbols.size() + _symbolTableSize = nlistSize * (_file.stabsSymbols.size() + + _file.localSymbols.size() + _file.globalSymbols.size() + _file.undefinedSymbols.size()); - _symbolStringPoolSize = 1; // Always reserve 1-byte for the empty string. + // Always reserve 1-byte for the empty string and 1-byte for its terminator. + _symbolStringPoolSize = 2; + for (const Symbol &sym : _file.stabsSymbols) { + _symbolStringPoolSize += (sym.name.size()+1); + } for (const Symbol &sym : _file.localSymbols) { _symbolStringPoolSize += (sym.name.size()+1); } @@ -1428,7 +1478,8 @@ void MachOFileLayout::computeSymbolTableSizes() { _symbolStringPoolSize += (sym.name.size()+1); } _symbolTableLocalsStartIndex = 0; - _symbolTableGlobalsStartIndex = _file.localSymbols.size(); + _symbolTableGlobalsStartIndex = _file.stabsSymbols.size() + + _file.localSymbols.size(); _symbolTableUndefinesStartIndex = _symbolTableGlobalsStartIndex + _file.globalSymbols.size(); @@ -1486,7 +1537,7 @@ llvm::Error MachOFileLayout::writeBinary(StringRef path) { writeLinkEditContent(); fob->commit(); - return llvm::Error(); + return llvm::Error::success(); } /// Takes in-memory normalized view and writes a mach-o object file. diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 4775c75f7211..ddd3259842e2 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -22,6 +22,7 @@ #include "MachONormalizedFile.h" #include "ArchHandler.h" +#include "DebugInfo.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" @@ -34,6 +35,7 @@ #include "llvm/Support/MachO.h" #include <map> #include <system_error> +#include <unordered_set> using llvm::StringRef; using llvm::isa; @@ -120,6 +122,7 @@ public: void copySectionInfo(NormalizedFile &file); void updateSectionInfo(NormalizedFile &file); void buildAtomToAddressMap(); + llvm::Error synthesizeDebugNotes(NormalizedFile &file); llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file); void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file); void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file); @@ -201,6 +204,7 @@ private: bool _allSourceFilesHaveMinVersions = true; LoadCommandType _minVersionCommandType = (LoadCommandType)0; uint32_t _minVersion = 0; + std::vector<lld::mach_o::Stab> _stabs; }; Util::~Util() { @@ -785,6 +789,158 @@ void Util::buildAtomToAddressMap() { } } +llvm::Error Util::synthesizeDebugNotes(NormalizedFile &file) { + + // Bail out early if we don't need to generate a debug map. + if (_ctx.debugInfoMode() == MachOLinkingContext::DebugInfoMode::noDebugMap) + return llvm::Error::success(); + + std::vector<const DefinedAtom*> atomsNeedingDebugNotes; + std::set<const mach_o::MachOFile*> filesWithStabs; + bool objFileHasDwarf = false; + const File *objFile = nullptr; + + for (SectionInfo *sect : _sectionInfos) { + for (const AtomInfo &info : sect->atomsAndOffsets) { + if (const DefinedAtom *atom = dyn_cast<DefinedAtom>(info.atom)) { + + // FIXME: No stabs/debug-notes for symbols that wouldn't be in the + // symbol table. + // FIXME: No stabs/debug-notes for kernel dtrace probes. + + if (atom->contentType() == DefinedAtom::typeCFI || + atom->contentType() == DefinedAtom::typeCString) + continue; + + // Whenever we encounter a new file, update the 'objfileHasDwarf' flag. + if (&info.atom->file() != objFile) { + objFileHasDwarf = false; + if (const mach_o::MachOFile *atomFile = + dyn_cast<mach_o::MachOFile>(&info.atom->file())) { + if (atomFile->debugInfo()) { + if (isa<mach_o::DwarfDebugInfo>(atomFile->debugInfo())) + objFileHasDwarf = true; + else if (isa<mach_o::StabsDebugInfo>(atomFile->debugInfo())) + filesWithStabs.insert(atomFile); + } + } + } + + // If this atom is from a file that needs dwarf, add it to the list. + if (objFileHasDwarf) + atomsNeedingDebugNotes.push_back(info.atom); + } + } + } + + // Sort atoms needing debug notes by file ordinal, then atom ordinal. + std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(), + [](const DefinedAtom *lhs, const DefinedAtom *rhs) { + if (lhs->file().ordinal() != rhs->file().ordinal()) + return (lhs->file().ordinal() < rhs->file().ordinal()); + return (lhs->ordinal() < rhs->ordinal()); + }); + + // FIXME: Handle <rdar://problem/17689030>: Add -add_ast_path option to \ + // linker which add N_AST stab entry to output + // See OutputFile::synthesizeDebugNotes in ObjectFile.cpp in ld64. + + StringRef oldFileName = ""; + StringRef oldDirPath = ""; + bool wroteStartSO = false; + std::unordered_set<std::string> seenFiles; + for (const DefinedAtom *atom : atomsNeedingDebugNotes) { + const auto &atomFile = cast<mach_o::MachOFile>(atom->file()); + assert(dyn_cast_or_null<lld::mach_o::DwarfDebugInfo>(atomFile.debugInfo()) + && "file for atom needing debug notes does not contain dwarf"); + auto &dwarf = cast<lld::mach_o::DwarfDebugInfo>(*atomFile.debugInfo()); + + auto &tu = dwarf.translationUnitSource(); + StringRef newFileName = tu.name; + StringRef newDirPath = tu.path; + + // Add an SO whenever the TU source file changes. + if (newFileName != oldFileName || newDirPath != oldDirPath) { + // Translation unit change, emit ending SO + if (oldFileName != "") + _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, "")); + + oldFileName = newFileName; + oldDirPath = newDirPath; + + // If newDirPath doesn't end with a '/' we need to add one: + if (newDirPath.back() != '/') { + char *p = + file.ownedAllocations.Allocate<char>(newDirPath.size() + 2); + memcpy(p, newDirPath.data(), newDirPath.size()); + p[newDirPath.size()] = '/'; + p[newDirPath.size() + 1] = '\0'; + newDirPath = p; + } + + // New translation unit, emit start SOs: + _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newDirPath)); + _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newFileName)); + + // Synthesize OSO for start of file. + char *fullPath = nullptr; + { + SmallString<1024> pathBuf(atomFile.path()); + if (auto EC = llvm::sys::fs::make_absolute(pathBuf)) + return llvm::errorCodeToError(EC); + fullPath = file.ownedAllocations.Allocate<char>(pathBuf.size() + 1); + memcpy(fullPath, pathBuf.c_str(), pathBuf.size() + 1); + } + + // Get mod time. + uint32_t modTime = 0; + llvm::sys::fs::file_status stat; + if (!llvm::sys::fs::status(fullPath, stat)) + if (llvm::sys::fs::exists(stat)) + modTime = llvm::sys::toTimeT(stat.getLastModificationTime()); + + _stabs.push_back(mach_o::Stab(nullptr, N_OSO, _ctx.getCPUSubType(), 1, + modTime, fullPath)); + // <rdar://problem/6337329> linker should put cpusubtype in n_sect field + // of nlist entry for N_OSO debug note entries. + wroteStartSO = true; + } + + if (atom->contentType() == DefinedAtom::typeCode) { + // Synthesize BNSYM and start FUN stabs. + _stabs.push_back(mach_o::Stab(atom, N_BNSYM, 1, 0, 0, "")); + _stabs.push_back(mach_o::Stab(atom, N_FUN, 1, 0, 0, atom->name())); + // Synthesize any SOL stabs needed + // FIXME: add SOL stabs. + _stabs.push_back(mach_o::Stab(nullptr, N_FUN, 0, 0, + atom->rawContent().size(), "")); + _stabs.push_back(mach_o::Stab(nullptr, N_ENSYM, 1, 0, + atom->rawContent().size(), "")); + } else { + if (atom->scope() == Atom::scopeTranslationUnit) + _stabs.push_back(mach_o::Stab(atom, N_STSYM, 1, 0, 0, atom->name())); + else + _stabs.push_back(mach_o::Stab(nullptr, N_GSYM, 1, 0, 0, atom->name())); + } + } + + // Emit ending SO if necessary. + if (wroteStartSO) + _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, "")); + + // Copy any stabs from .o file. + for (const auto *objFile : filesWithStabs) { + const auto &stabsList = + cast<mach_o::StabsDebugInfo>(objFile->debugInfo())->stabs(); + for (auto &stab : stabsList) { + // FIXME: Drop stabs whose atoms have been dead-stripped. + _stabs.push_back(stab); + } + } + + return llvm::Error::success(); +} + uint16_t Util::descBits(const DefinedAtom* atom) { uint16_t desc = 0; switch (atom->merge()) { @@ -807,7 +963,8 @@ uint16_t Util::descBits(const DefinedAtom* atom) { desc |= REFERENCED_DYNAMICALLY; if (_archHandler.isThumbFunction(*atom)) desc |= N_ARM_THUMB_DEF; - if (atom->deadStrip() == DefinedAtom::deadStripNever) { + if (atom->deadStrip() == DefinedAtom::deadStripNever && + _ctx.outputMachOType() == llvm::MachO::MH_OBJECT) { if ((atom->contentType() != DefinedAtom::typeInitializerPtr) && (atom->contentType() != DefinedAtom::typeTerminatorPtr)) desc |= N_NO_DEAD_STRIP; @@ -828,7 +985,7 @@ llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom, case Atom::scopeTranslationUnit: scope = 0; inGlobalsRegion = false; - return llvm::Error(); + return llvm::Error::success(); case Atom::scopeLinkageUnit: if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) && _ctx.exportSymbolNamed(atom->name())) { @@ -840,38 +997,55 @@ llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom, // -keep_private_externs means keep in globals region as N_PEXT. scope = N_PEXT | N_EXT; inGlobalsRegion = true; - return llvm::Error(); + return llvm::Error::success(); } } // scopeLinkageUnit symbols are no longer global once linked. scope = N_PEXT; inGlobalsRegion = false; - return llvm::Error(); + return llvm::Error::success(); case Atom::scopeGlobal: if (_ctx.exportRestrictMode()) { if (_ctx.exportSymbolNamed(atom->name())) { scope = N_EXT; inGlobalsRegion = true; - return llvm::Error(); + return llvm::Error::success(); } else { scope = N_PEXT; inGlobalsRegion = false; - return llvm::Error(); + return llvm::Error::success(); } } else { scope = N_EXT; inGlobalsRegion = true; - return llvm::Error(); + return llvm::Error::success(); } break; } llvm_unreachable("atom->scope() unknown enum value"); } + + llvm::Error Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) { bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); - // Mach-O symbol table has three regions: locals, globals, undefs. + // Mach-O symbol table has four regions: stabs, locals, globals, undefs. + + // Add all stabs. + for (auto &stab : _stabs) { + Symbol sym; + sym.type = static_cast<NListType>(stab.type); + sym.scope = 0; + sym.sect = stab.other; + sym.desc = stab.desc; + if (stab.atom) + sym.value = _atomToAddress[stab.atom]; + else + sym.value = stab.value; + sym.name = stab.str; + file.stabsSymbols.push_back(sym); + } // Add all local (non-global) symbols in address order std::vector<AtomAndIndex> globals; @@ -965,7 +1139,7 @@ llvm::Error Util::addSymbols(const lld::File &atomFile, file.undefinedSymbols.push_back(sym); } - return llvm::Error(); + return llvm::Error::success(); } const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) { @@ -1040,15 +1214,15 @@ void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) { } } -void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) { +void Util::addDependentDylibs(const lld::File &atomFile, + NormalizedFile &nFile) { // Scan all imported symbols and build up list of dylibs they are from. int ordinal = 1; - for (const SharedLibraryAtom *slAtom : atomFile.sharedLibrary()) { - StringRef loadPath = slAtom->loadName(); - DylibPathToInfo::iterator pos = _dylibInfo.find(loadPath); + for (const auto *dylib : _ctx.allDylibs()) { + DylibPathToInfo::iterator pos = _dylibInfo.find(dylib->installName()); if (pos == _dylibInfo.end()) { DylibInfo info; - bool flatNamespaceAtom = &slAtom->file() == _ctx.flatNamespaceFile(); + bool flatNamespaceAtom = dylib == _ctx.flatNamespaceFile(); // If we're in -flat_namespace mode (or this atom came from the flat // namespace file under -undefined dynamic_lookup) then use the flat @@ -1057,24 +1231,22 @@ void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) { info.ordinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP; else info.ordinal = ordinal++; - info.hasWeak = slAtom->canBeNullAtRuntime(); + info.hasWeak = false; info.hasNonWeak = !info.hasWeak; - _dylibInfo[loadPath] = info; + _dylibInfo[dylib->installName()] = info; // Unless this was a flat_namespace atom, record the source dylib. if (!flatNamespaceAtom) { DependentDylib depInfo; - depInfo.path = loadPath; + depInfo.path = dylib->installName(); depInfo.kind = llvm::MachO::LC_LOAD_DYLIB; - depInfo.currentVersion = _ctx.dylibCurrentVersion(loadPath); - depInfo.compatVersion = _ctx.dylibCompatVersion(loadPath); + depInfo.currentVersion = _ctx.dylibCurrentVersion(dylib->path()); + depInfo.compatVersion = _ctx.dylibCompatVersion(dylib->path()); nFile.dependentDylibs.push_back(depInfo); } } else { - if ( slAtom->canBeNullAtRuntime() ) - pos->second.hasWeak = true; - else - pos->second.hasNonWeak = true; + pos->second.hasWeak = false; + pos->second.hasNonWeak = !pos->second.hasWeak; } } // Automatically weak link dylib in which all symbols are weak (canBeNull). @@ -1404,6 +1576,8 @@ normalizedFromAtoms(const lld::File &atomFile, util.copySectionInfo(normFile); util.assignAddressesToSections(normFile); util.buildAtomToAddressMap(); + if (auto err = util.synthesizeDebugNotes(normFile)) + return std::move(err); util.updateSectionInfo(normFile); util.copySectionContent(normFile); if (auto ec = util.addSymbols(atomFile, normFile)) { diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index fc760a3eddd0..4b17f7b3a85f 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -27,7 +27,11 @@ #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Format.h" #include "llvm/Support/MachO.h" #include "llvm/Support/LEB128.h" @@ -320,7 +324,7 @@ llvm::Error processSymboledSection(DefinedAtom::ContentType atomType, // If section has no symbols and no content, there are no atoms. if (symbols.empty() && section.content.empty()) - return llvm::Error(); + return llvm::Error::success(); if (symbols.empty()) { // Section has no symbols, put all content in one anoymous atom. @@ -371,7 +375,7 @@ llvm::Error processSymboledSection(DefinedAtom::ContentType atomType, }); } - return llvm::Error(); + return llvm::Error::success(); } llvm::Error processSection(DefinedAtom::ContentType atomType, @@ -483,7 +487,7 @@ llvm::Error processSection(DefinedAtom::ContentType atomType, offset += size; } } - return llvm::Error(); + return llvm::Error::success(); } const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile, @@ -499,7 +503,7 @@ const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile, const MachODefinedAtom * findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file, - uint64_t addr, Reference::Addend *addend) { + uint64_t addr, Reference::Addend &addend) { const Section *sect = nullptr; sect = findSectionCoveringAddress(normalizedFile, addr); if (!sect) @@ -509,7 +513,7 @@ findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file, uint64_t offsetInSect = addr - sect->address; auto atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget); - *addend = offsetInTarget; + addend = offsetInTarget; return atom; } @@ -540,7 +544,7 @@ llvm::Error convertRelocs(const Section §ion, uint64_t offsetInSect = addr - sect->address; *atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget); *addend = offsetInTarget; - return llvm::Error(); + return llvm::Error::success(); }; // Utility function for ArchHandler to find atom by its symbol index. @@ -548,19 +552,23 @@ llvm::Error convertRelocs(const Section §ion, -> llvm::Error { // Find symbol from index. const Symbol *sym = nullptr; + uint32_t numStabs = normalizedFile.stabsSymbols.size(); uint32_t numLocal = normalizedFile.localSymbols.size(); uint32_t numGlobal = normalizedFile.globalSymbols.size(); uint32_t numUndef = normalizedFile.undefinedSymbols.size(); - if (symbolIndex < numLocal) { - sym = &normalizedFile.localSymbols[symbolIndex]; - } else if (symbolIndex < numLocal+numGlobal) { - sym = &normalizedFile.globalSymbols[symbolIndex-numLocal]; - } else if (symbolIndex < numLocal+numGlobal+numUndef) { - sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal]; + assert(symbolIndex >= numStabs && "Searched for stab via atomBySymbol?"); + if (symbolIndex < numStabs+numLocal) { + sym = &normalizedFile.localSymbols[symbolIndex-numStabs]; + } else if (symbolIndex < numStabs+numLocal+numGlobal) { + sym = &normalizedFile.globalSymbols[symbolIndex-numStabs-numLocal]; + } else if (symbolIndex < numStabs+numLocal+numGlobal+numUndef) { + sym = &normalizedFile.undefinedSymbols[symbolIndex-numStabs-numLocal- + numGlobal]; } else { return llvm::make_error<GenericError>(Twine("symbol index (") + Twine(symbolIndex) + ") out of range"); } + // Find atom from symbol. if ((sym->type & N_TYPE) == N_SECT) { if (sym->sect > normalizedFile.sections.size()) @@ -572,14 +580,14 @@ llvm::Error convertRelocs(const Section §ion, targetOffsetInSect); if (target) { *result = target; - return llvm::Error(); + return llvm::Error::success(); } return llvm::make_error<GenericError>("no atom found for defined symbol"); } else if ((sym->type & N_TYPE) == N_UNDF) { const lld::Atom *target = file.findUndefAtom(sym->name); if (target) { *result = target; - return llvm::Error(); + return llvm::Error::success(); } return llvm::make_error<GenericError>("no undefined atom found for sym"); } else { @@ -676,7 +684,7 @@ llvm::Error convertRelocs(const Section §ion, kind, offsetInAtom, target, addend); } - return llvm::Error(); + return llvm::Error::success(); } bool isDebugInfoSection(const Section §ion) { @@ -685,6 +693,301 @@ bool isDebugInfoSection(const Section §ion) { return section.segmentName.equals("__DWARF"); } +static const Atom* findDefinedAtomByName(MachOFile &file, Twine name) { + std::string strName = name.str(); + for (auto *atom : file.defined()) + if (atom->name() == strName) + return atom; + return nullptr; +} + +static StringRef copyDebugString(StringRef str, BumpPtrAllocator &alloc) { + char *strCopy = alloc.Allocate<char>(str.size() + 1); + memcpy(strCopy, str.data(), str.size()); + strCopy[str.size()] = '\0'; + return strCopy; +} + +llvm::Error parseStabs(MachOFile &file, + const NormalizedFile &normalizedFile, + bool copyRefs) { + + if (normalizedFile.stabsSymbols.empty()) + return llvm::Error::success(); + + // FIXME: Kill this off when we can move to sane yaml parsing. + std::unique_ptr<BumpPtrAllocator> allocator; + if (copyRefs) + allocator = llvm::make_unique<BumpPtrAllocator>(); + + enum { start, inBeginEnd } state = start; + + const Atom *currentAtom = nullptr; + uint64_t currentAtomAddress = 0; + StabsDebugInfo::StabsList stabsList; + for (const auto &stabSym : normalizedFile.stabsSymbols) { + Stab stab(nullptr, stabSym.type, stabSym.sect, stabSym.desc, + stabSym.value, stabSym.name); + switch (state) { + case start: + switch (static_cast<StabType>(stabSym.type)) { + case N_BNSYM: + state = inBeginEnd; + currentAtomAddress = stabSym.value; + Reference::Addend addend; + currentAtom = findAtomCoveringAddress(normalizedFile, file, + currentAtomAddress, addend); + if (addend != 0) + return llvm::make_error<GenericError>( + "Non-zero addend for BNSYM '" + stabSym.name + "' in " + + file.path()); + if (currentAtom) + stab.atom = currentAtom; + else { + // FIXME: ld64 just issues a warning here - should we match that? + return llvm::make_error<GenericError>( + "can't find atom for stabs BNSYM at " + + Twine::utohexstr(stabSym.value) + " in " + file.path()); + } + break; + case N_SO: + case N_OSO: + // Not associated with an atom, just copy. + if (copyRefs) + stab.str = copyDebugString(stabSym.name, *allocator); + else + stab.str = stabSym.name; + break; + case N_GSYM: { + auto colonIdx = stabSym.name.find(':'); + if (colonIdx != StringRef::npos) { + StringRef name = stabSym.name.substr(0, colonIdx); + currentAtom = findDefinedAtomByName(file, "_" + name); + stab.atom = currentAtom; + if (copyRefs) + stab.str = copyDebugString(stabSym.name, *allocator); + else + stab.str = stabSym.name; + } else { + currentAtom = findDefinedAtomByName(file, stabSym.name); + stab.atom = currentAtom; + if (copyRefs) + stab.str = copyDebugString(stabSym.name, *allocator); + else + stab.str = stabSym.name; + } + if (stab.atom == nullptr) + return llvm::make_error<GenericError>( + "can't find atom for N_GSYM stabs" + stabSym.name + + " in " + file.path()); + break; + } + case N_FUN: + return llvm::make_error<GenericError>( + "old-style N_FUN stab '" + stabSym.name + "' unsupported"); + default: + return llvm::make_error<GenericError>( + "unrecognized stab symbol '" + stabSym.name + "'"); + } + break; + case inBeginEnd: + stab.atom = currentAtom; + switch (static_cast<StabType>(stabSym.type)) { + case N_ENSYM: + state = start; + currentAtom = nullptr; + break; + case N_FUN: + // Just copy the string. + if (copyRefs) + stab.str = copyDebugString(stabSym.name, *allocator); + else + stab.str = stabSym.name; + break; + default: + return llvm::make_error<GenericError>( + "unrecognized stab symbol '" + stabSym.name + "'"); + } + } + llvm::dbgs() << "Adding to stabsList: " << stab << "\n"; + stabsList.push_back(stab); + } + + file.setDebugInfo(llvm::make_unique<StabsDebugInfo>(std::move(stabsList))); + + // FIXME: Kill this off when we fix YAML memory ownership. + file.debugInfo()->setAllocator(std::move(allocator)); + + return llvm::Error::success(); +} + +static llvm::DataExtractor +dataExtractorFromSection(const NormalizedFile &normalizedFile, + const Section &S) { + const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); + const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); + StringRef SecData(reinterpret_cast<const char*>(S.content.data()), + S.content.size()); + return llvm::DataExtractor(SecData, !isBig, is64 ? 8 : 4); +} + +// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE +// inspection" code if possible. +static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData, + uint64_t abbrCode) { + uint64_t curCode; + uint32_t offset = 0; + while ((curCode = abbrevData.getULEB128(&offset)) != abbrCode) { + // Tag + abbrevData.getULEB128(&offset); + // DW_CHILDREN + abbrevData.getU8(&offset); + // Attributes + while (abbrevData.getULEB128(&offset) | abbrevData.getULEB128(&offset)) + ; + } + return offset; +} + +// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE +// inspection" code if possible. +static Expected<const char *> +getIndexedString(const NormalizedFile &normalizedFile, + llvm::dwarf::Form form, llvm::DataExtractor infoData, + uint32_t &infoOffset, const Section &stringsSection) { + if (form == llvm::dwarf::DW_FORM_string) + return infoData.getCStr(&infoOffset); + if (form != llvm::dwarf::DW_FORM_strp) + return llvm::make_error<GenericError>( + "string field encoded without DW_FORM_strp"); + uint32_t stringOffset = infoData.getU32(&infoOffset); + llvm::DataExtractor stringsData = + dataExtractorFromSection(normalizedFile, stringsSection); + return stringsData.getCStr(&stringOffset); +} + +// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE +// inspection" code if possible. +static llvm::Expected<TranslationUnitSource> +readCompUnit(const NormalizedFile &normalizedFile, + const Section &info, + const Section &abbrev, + const Section &strings, + StringRef path) { + // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE + // inspection" code if possible. + uint32_t offset = 0; + llvm::dwarf::DwarfFormat Format = llvm::dwarf::DwarfFormat::DWARF32; + auto infoData = dataExtractorFromSection(normalizedFile, info); + uint32_t length = infoData.getU32(&offset); + if (length == 0xffffffff) { + Format = llvm::dwarf::DwarfFormat::DWARF64; + infoData.getU64(&offset); + } + else if (length > 0xffffff00) + return llvm::make_error<GenericError>("Malformed DWARF in " + path); + + uint16_t version = infoData.getU16(&offset); + + if (version < 2 || version > 4) + return llvm::make_error<GenericError>("Unsupported DWARF version in " + + path); + + infoData.getU32(&offset); // Abbrev offset (should be zero) + uint8_t addrSize = infoData.getU8(&offset); + + uint32_t abbrCode = infoData.getULEB128(&offset); + auto abbrevData = dataExtractorFromSection(normalizedFile, abbrev); + uint32_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode); + uint64_t tag = abbrevData.getULEB128(&abbrevOffset); + if (tag != llvm::dwarf::DW_TAG_compile_unit) + return llvm::make_error<GenericError>("top level DIE is not a compile unit"); + // DW_CHILDREN + abbrevData.getU8(&abbrevOffset); + uint32_t name; + llvm::dwarf::Form form; + TranslationUnitSource tu; + while ((name = abbrevData.getULEB128(&abbrevOffset)) | + (form = static_cast<llvm::dwarf::Form>( + abbrevData.getULEB128(&abbrevOffset))) && + (name != 0 || form != 0)) { + switch (name) { + case llvm::dwarf::DW_AT_name: { + if (auto eName = getIndexedString(normalizedFile, form, infoData, offset, + strings)) + tu.name = *eName; + else + return eName.takeError(); + break; + } + case llvm::dwarf::DW_AT_comp_dir: { + if (auto eName = getIndexedString(normalizedFile, form, infoData, offset, + strings)) + tu.path = *eName; + else + return eName.takeError(); + break; + } + default: + llvm::DWARFFormValue::skipValue(form, infoData, &offset, version, + addrSize, Format); + } + } + return tu; +} + +llvm::Error parseDebugInfo(MachOFile &file, + const NormalizedFile &normalizedFile, bool copyRefs) { + + // Find the interesting debug info sections. + const Section *debugInfo = nullptr; + const Section *debugAbbrev = nullptr; + const Section *debugStrings = nullptr; + + for (auto &s : normalizedFile.sections) { + if (s.segmentName == "__DWARF") { + if (s.sectionName == "__debug_info") + debugInfo = &s; + else if (s.sectionName == "__debug_abbrev") + debugAbbrev = &s; + else if (s.sectionName == "__debug_str") + debugStrings = &s; + } + } + + if (!debugInfo) + return parseStabs(file, normalizedFile, copyRefs); + + if (debugInfo->content.size() == 0) + return llvm::Error::success(); + + if (debugInfo->content.size() < 12) + return llvm::make_error<GenericError>("Malformed __debug_info section in " + + file.path() + ": too small"); + + if (!debugAbbrev) + return llvm::make_error<GenericError>("Missing __dwarf_abbrev section in " + + file.path()); + + if (auto tuOrErr = readCompUnit(normalizedFile, *debugInfo, *debugAbbrev, + *debugStrings, file.path())) { + // FIXME: Kill of allocator and code under 'copyRefs' when we fix YAML + // memory ownership. + std::unique_ptr<BumpPtrAllocator> allocator; + if (copyRefs) { + allocator = llvm::make_unique<BumpPtrAllocator>(); + tuOrErr->name = copyDebugString(tuOrErr->name, *allocator); + tuOrErr->path = copyDebugString(tuOrErr->path, *allocator); + } + file.setDebugInfo(llvm::make_unique<DwarfDebugInfo>(std::move(*tuOrErr))); + if (copyRefs) + file.debugInfo()->setAllocator(std::move(allocator)); + } else + return tuOrErr.takeError(); + + return llvm::Error::success(); +} + static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) { if (is64) return read64(addr, isBig); @@ -712,7 +1015,7 @@ static llvm::Error processAugmentationString(const uint8_t *augStr, if (augStr[0] == '\0') { len = 1; - return llvm::Error(); + return llvm::Error::success(); } if (augStr[0] != 'z') @@ -762,7 +1065,7 @@ static llvm::Error processAugmentationString(const uint8_t *augStr, cieInfo._augmentationDataLength = offsetInAugmentationData; len = idx + 1; - return llvm::Error(); + return llvm::Error::success(); } static llvm::Error processCIE(const NormalizedFile &normalizedFile, @@ -853,7 +1156,7 @@ static llvm::Error processCIE(const NormalizedFile &normalizedFile, const MachODefinedAtom *func = nullptr; Reference::Addend addend; func = findAtomCoveringAddress(normalizedFile, file, funcAddress, - &addend); + addend); atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(), handler.unwindRefToPersonalityFunctionKind(), PersonalityFunctionField, func, addend); @@ -867,7 +1170,7 @@ static llvm::Error processCIE(const NormalizedFile &normalizedFile, cieInfos[atom] = std::move(cieInfo); - return llvm::Error(); + return llvm::Error::success(); } static llvm::Error processFDE(const NormalizedFile &normalizedFile, @@ -936,7 +1239,7 @@ static llvm::Error processFDE(const NormalizedFile &normalizedFile, } Reference::Addend addend; auto *target = findAtomCoveringAddress(normalizedFile, file, - targetAddress, &addend); + targetAddress, addend); atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(), refKind, refAddress, target, addend); @@ -1011,7 +1314,7 @@ static llvm::Error processFDE(const NormalizedFile &normalizedFile, } } - return llvm::Error(); + return llvm::Error::success(); } llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile, @@ -1028,9 +1331,9 @@ llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile, // No __eh_frame so nothing to do. if (!ehFrameSection) - return llvm::Error(); + return llvm::Error::success(); - llvm::Error ehFrameErr; + llvm::Error ehFrameErr = llvm::Error::success(); CIEInfoMap cieInfos; file.eachAtomInSection(*ehFrameSection, @@ -1092,10 +1395,9 @@ llvm::Error parseObjCImageInfo(const Section §, file.setSwiftVersion((flags >> 8) & 0xFF); - return llvm::Error(); + return llvm::Error::success(); } - /// Converts normalized mach-o file into an lld::File and lld::Atoms. llvm::Expected<std::unique_ptr<lld::File>> objectToAtoms(const NormalizedFile &normalizedFile, StringRef path, @@ -1135,11 +1437,11 @@ normalizedObjectToAtoms(MachOFile *file, // Create atoms from each section. for (auto § : normalizedFile.sections) { - DEBUG(llvm::dbgs() << "Creating atoms: "; sect.dump()); + + // If this is a debug-info section parse it specially. if (isDebugInfoSection(sect)) continue; - // If the file contains an objc_image_info struct, then we should parse the // ObjC flags and Swift version. if (isObjCImageInfo(sect)) { @@ -1248,7 +1550,11 @@ normalizedObjectToAtoms(MachOFile *file, for (const DefinedAtom* defAtom : file->defined()) { reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences(); } - return llvm::Error(); + + if (auto err = parseDebugInfo(*file, normalizedFile, copyRefs)) + return err; + + return llvm::Error::success(); } llvm::Error @@ -1279,7 +1585,7 @@ normalizedDylibToAtoms(MachODylibFile *file, if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB) file->addReExportedDylib(dep.path); } - return llvm::Error(); + return llvm::Error::success(); } void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType, @@ -1324,14 +1630,6 @@ normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path, } } -#ifndef NDEBUG -void Section::dump(llvm::raw_ostream &OS) const { - OS << "Section (\"" << segmentName << ", " << sectionName << "\""; - OS << ", addr: " << llvm::format_hex(address, 16, true); - OS << ", size: " << llvm::format_hex(content.size(), 8, true) << ")\n"; -} -#endif - } // namespace normalized } // namespace mach_o } // namespace lld diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp index 66be77173983..218170965eca 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp @@ -234,6 +234,8 @@ struct ScalarBitSetTraits<SectionAttr> { llvm::MachO::S_ATTR_EXT_RELOC); io.bitSetCase(value, "S_ATTR_LOC_RELOC", llvm::MachO::S_ATTR_LOC_RELOC); + io.bitSetCase(value, "S_ATTR_DEBUG", + llvm::MachO::S_ATTR_DEBUG); } }; diff --git a/lib/ReaderWriter/MachO/ObjCPass.cpp b/lib/ReaderWriter/MachO/ObjCPass.cpp index ba24b3fecdf4..4712d8ca969c 100644 --- a/lib/ReaderWriter/MachO/ObjCPass.cpp +++ b/lib/ReaderWriter/MachO/ObjCPass.cpp @@ -103,7 +103,7 @@ public: // Add the image info. mergedFile.addAtom(*getImageInfo()); - return llvm::Error(); + return llvm::Error::success(); } private: diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp index cd5367146658..ff559d70eabe 100644 --- a/lib/ReaderWriter/MachO/ShimPass.cpp +++ b/lib/ReaderWriter/MachO/ShimPass.cpp @@ -66,7 +66,7 @@ public: } // Exit early if no shims needed. if (_targetToShim.empty()) - return llvm::Error(); + return llvm::Error::success(); // Sort shim atoms so the layout order is stable. std::vector<const DefinedAtom *> shims; @@ -83,7 +83,7 @@ public: for (const DefinedAtom *shim : shims) mergedFile.addAtom(*shim); - return llvm::Error(); + return llvm::Error::success(); } private: diff --git a/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp index d53b78b24d14..19e2bc592f5c 100644 --- a/lib/ReaderWriter/MachO/StubsPass.cpp +++ b/lib/ReaderWriter/MachO/StubsPass.cpp @@ -218,7 +218,7 @@ public: llvm::Error perform(SimpleFile &mergedFile) override { // Skip this pass if output format uses text relocations instead of stubs. if (!this->noTextRelocs()) - return llvm::Error(); + return llvm::Error::success(); // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { @@ -245,7 +245,7 @@ public: // Exit early if no stubs needed. if (_targetToUses.empty()) - return llvm::Error(); + return llvm::Error::success(); // First add help-common and GOT slots used by lazy binding. SimpleDefinedAtom *helperCommonAtom = @@ -323,7 +323,7 @@ public: lazyOffset += target->name().size() + 12; } - return llvm::Error(); + return llvm::Error::success(); } private: diff --git a/lib/ReaderWriter/MachO/TLVPass.cpp b/lib/ReaderWriter/MachO/TLVPass.cpp index 7a8496c20a4e..e362e507ebf2 100644 --- a/lib/ReaderWriter/MachO/TLVPass.cpp +++ b/lib/ReaderWriter/MachO/TLVPass.cpp @@ -107,7 +107,7 @@ private: for (const TLVPEntryAtom *slot : entries) mergedFile.addAtom(*slot); - return llvm::Error(); + return llvm::Error::success(); } const DefinedAtom *makeTLVPEntry(const Atom *target) { diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index ee2a9ec10883..59ca43079a6d 100644 --- a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -249,6 +249,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember) LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *) // Always write DefinedAtoms content bytes as a flow sequence. LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8) + // for compatibility with gcc-4.7 in C++11 mode, add extra namespace namespace llvm { namespace yaml { @@ -567,10 +568,10 @@ template <> struct DocumentListTraits<std::vector<const lld::File *> > { // YAML conversion for const lld::File* template <> struct MappingTraits<const lld::File *> { - class NormArchiveFile : public lld::ArchiveLibraryFile { public: - NormArchiveFile(IO &io) : ArchiveLibraryFile(""), _path() {} + NormArchiveFile(IO &io) : ArchiveLibraryFile("") {} + NormArchiveFile(IO &io, const lld::File *file) : ArchiveLibraryFile(file->path()), _path(file->path()) { // If we want to support writing archives, this constructor would @@ -627,6 +628,7 @@ template <> struct MappingTraits<const lld::File *> { _undefinedAtomsRef(_undefinedAtoms._atoms), _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms), _absoluteAtomsRef(_absoluteAtoms._atoms) {} + NormalizedFile(IO &io, const lld::File *file) : File(file->path(), kindNormalizedObject), _io(io), _rnb(new RefNameBuilder(*file)), _path(file->path()), @@ -673,7 +675,7 @@ template <> struct MappingTraits<const lld::File *> { } IO &_io; - std::unique_ptr<RefNameBuilder> _rnb; + std::unique_ptr<RefNameBuilder> _rnb; StringRef _path; AtomList<lld::DefinedAtom> _definedAtoms; AtomList<lld::UndefinedAtom> _undefinedAtoms; @@ -732,13 +734,12 @@ template <> struct MappingTraits<const lld::File *> { // YAML conversion for const lld::Reference* template <> struct MappingTraits<const lld::Reference *> { - class NormalizedReference : public lld::Reference { public: NormalizedReference(IO &io) : lld::Reference(lld::Reference::KindNamespace::all, lld::Reference::KindArch::all, 0), - _target(nullptr), _targetName(), _offset(0), _addend(0), _tag(0) {} + _target(nullptr), _offset(0), _addend(0), _tag(0) {} NormalizedReference(IO &io, const lld::Reference *ref) : lld::Reference(ref->kindNamespace(), ref->kindArch(), @@ -768,6 +769,7 @@ template <> struct MappingTraits<const lld::Reference *> { setKindValue(_mappedKind.value); return this; } + void bind(const RefNameResolver &); static StringRef targetName(IO &io, const lld::Reference *ref); @@ -804,13 +806,13 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { class NormalizedAtom : public lld::DefinedAtom { public: NormalizedAtom(IO &io) - : _file(fileFromContext(io)), _name(), _refName(), _contentType(), - _alignment(1), _content(), _references() { + : _file(fileFromContext(io)), _contentType(), _alignment(1) { static uint32_t ordinalCounter = 1; _ordinal = ordinalCounter++; } + NormalizedAtom(IO &io, const lld::DefinedAtom *atom) - : _file(fileFromContext(io)), _name(atom->name()), _refName(), + : _file(fileFromContext(io)), _name(atom->name()), _scope(atom->scope()), _interpose(atom->interposable()), _merge(atom->merge()), _contentType(atom->contentType()), _alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()), @@ -991,11 +993,10 @@ template <> struct MappingTraits<lld::DefinedAtom *> { // YAML conversion for const lld::UndefinedAtom* template <> struct MappingTraits<const lld::UndefinedAtom *> { - class NormalizedAtom : public lld::UndefinedAtom { public: NormalizedAtom(IO &io) - : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {} + : _file(fileFromContext(io)), _canBeNull(canBeNullNever) {} NormalizedAtom(IO &io, const lld::UndefinedAtom *atom) : _file(fileFromContext(io)), _name(atom->name()), @@ -1059,8 +1060,9 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> { class NormalizedAtom : public lld::SharedLibraryAtom { public: NormalizedAtom(IO &io) - : _file(fileFromContext(io)), _name(), _loadName(), _canBeNull(false), + : _file(fileFromContext(io)), _canBeNull(false), _type(Type::Unknown), _size(0) {} + NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom) : _file(fileFromContext(io)), _name(atom->name()), _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()), @@ -1133,11 +1135,11 @@ template <> struct MappingTraits<lld::SharedLibraryAtom *> { // YAML conversion for const lld::AbsoluteAtom* template <> struct MappingTraits<const lld::AbsoluteAtom *> { - class NormalizedAtom : public lld::AbsoluteAtom { public: NormalizedAtom(IO &io) - : _file(fileFromContext(io)), _name(), _scope(), _value(0) {} + : _file(fileFromContext(io)), _scope(), _value(0) {} + NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom) : _file(fileFromContext(io)), _name(atom->name()), _scope(atom->scope()), _value(atom->value()) {} @@ -1158,6 +1160,7 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> { << ", " << _name.size() << ")\n"); return this; } + // Extract current File object from YAML I/O parsing context const lld::File &fileFromContext(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); @@ -1309,7 +1312,7 @@ public: const lld::File *fileRef = &file; yout << fileRef; - return llvm::Error(); + return llvm::Error::success(); } private: |