forked from OSchip/llvm-project
[lld][MachO] Re-apply r276921 with fix - initialize strings for debug string
copies. llvm-svn: 276935
This commit is contained in:
parent
03a3cec480
commit
436f7d6606
|
@ -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;
|
||||
|
|
|
@ -21,6 +21,7 @@ add_lld_library(lldMachO
|
|||
LINK_LIBS
|
||||
lldCore
|
||||
lldYAML
|
||||
LLVMDebugInfoDWARF
|
||||
LLVMObject
|
||||
LLVMSupport
|
||||
${PTHREAD_LIB}
|
||||
|
|
|
@ -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
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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<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,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<std::string>();
|
||||
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<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 +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<std::unique_ptr<lld::File>>
|
||||
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<const SimpleDefinedAtom*>(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);
|
||||
|
|
|
@ -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
|
||||
...
|
Loading…
Reference in New Issue