From 436f7d660625d45a306977c31577ac62820df3e3 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Wed, 27 Jul 2016 22:55:30 +0000 Subject: [PATCH] [lld][MachO] Re-apply r276921 with fix - initialize strings for debug string copies. llvm-svn: 276935 --- .../ReaderWriter/MachO/ArchHandler_x86_64.cpp | 5 +- lld/lib/ReaderWriter/MachO/CMakeLists.txt | 1 + lld/lib/ReaderWriter/MachO/DebugInfo.h | 310 ++++++++++++++++ lld/lib/ReaderWriter/MachO/File.h | 16 +- .../ReaderWriter/MachO/MachONormalizedFile.h | 17 +- .../MachO/MachONormalizedFileBinaryReader.cpp | 10 +- .../MachO/MachONormalizedFileBinaryWriter.cpp | 21 +- .../MachO/MachONormalizedFileFromAtoms.cpp | 175 ++++++++- .../MachO/MachONormalizedFileToAtoms.cpp | 334 +++++++++++++++++- lld/test/mach-o/debug-syms.yaml | 249 +++++++++++++ 10 files changed, 1112 insertions(+), 26 deletions(-) create mode 100644 lld/lib/ReaderWriter/MachO/DebugInfo.h create mode 100644 lld/test/mach-o/debug-syms.yaml diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index c36982a77b13..391cbf668591 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -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; diff --git a/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/lld/lib/ReaderWriter/MachO/CMakeLists.txt index 70f451c997b3..d8f7d9bacc47 100644 --- a/lld/lib/ReaderWriter/MachO/CMakeLists.txt +++ b/lld/lib/ReaderWriter/MachO/CMakeLists.txt @@ -21,6 +21,7 @@ add_lld_library(lldMachO LINK_LIBS lldCore lldYAML + LLVMDebugInfoDWARF LLVMObject LLVMSupport ${PTHREAD_LIB} diff --git a/lld/lib/ReaderWriter/MachO/DebugInfo.h b/lld/lib/ReaderWriter/MachO/DebugInfo.h new file mode 100644 index 000000000000..7729b020d5e5 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/DebugInfo.h @@ -0,0 +1,310 @@ +//===- 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 + +#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 allocator) { + _allocator = std::move(allocator); + } + +protected: + DebugInfo(Kind kind) : _kind(kind) {} + +private: + std::unique_ptr _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 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 +//===- 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 + +#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; } + +protected: + DebugInfo(Kind kind) : _kind(kind) {} + +private: + 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 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 +//===- 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 + +#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; } + +protected: + DebugInfo(Kind kind) : _kind(kind) {} + +private: + 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 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/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index 64a0fcf82844..82c73e35e766 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/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 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 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 = std::move(debugInfo); + } + + DebugInfo* debugInfo() const { return _debugInfo.get(); } + std::unique_ptr 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; }; class MachODylibFile : public SharedLibraryFile { diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h index 92a21f7ef83d..c2d0ac3a2028 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h +++ b/lld/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" @@ -91,8 +92,22 @@ struct Relocation { bool isExtern; Hex32 value; uint32_t symbol; + +#ifndef NDEBUG + raw_ostream& operator<<(raw_ostream &OS) const { + dump(OS); + return OS; + } + + void dump(raw_ostream &OS = llvm::dbgs()) const; +#endif }; +inline raw_ostream& operator<<(raw_ostream &OS, const Relocation &R) { + R.dump(OS); + return OS; +} + /// A typedef so that YAML I/O can treat this vector as a sequence. typedef std::vector Relocations; @@ -226,7 +241,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 +256,7 @@ struct NormalizedFile { std::vector localSymbols; std::vector globalSymbols; std::vector undefinedSymbols; + std::vector stabsSymbols; // Maps to load commands with no LINKEDIT content (final linked images only). std::vector dependentDylibs; diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index a17de5be1742..d70113514118 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -390,12 +390,14 @@ readBinary(std::unique_ptr &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(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 &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 mb, const Registry ®istry) const override { std::unique_ptr ret = - llvm::make_unique(std::move(mb), &_ctx); + llvm::make_unique(std::move(mb), &_ctx); return std::move(ret); } diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index f3e159684e15..ed58d92a80b3 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -789,8 +789,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 +876,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 +890,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; @@ -1102,6 +1103,7 @@ void MachOFileLayout::writeSymbolTable() { uint32_t symOffset = _startOfSymbols; uint32_t strOffset = _startOfSymbolStrings; _buffer[strOffset++] = '\0'; // Reserve n_strx offset of zero to mean no name. + appendSymbols(_file.stabsSymbols, symOffset, strOffset); appendSymbols(_file.localSymbols, symOffset, strOffset); appendSymbols(_file.globalSymbols, symOffset, strOffset); appendSymbols(_file.undefinedSymbols, symOffset, strOffset); @@ -1414,10 +1416,14 @@ 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. + for (const Symbol &sym : _file.stabsSymbols) { + _symbolStringPoolSize += (sym.name.size()+1); + } for (const Symbol &sym : _file.localSymbols) { _symbolStringPoolSize += (sym.name.size()+1); } @@ -1428,7 +1434,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(); diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 4775c75f7211..2d95ab7ec9d3 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lld/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 #include +#include 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 _stabs; }; Util::~Util() { @@ -785,6 +789,156 @@ 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 atomsNeedingDebugNotes; + std::set filesWithStabs; + bool objFileHasDwarf = false; + const File *objFile = nullptr; + + for (SectionInfo *sect : _sectionInfos) { + for (const AtomInfo &info : sect->atomsAndOffsets) { + if (const DefinedAtom *atom = dyn_cast(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(&info.atom->file())) { + if (atomFile->debugInfo()) { + if (isa(atomFile->debugInfo())) + objFileHasDwarf = true; + else if (isa(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 : 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 seenFiles; + for (const DefinedAtom *atom : atomsNeedingDebugNotes) { + const auto &atomFile = cast(atom->file()); + assert(dyn_cast_or_null(atomFile.debugInfo()) + && "file for atom needing debug notes does not contain dwarf"); + auto &dwarf = cast(*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() != '/') { + std::string *p = file.ownedAllocations.Allocate(); + new (p) std::string(); + *p = (newDirPath + "/").str(); + 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. + std::string *fullPath = file.ownedAllocations.Allocate(); + new (fullPath) std::string(); + { + SmallString<1024> pathBuf(atomFile.path()); + if (auto EC = llvm::sys::fs::make_absolute(pathBuf)) + return llvm::errorCodeToError(EC); + *fullPath = pathBuf.str(); + } + + // 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 = stat.getLastModificationTime().toEpochTime(); + + _stabs.push_back(mach_o::Stab(nullptr, N_OSO, _ctx.getCPUSubType(), 1, + modTime, *fullPath)); + // 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(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()) { @@ -868,10 +1022,27 @@ llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom, 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(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 globals; @@ -1404,6 +1575,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/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index fc760a3eddd0..a1d43d30b74a 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/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" @@ -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; } @@ -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(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()) @@ -685,6 +693,297 @@ 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) { + std::string *strCopy = alloc.Allocate(); + new (strCopy) std::string(); + *strCopy = str; + 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 allocator; + if (copyRefs) + allocator = llvm::make_unique(); + + 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(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( + "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( + "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( + "can't find atom for N_GSYM stabs" + stabSym.name + + " in " + file.path()); + break; + } + case N_FUN: + return llvm::make_error( + "old-style N_FUN stab '" + stabSym.name + "' unsupported"); + default: + return llvm::make_error( + "unrecognized stab symbol '" + stabSym.name + "'"); + } + break; + case inBeginEnd: + stab.atom = currentAtom; + switch (static_cast(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( + "unrecognized stab symbol '" + stabSym.name + "'"); + } + } + llvm::dbgs() << "Adding to stabsList: " << stab << "\n"; + stabsList.push_back(stab); + } + + file.setDebugInfo(llvm::make_unique(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(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 +getIndexedString(const NormalizedFile &normalizedFile, + uint32_t 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( + "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 +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; + auto infoData = dataExtractorFromSection(normalizedFile, info); + uint32_t length = infoData.getU32(&offset); + if (length == 0xffffffff) + infoData.getU64(&offset); + else if (length > 0xffffff00) + return llvm::make_error("Malformed DWARF in " + path); + + uint16_t version = infoData.getU16(&offset); + + if (version < 2 || version > 4) + return llvm::make_error("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("top level DIE is not a compile unit"); + // DW_CHILDREN + abbrevData.getU8(&abbrevOffset); + uint32_t name; + uint32_t form; + TranslationUnitSource tu; + while ((name = abbrevData.getULEB128(&abbrevOffset)) | + (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); + } + } + 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("Malformed __debug_info section in " + + file.path() + ": too small"); + + if (!debugAbbrev) + return llvm::make_error("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 allocator; + if (copyRefs) { + allocator = llvm::make_unique(); + tuOrErr->name = copyDebugString(tuOrErr->name, *allocator); + tuOrErr->path = copyDebugString(tuOrErr->path, *allocator); + } + file.setDebugInfo(llvm::make_unique(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); @@ -853,7 +1152,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); @@ -936,7 +1235,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); @@ -1095,7 +1394,6 @@ llvm::Error parseObjCImageInfo(const Section §, return llvm::Error(); } - /// Converts normalized mach-o file into an lld::File and lld::Atoms. llvm::Expected> objectToAtoms(const NormalizedFile &normalizedFile, StringRef path, @@ -1136,10 +1434,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,6 +1547,10 @@ normalizedObjectToAtoms(MachOFile *file, for (const DefinedAtom* defAtom : file->defined()) { reinterpret_cast(defAtom)->sortReferences(); } + + if (auto err = parseDebugInfo(*file, normalizedFile, copyRefs)) + return err; + return llvm::Error(); } @@ -1325,6 +1628,13 @@ normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path, } #ifndef NDEBUG +void Relocation::dump(llvm::raw_ostream &OS) const { + OS << "Relocation (offset=" << llvm::format_hex(offset, 8, true) + << ", scatered=" << scattered << ", type=" << type << ", length=" << length + << ", pcrel=" << pcRel << ", isExtern=" << isExtern << ", value=" + << llvm::format_hex(value, 8, true) << ", symbol=" << symbol << ")\n"; +} + void Section::dump(llvm::raw_ostream &OS) const { OS << "Section (\"" << segmentName << ", " << sectionName << "\""; OS << ", addr: " << llvm::format_hex(address, 16, true); diff --git a/lld/test/mach-o/debug-syms.yaml b/lld/test/mach-o/debug-syms.yaml new file mode 100644 index 000000000000..37bebeb55f88 --- /dev/null +++ b/lld/test/mach-o/debug-syms.yaml @@ -0,0 +1,249 @@ +# RUN: lld -flavor darwin -arch x86_64 -o %t %s -lSystem && \ +# RUN: llvm-nm -no-sort -debug-syms %t | FileCheck %s + +# CHECK: 0000000000000000 - 00 0000 SO /Users/lhames/Projects/lld/lld-svn-tot/scratch/ +# CHECK-NEXT: 0000000000000000 - 00 0000 SO hw.c +# CHECK-NEXT: {{[0-9a-f]+}} - 03 0001 OSO {{.*}}/test/mach-o/debug-syms.yaml +# CHECK-NEXT: 0000000100000fa0 - 01 0000 BNSYM +# CHECK-NEXT: 0000000100000fa0 - 01 0000 FUN _main +# CHECK-NEXT: 0000000000000016 - 00 0000 FUN +# CHECK-NEXT: 0000000000000016 - 01 0000 ENSYM +# CHECK-NEXT: 0000000000000000 - 01 0000 SO + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +compat-version: 0.0 +current-version: 0.0 +has-UUID: false +OS: unknown +min-os-version-kind: LC_VERSION_MIN_MACOSX +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + alignment: 16 + address: 0x0000000000000000 + content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0xC7, 0x45, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x89, 0x7D, 0xF8, + 0x48, 0x89, 0x75, 0xF0, 0x5D, 0xC3 ] + - segment: __DWARF + section: __debug_str + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x0000000000000016 + content: [ 0x41, 0x70, 0x70, 0x6C, 0x65, 0x20, 0x4C, 0x4C, + 0x56, 0x4D, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6F, 0x6E, 0x20, 0x38, 0x2E, 0x30, 0x2E, 0x30, + 0x20, 0x28, 0x63, 0x6C, 0x61, 0x6E, 0x67, 0x2D, + 0x38, 0x30, 0x30, 0x2E, 0x30, 0x2E, 0x32, 0x34, + 0x2E, 0x31, 0x29, 0x00, 0x68, 0x77, 0x2E, 0x63, + 0x00, 0x2F, 0x55, 0x73, 0x65, 0x72, 0x73, 0x2F, + 0x6C, 0x68, 0x61, 0x6D, 0x65, 0x73, 0x2F, 0x50, + 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x2F, + 0x6C, 0x6C, 0x64, 0x2F, 0x6C, 0x6C, 0x64, 0x2D, + 0x73, 0x76, 0x6E, 0x2D, 0x74, 0x6F, 0x74, 0x2F, + 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x00, + 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x69, 0x6E, 0x74, + 0x00, 0x61, 0x72, 0x67, 0x63, 0x00, 0x61, 0x72, + 0x67, 0x76, 0x00, 0x63, 0x68, 0x61, 0x72, 0x00 ] + - segment: __DWARF + section: __debug_loc + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x000000000000008E + - segment: __DWARF + section: __debug_abbrev + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x000000000000008E + content: [ 0x01, 0x11, 0x01, 0x25, 0x0E, 0x13, 0x05, 0x03, + 0x0E, 0x10, 0x06, 0x1B, 0x0E, 0x11, 0x01, 0x12, + 0x01, 0x00, 0x00, 0x02, 0x2E, 0x01, 0x11, 0x01, + 0x12, 0x01, 0x40, 0x0A, 0x03, 0x0E, 0x3A, 0x0B, + 0x3B, 0x0B, 0x27, 0x0C, 0x49, 0x13, 0x3F, 0x0C, + 0x00, 0x00, 0x03, 0x05, 0x00, 0x02, 0x0A, 0x03, + 0x0E, 0x3A, 0x0B, 0x3B, 0x0B, 0x49, 0x13, 0x00, + 0x00, 0x04, 0x24, 0x00, 0x03, 0x0E, 0x3E, 0x0B, + 0x0B, 0x0B, 0x00, 0x00, 0x05, 0x0F, 0x00, 0x49, + 0x13, 0x00, 0x00, 0x00 ] + - segment: __DWARF + section: __debug_info + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x00000000000000DA + content: [ 0x7F, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x56, 0x60, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x6A, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x91, + 0x78, 0x69, 0x00, 0x00, 0x00, 0x01, 0x01, 0x6A, + 0x00, 0x00, 0x00, 0x03, 0x02, 0x91, 0x70, 0x6E, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x71, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x65, 0x00, 0x00, 0x00, 0x05, + 0x04, 0x05, 0x76, 0x00, 0x00, 0x00, 0x05, 0x7B, + 0x00, 0x00, 0x00, 0x04, 0x73, 0x00, 0x00, 0x00, + 0x06, 0x01, 0x00 ] + relocations: + - offset: 0x00000037 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - offset: 0x0000002F + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - offset: 0x00000026 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - offset: 0x0000001E + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - segment: __DWARF + section: __debug_ranges + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x000000000000015D + - segment: __DWARF + section: __debug_macinfo + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x000000000000015D + content: [ 0x00 ] + - segment: __DWARF + section: __apple_names + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x000000000000015E + content: [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6A, 0x7F, 0x9A, 0x7C, + 0x2C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 ] + - segment: __DWARF + section: __apple_objc + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x000000000000019A + content: [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF ] + - segment: __DWARF + section: __apple_namespac + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x00000000000001BE + content: [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF ] + - segment: __DWARF + section: __apple_types + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x00000000000001E2 + content: [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, + 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x30, 0x80, 0x88, 0x0B, 0x63, 0x20, 0x95, 0x7C, + 0x40, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x6A, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + - segment: __DWARF + section: __apple_exttypes + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x0000000000000248 + content: [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x06, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF ] + - segment: __LD + section: __compact_unwind + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + alignment: 8 + address: 0x0000000000000270 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - segment: __TEXT + section: __eh_frame + type: S_COALESCED + attributes: [ ] + alignment: 8 + address: 0x0000000000000290 + content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01, + 0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x50, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + - segment: __DWARF + section: __debug_line + type: S_REGULAR + attributes: [ S_ATTR_DEBUG ] + address: 0x00000000000002D0 + content: [ 0x37, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1B, 0x00, + 0x00, 0x00, 0x01, 0x01, 0xFB, 0x0E, 0x0D, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x68, 0x77, 0x2E, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x05, 0x03, 0x0A, 0x08, 0x3D, 0x02, 0x02, + 0x00, 0x01, 0x01 ] + relocations: + - offset: 0x00000028 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 +global-symbols: + - name: _main + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 +page-size: 0x00000000 +...