[lld][MachO] Add debug info support for MachO.

This patch causes LLD to build stabs debugging symbols for files containing
DWARF debug info, and to propagate existing stabs symbols for object files
built using '-r' mode. This enables debugging of binaries generated by LLD
from MachO objects.

llvm-svn: 276921
This commit is contained in:
Lang Hames 2016-07-27 21:31:25 +00:00
parent 06a2b6b1ee
commit 560333749f
10 changed files with 1111 additions and 26 deletions

View File

@ -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;

View File

@ -21,6 +21,7 @@ add_lld_library(lldMachO
LINK_LIBS
lldCore
lldYAML
LLVMDebugInfoDWARF
LLVMObject
LLVMSupport
${PTHREAD_LIB}

View File

@ -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 <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
//===- 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; }
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<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
//===- 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; }
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<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

View File

@ -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 {

View File

@ -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<Relocation> 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<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;

View File

@ -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 &registry) 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);
}

View File

@ -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();

View File

@ -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,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<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() != '/') {
std::string *p = file.ownedAllocations.Allocate<std::string>();
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<std::string>();
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));
// <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()) {
@ -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<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;
@ -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)) {

View File

@ -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 &section,
-> 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())
@ -685,6 +693,296 @@ bool isDebugInfoSection(const Section &section) {
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<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<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,
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<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;
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<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;
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<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);
@ -853,7 +1151,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 +1234,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 +1393,6 @@ llvm::Error parseObjCImageInfo(const Section &sect,
return llvm::Error();
}
/// 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,
@ -1136,10 +1433,11 @@ normalizedObjectToAtoms(MachOFile *file,
// Create atoms from each section.
for (auto &sect : 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 +1546,10 @@ normalizedObjectToAtoms(MachOFile *file,
for (const DefinedAtom* defAtom : file->defined()) {
reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
}
if (auto err = parseDebugInfo(*file, normalizedFile, copyRefs))
return err;
return llvm::Error();
}
@ -1325,6 +1627,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);

View File

@ -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
...