mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-23 17:29:19 +00:00
[llvm-objdump] for mach-o add -bind, -lazy-bind, and -weak-bind options
This finishes the ability of llvm-objdump to print out all information from the LC_DYLD_INFO load command. The -bind option prints out symbolic references that dyld must resolve immediately. The -lazy-bind option prints out symbolc reference that are lazily resolved on first use. The -weak-bind option prints out information about symbols which dyld must try to coalesce across images. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217853 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2e363ece75
commit
367cf70f27
@ -136,6 +136,54 @@ private:
|
||||
};
|
||||
typedef content_iterator<MachORebaseEntry> rebase_iterator;
|
||||
|
||||
/// MachOBindEntry encapsulates the current state in the decompression of
|
||||
/// binding opcodes. This allows you to iterate through the compressed table of
|
||||
/// bindings using:
|
||||
/// for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) {
|
||||
/// }
|
||||
class MachOBindEntry {
|
||||
public:
|
||||
enum class Kind { Regular, Lazy, Weak };
|
||||
|
||||
MachOBindEntry(ArrayRef<uint8_t> Opcodes, bool is64Bit, MachOBindEntry::Kind);
|
||||
|
||||
uint32_t segmentIndex() const;
|
||||
uint64_t segmentOffset() const;
|
||||
StringRef typeName() const;
|
||||
StringRef symbolName() const;
|
||||
uint32_t flags() const;
|
||||
int64_t addend() const;
|
||||
int ordinal() const;
|
||||
|
||||
bool operator==(const MachOBindEntry &) const;
|
||||
|
||||
void moveNext();
|
||||
|
||||
private:
|
||||
friend class MachOObjectFile;
|
||||
void moveToFirst();
|
||||
void moveToEnd();
|
||||
uint64_t readULEB128();
|
||||
int64_t readSLEB128();
|
||||
|
||||
ArrayRef<uint8_t> Opcodes;
|
||||
const uint8_t *Ptr;
|
||||
uint64_t SegmentOffset;
|
||||
uint32_t SegmentIndex;
|
||||
StringRef SymbolName;
|
||||
int Ordinal;
|
||||
uint32_t Flags;
|
||||
int64_t Addend;
|
||||
uint64_t RemainingLoopCount;
|
||||
uint64_t AdvanceAmount;
|
||||
uint8_t BindType;
|
||||
uint8_t PointerSize;
|
||||
Kind TableKind;
|
||||
bool Malformed;
|
||||
bool Done;
|
||||
};
|
||||
typedef content_iterator<MachOBindEntry> bind_iterator;
|
||||
|
||||
class MachOObjectFile : public ObjectFile {
|
||||
public:
|
||||
struct LoadCommandInfo {
|
||||
@ -245,6 +293,21 @@ public:
|
||||
static iterator_range<rebase_iterator> rebaseTable(ArrayRef<uint8_t> Opcodes,
|
||||
bool is64);
|
||||
|
||||
/// For use iterating over all bind table entries.
|
||||
iterator_range<bind_iterator> bindTable() const;
|
||||
|
||||
/// For use iterating over all lazy bind table entries.
|
||||
iterator_range<bind_iterator> lazyBindTable() const;
|
||||
|
||||
/// For use iterating over all lazy bind table entries.
|
||||
iterator_range<bind_iterator> weakBindTable() const;
|
||||
|
||||
/// For use examining bind opcodes not in a MachOObjectFile.
|
||||
static iterator_range<bind_iterator> bindTable(ArrayRef<uint8_t> Opcodes,
|
||||
bool is64,
|
||||
MachOBindEntry::Kind);
|
||||
|
||||
|
||||
// In a MachO file, sections have a segment name. This is used in the .o
|
||||
// files. They have a single segment, but this field specifies which segment
|
||||
// a section should be put in in the final object.
|
||||
@ -342,6 +405,8 @@ public:
|
||||
|
||||
bool isRelocatableObject() const override;
|
||||
|
||||
bool hasPageZeroSegment() const { return HasPageZeroSegment; }
|
||||
|
||||
static bool classof(const Binary *v) {
|
||||
return v->isMachO();
|
||||
}
|
||||
@ -357,6 +422,7 @@ private:
|
||||
const char *DysymtabLoadCmd;
|
||||
const char *DataInCodeLoadCmd;
|
||||
const char *DyldInfoLoadCmd;
|
||||
bool HasPageZeroSegment;
|
||||
};
|
||||
|
||||
/// DiceRef
|
||||
|
@ -58,6 +58,17 @@ getSegmentLoadCommandNumSections(const MachOObjectFile *O,
|
||||
return S.nsects;
|
||||
}
|
||||
|
||||
static bool isPageZeroSegment(const MachOObjectFile *O,
|
||||
const MachOObjectFile::LoadCommandInfo &L) {
|
||||
if (O->is64Bit()) {
|
||||
MachO::segment_command_64 S = O->getSegment64LoadCommand(L);
|
||||
return StringRef("__PAGEZERO").equals(S.segname);
|
||||
}
|
||||
MachO::segment_command S = O->getSegmentLoadCommand(L);
|
||||
return StringRef("__PAGEZERO").equals(S.segname);
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
getSectionPtr(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L,
|
||||
unsigned Sec) {
|
||||
@ -229,7 +240,8 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
|
||||
bool Is64bits, std::error_code &EC)
|
||||
: ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),
|
||||
SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr),
|
||||
DataInCodeLoadCmd(nullptr), DyldInfoLoadCmd(nullptr) {
|
||||
DataInCodeLoadCmd(nullptr), DyldInfoLoadCmd(nullptr),
|
||||
HasPageZeroSegment(false) {
|
||||
uint32_t LoadCommandCount = this->getHeader().ncmds;
|
||||
MachO::LoadCommandType SegmentLoadType = is64Bit() ?
|
||||
MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT;
|
||||
@ -255,6 +267,8 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
|
||||
const char *Sec = getSectionPtr(this, Load, J);
|
||||
Sections.push_back(Sec);
|
||||
}
|
||||
if (isPageZeroSegment(this, Load))
|
||||
HasPageZeroSegment = true;
|
||||
} else if (Load.C.cmd == MachO::LC_LOAD_DYLIB ||
|
||||
Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
|
||||
Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
|
||||
@ -1860,6 +1874,272 @@ iterator_range<rebase_iterator> MachOObjectFile::rebaseTable() const {
|
||||
return rebaseTable(getDyldInfoRebaseOpcodes(), is64Bit());
|
||||
}
|
||||
|
||||
|
||||
MachOBindEntry::MachOBindEntry(ArrayRef<uint8_t> Bytes, bool is64Bit,
|
||||
Kind BK)
|
||||
: Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0),
|
||||
Ordinal(0), Flags(0), Addend(0), RemainingLoopCount(0), AdvanceAmount(0),
|
||||
BindType(0), PointerSize(is64Bit ? 8 : 4),
|
||||
TableKind(BK), Malformed(false), Done(false) {}
|
||||
|
||||
void MachOBindEntry::moveToFirst() {
|
||||
Ptr = Opcodes.begin();
|
||||
moveNext();
|
||||
}
|
||||
|
||||
void MachOBindEntry::moveToEnd() {
|
||||
Ptr = Opcodes.end();
|
||||
RemainingLoopCount = 0;
|
||||
Done = true;
|
||||
}
|
||||
|
||||
void MachOBindEntry::moveNext() {
|
||||
// If in the middle of some loop, move to next binding in loop.
|
||||
SegmentOffset += AdvanceAmount;
|
||||
if (RemainingLoopCount) {
|
||||
--RemainingLoopCount;
|
||||
return;
|
||||
}
|
||||
if (Ptr == Opcodes.end()) {
|
||||
Done = true;
|
||||
return;
|
||||
}
|
||||
bool More = true;
|
||||
while (More && !Malformed) {
|
||||
// Parse next opcode and set up next loop.
|
||||
uint8_t Byte = *Ptr++;
|
||||
uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK;
|
||||
uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;
|
||||
int8_t SignExtended;
|
||||
const uint8_t *SymStart;
|
||||
switch (Opcode) {
|
||||
case MachO::BIND_OPCODE_DONE:
|
||||
if (TableKind == Kind::Lazy) {
|
||||
// Lazying bindings have a DONE opcode between entries. Need to ignore
|
||||
// it to advance to next entry. But need not if this is last entry.
|
||||
bool NotLastEntry = false;
|
||||
for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) {
|
||||
if (*P) {
|
||||
NotLastEntry = true;
|
||||
}
|
||||
}
|
||||
if (NotLastEntry)
|
||||
break;
|
||||
}
|
||||
More = false;
|
||||
Done = true;
|
||||
moveToEnd();
|
||||
DEBUG_WITH_TYPE("mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DONE\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
|
||||
Ordinal = ImmValue;
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: "
|
||||
<< "Ordinal=" << Ordinal << "\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
|
||||
Ordinal = readULEB128();
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: "
|
||||
<< "Ordinal=" << Ordinal << "\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
|
||||
if (ImmValue) {
|
||||
SignExtended = MachO::BIND_OPCODE_MASK | ImmValue;
|
||||
Ordinal = SignExtended;
|
||||
} else
|
||||
Ordinal = 0;
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: "
|
||||
<< "Ordinal=" << Ordinal << "\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
|
||||
Flags = ImmValue;
|
||||
SymStart = Ptr;
|
||||
while (*Ptr) {
|
||||
++Ptr;
|
||||
}
|
||||
++Ptr;
|
||||
SymbolName = StringRef(reinterpret_cast<const char*>(SymStart),
|
||||
Ptr-SymStart);
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: "
|
||||
<< "SymbolName=" << SymbolName << "\n");
|
||||
if (TableKind == Kind::Weak) {
|
||||
if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MachO::BIND_OPCODE_SET_TYPE_IMM:
|
||||
BindType = ImmValue;
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_SET_TYPE_IMM: "
|
||||
<< "BindType=" << (int)BindType << "\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_SET_ADDEND_SLEB:
|
||||
Addend = readSLEB128();
|
||||
if (TableKind == Kind::Lazy)
|
||||
Malformed = true;
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: "
|
||||
<< "Addend=" << Addend << "\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
|
||||
SegmentIndex = ImmValue;
|
||||
SegmentOffset = readULEB128();
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
|
||||
<< "SegmentIndex=" << SegmentIndex << ", "
|
||||
<< format("SegmentOffset=0x%06X", SegmentOffset)
|
||||
<< "\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_ADD_ADDR_ULEB:
|
||||
SegmentOffset += readULEB128();
|
||||
DEBUG_WITH_TYPE("mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: "
|
||||
<< format("SegmentOffset=0x%06X",
|
||||
SegmentOffset) << "\n");
|
||||
break;
|
||||
case MachO::BIND_OPCODE_DO_BIND:
|
||||
AdvanceAmount = PointerSize;
|
||||
RemainingLoopCount = 0;
|
||||
DEBUG_WITH_TYPE("mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_DO_BIND: "
|
||||
<< format("SegmentOffset=0x%06X",
|
||||
SegmentOffset) << "\n");
|
||||
return;
|
||||
case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
|
||||
AdvanceAmount = readULEB128();
|
||||
RemainingLoopCount = 0;
|
||||
if (TableKind == Kind::Lazy)
|
||||
Malformed = true;
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_DO_BIND_IMM_TIMES: "
|
||||
<< format("SegmentOffset=0x%06X", SegmentOffset)
|
||||
<< ", AdvanceAmount=" << AdvanceAmount
|
||||
<< ", RemainingLoopCount=" << RemainingLoopCount
|
||||
<< "\n");
|
||||
return;
|
||||
case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
|
||||
AdvanceAmount = ImmValue * PointerSize;
|
||||
RemainingLoopCount = 0;
|
||||
if (TableKind == Kind::Lazy)
|
||||
Malformed = true;
|
||||
DEBUG_WITH_TYPE("mach-o-bind",
|
||||
llvm::dbgs()
|
||||
<< "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: "
|
||||
<< format("SegmentOffset=0x%06X",
|
||||
SegmentOffset) << "\n");
|
||||
return;
|
||||
case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
|
||||
RemainingLoopCount = readULEB128() - 1;
|
||||
AdvanceAmount = readULEB128() + PointerSize;
|
||||
if (TableKind == Kind::Lazy)
|
||||
Malformed = true;
|
||||
DEBUG_WITH_TYPE(
|
||||
"mach-o-bind",
|
||||
llvm::dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: "
|
||||
<< format("SegmentOffset=0x%06X", SegmentOffset)
|
||||
<< ", AdvanceAmount=" << AdvanceAmount
|
||||
<< ", RemainingLoopCount=" << RemainingLoopCount
|
||||
<< "\n");
|
||||
return;
|
||||
default:
|
||||
Malformed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t MachOBindEntry::readULEB128() {
|
||||
unsigned Count;
|
||||
uint64_t Result = decodeULEB128(Ptr, &Count);
|
||||
Ptr += Count;
|
||||
if (Ptr > Opcodes.end()) {
|
||||
Ptr = Opcodes.end();
|
||||
Malformed = true;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
int64_t MachOBindEntry::readSLEB128() {
|
||||
unsigned Count;
|
||||
int64_t Result = decodeSLEB128(Ptr, &Count);
|
||||
Ptr += Count;
|
||||
if (Ptr > Opcodes.end()) {
|
||||
Ptr = Opcodes.end();
|
||||
Malformed = true;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
uint32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; }
|
||||
|
||||
uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; }
|
||||
|
||||
StringRef MachOBindEntry::typeName() const {
|
||||
switch (BindType) {
|
||||
case MachO::BIND_TYPE_POINTER:
|
||||
return "pointer";
|
||||
case MachO::BIND_TYPE_TEXT_ABSOLUTE32:
|
||||
return "text abs32";
|
||||
case MachO::BIND_TYPE_TEXT_PCREL32:
|
||||
return "text rel32";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
StringRef MachOBindEntry::symbolName() const { return SymbolName; }
|
||||
|
||||
int64_t MachOBindEntry::addend() const { return Addend; }
|
||||
|
||||
uint32_t MachOBindEntry::flags() const { return Flags; }
|
||||
|
||||
int MachOBindEntry::ordinal() const { return Ordinal; }
|
||||
|
||||
bool MachOBindEntry::operator==(const MachOBindEntry &Other) const {
|
||||
assert(Opcodes == Other.Opcodes && "compare iterators of different files");
|
||||
return (Ptr == Other.Ptr) &&
|
||||
(RemainingLoopCount == Other.RemainingLoopCount) &&
|
||||
(Done == Other.Done);
|
||||
}
|
||||
|
||||
iterator_range<bind_iterator>
|
||||
MachOObjectFile::bindTable(ArrayRef<uint8_t> Opcodes, bool is64,
|
||||
MachOBindEntry::Kind BKind) {
|
||||
MachOBindEntry Start(Opcodes, is64, BKind);
|
||||
Start.moveToFirst();
|
||||
|
||||
MachOBindEntry Finish(Opcodes, is64, BKind);
|
||||
Finish.moveToEnd();
|
||||
|
||||
return iterator_range<bind_iterator>(bind_iterator(Start),
|
||||
bind_iterator(Finish));
|
||||
}
|
||||
|
||||
iterator_range<bind_iterator> MachOObjectFile::bindTable() const {
|
||||
return bindTable(getDyldInfoBindOpcodes(), is64Bit(),
|
||||
MachOBindEntry::Kind::Regular);
|
||||
}
|
||||
|
||||
iterator_range<bind_iterator> MachOObjectFile::lazyBindTable() const {
|
||||
return bindTable(getDyldInfoLazyBindOpcodes(), is64Bit(),
|
||||
MachOBindEntry::Kind::Lazy);
|
||||
}
|
||||
|
||||
iterator_range<bind_iterator> MachOObjectFile::weakBindTable() const {
|
||||
return bindTable(getDyldInfoWeakBindOpcodes(), is64Bit(),
|
||||
MachOBindEntry::Kind::Weak);
|
||||
}
|
||||
|
||||
StringRef
|
||||
MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {
|
||||
ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec);
|
||||
|
BIN
test/tools/llvm-objdump/Inputs/bind.macho-x86_64
Executable file
BIN
test/tools/llvm-objdump/Inputs/bind.macho-x86_64
Executable file
Binary file not shown.
BIN
test/tools/llvm-objdump/Inputs/lazy-bind.macho-x86_64
Executable file
BIN
test/tools/llvm-objdump/Inputs/lazy-bind.macho-x86_64
Executable file
Binary file not shown.
BIN
test/tools/llvm-objdump/Inputs/weak-bind.macho-x86_64
Executable file
BIN
test/tools/llvm-objdump/Inputs/weak-bind.macho-x86_64
Executable file
Binary file not shown.
10
test/tools/llvm-objdump/macho-bind.test
Normal file
10
test/tools/llvm-objdump/macho-bind.test
Normal file
@ -0,0 +1,10 @@
|
||||
# RUN: llvm-objdump -macho -bind -arch x86_64 \
|
||||
# RUN: %p/Inputs/bind.macho-x86_64 | FileCheck %s
|
||||
|
||||
|
||||
# CHECK:__DATA __data 0x00001028 pointer 0 flat-namespace _any
|
||||
# CHECK:__DATA __data 0x00001020 pointer 0 main-executable _fromApp
|
||||
# CHECK:__DATA __data 0x00001018 pointer 0 this-image _myfunc
|
||||
# CHECK:__DATA __data 0x00001000 pointer 0 libfoo.dylib _foo
|
||||
# CHECK:__DATA __data 0x00001008 pointer 0 libbar.dylib _bar
|
||||
# CHECK:__DATA __data 0x00001010 pointer 0 libSystem.B.dylib _malloc
|
7
test/tools/llvm-objdump/macho-lazy-bind.test
Normal file
7
test/tools/llvm-objdump/macho-lazy-bind.test
Normal file
@ -0,0 +1,7 @@
|
||||
# RUN: llvm-objdump -macho -lazy-bind -arch x86_64 \
|
||||
# RUN: %p/Inputs/lazy-bind.macho-x86_64 | FileCheck %s
|
||||
|
||||
|
||||
# CHECK: __DATA __la_symbol_ptr 0x100001010 libfoo.dylib _foo
|
||||
# CHECK: __DATA __la_symbol_ptr 0x100001018 libbar.dylib _bar
|
||||
# CHECK: __DATA __la_symbol_ptr 0x100001020 libSystem.B.dylib _malloc
|
10
test/tools/llvm-objdump/macho-weak-bind.test
Normal file
10
test/tools/llvm-objdump/macho-weak-bind.test
Normal file
@ -0,0 +1,10 @@
|
||||
# RUN: llvm-objdump -macho -weak-bind -arch x86_64 \
|
||||
# RUN: %p/Inputs/weak-bind.macho-x86_64 | FileCheck %s
|
||||
|
||||
|
||||
# CHECK: __DATA __data 0x100001018 pointer 0 __ZTISt12out_of_range
|
||||
# CHECK: __DATA __data 0x100001020 pointer 0 __ZTISt12out_of_range
|
||||
# CHECK: __DATA __data 0x100001028 pointer 0 __ZTISt12out_of_range
|
||||
# CHECK: strong __ZdlPv
|
||||
# CHECK: __DATA __data 0x100001018 pointer 0 __Znam
|
||||
# CHECK: strong __Znwm
|
@ -2178,7 +2178,7 @@ private:
|
||||
|
||||
SegInfo::SegInfo(const object::MachOObjectFile *Obj) {
|
||||
// Build table of sections so segIndex/offset pairs can be translated.
|
||||
uint32_t CurSegIndex = 0;
|
||||
uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
|
||||
StringRef CurSegName;
|
||||
uint64_t CurSegAddress;
|
||||
for (const SectionRef &Section : Obj->sections()) {
|
||||
@ -2253,3 +2253,118 @@ void llvm::printMachORebaseTable(const object::MachOObjectFile *Obj) {
|
||||
Entry.typeName().str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
|
||||
StringRef DylibName;
|
||||
switch (Ordinal) {
|
||||
case MachO::BIND_SPECIAL_DYLIB_SELF:
|
||||
return "this-image";
|
||||
case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
|
||||
return "main-executable";
|
||||
case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
|
||||
return "flat-namespace";
|
||||
default:
|
||||
Obj->getLibraryShortNameByIndex(Ordinal-1, DylibName);
|
||||
return DylibName;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// bind table dumping
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) {
|
||||
// Build table of sections so names can used in final output.
|
||||
SegInfo sectionTable(Obj);
|
||||
|
||||
outs() << "segment section address type "
|
||||
"addend dylib symbol\n";
|
||||
for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) {
|
||||
uint32_t SegIndex = Entry.segmentIndex();
|
||||
uint64_t OffsetInSeg = Entry.segmentOffset();
|
||||
StringRef SegmentName = sectionTable.segmentName(SegIndex);
|
||||
StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
|
||||
uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
|
||||
|
||||
// Table lines look like:
|
||||
// __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
|
||||
outs() << format("%-8s %-18s 0x%08" PRIX64 " %-8s %-8" PRId64 " %-20s",
|
||||
SegmentName.str().c_str(),
|
||||
SectionName.str().c_str(),
|
||||
Address,
|
||||
Entry.typeName().str().c_str(),
|
||||
Entry.addend(),
|
||||
ordinalName(Obj, Entry.ordinal()))
|
||||
<< Entry.symbolName();
|
||||
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
|
||||
outs() << " (weak_import)\n";
|
||||
else
|
||||
outs() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// lazy bind table dumping
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) {
|
||||
// Build table of sections so names can used in final output.
|
||||
SegInfo sectionTable(Obj);
|
||||
|
||||
outs() << "segment section address "
|
||||
"dylib symbol\n";
|
||||
for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable()) {
|
||||
uint32_t SegIndex = Entry.segmentIndex();
|
||||
uint64_t OffsetInSeg = Entry.segmentOffset();
|
||||
StringRef SegmentName = sectionTable.segmentName(SegIndex);
|
||||
StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
|
||||
uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
|
||||
|
||||
// Table lines look like:
|
||||
// __DATA __got 0x00012010 libSystem ___stack_chk_guard
|
||||
outs() << format("%-8s %-18s 0x%08" PRIX64 " %-20s",
|
||||
SegmentName.str().c_str(),
|
||||
SectionName.str().c_str(),
|
||||
Address,
|
||||
ordinalName(Obj, Entry.ordinal()))
|
||||
<< Entry.symbolName() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// weak bind table dumping
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
|
||||
// Build table of sections so names can used in final output.
|
||||
SegInfo sectionTable(Obj);
|
||||
|
||||
outs() << "segment section address "
|
||||
"type addend symbol\n";
|
||||
for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable()) {
|
||||
// Strong symbols don't have a location to update.
|
||||
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
|
||||
outs() << " strong "
|
||||
<< Entry.symbolName() << "\n";
|
||||
continue;
|
||||
}
|
||||
uint32_t SegIndex = Entry.segmentIndex();
|
||||
uint64_t OffsetInSeg = Entry.segmentOffset();
|
||||
StringRef SegmentName = sectionTable.segmentName(SegIndex);
|
||||
StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
|
||||
uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
|
||||
|
||||
// Table lines look like:
|
||||
// __DATA __data 0x00001000 pointer 0 _foo
|
||||
outs() << format("%-8s %-18s 0x%08" PRIX64 " %-8s %-8" PRId64 " ",
|
||||
SegmentName.str().c_str(),
|
||||
SectionName.str().c_str(),
|
||||
Address,
|
||||
Entry.typeName().str().c_str(),
|
||||
Entry.addend())
|
||||
<< Entry.symbolName() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,6 +84,15 @@ ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
|
||||
static cl::opt<bool>
|
||||
Rebase("rebase", cl::desc("Display mach-o rebasing info"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Bind("bind", cl::desc("Display mach-o binding info"));
|
||||
|
||||
static cl::opt<bool>
|
||||
LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
|
||||
|
||||
static cl::opt<bool>
|
||||
WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
|
||||
|
||||
static cl::opt<bool>
|
||||
MachOOpt("macho", cl::desc("Use MachO specific object file parser"));
|
||||
static cl::alias
|
||||
@ -736,6 +745,38 @@ static void printRebaseTable(const ObjectFile *o) {
|
||||
}
|
||||
}
|
||||
|
||||
static void printBindTable(const ObjectFile *o) {
|
||||
outs() << "Bind table:\n";
|
||||
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
||||
printMachOBindTable(MachO);
|
||||
else {
|
||||
errs() << "This operation is only currently supported "
|
||||
"for Mach-O executable files.\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void printLazyBindTable(const ObjectFile *o) {
|
||||
outs() << "Lazy bind table:\n";
|
||||
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
||||
printMachOLazyBindTable(MachO);
|
||||
else {
|
||||
errs() << "This operation is only currently supported "
|
||||
"for Mach-O executable files.\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void printWeakBindTable(const ObjectFile *o) {
|
||||
outs() << "Weak bind table:\n";
|
||||
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
||||
printMachOWeakBindTable(MachO);
|
||||
else {
|
||||
errs() << "This operation is only currently supported "
|
||||
"for Mach-O executable files.\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void printPrivateFileHeader(const ObjectFile *o) {
|
||||
if (o->isELF()) {
|
||||
@ -770,6 +811,12 @@ static void DumpObject(const ObjectFile *o) {
|
||||
printExportsTrie(o);
|
||||
if (Rebase)
|
||||
printRebaseTable(o);
|
||||
if (Bind)
|
||||
printBindTable(o);
|
||||
if (LazyBind)
|
||||
printLazyBindTable(o);
|
||||
if (WeakBind)
|
||||
printWeakBindTable(o);
|
||||
}
|
||||
|
||||
/// @brief Dump each object file in \a a;
|
||||
@ -853,7 +900,10 @@ int main(int argc, char **argv) {
|
||||
&& !UnwindInfo
|
||||
&& !PrivateHeaders
|
||||
&& !ExportsTrie
|
||||
&& !Rebase) {
|
||||
&& !Rebase
|
||||
&& !Bind
|
||||
&& !LazyBind
|
||||
&& !WeakBind) {
|
||||
cl::PrintHelpMessage();
|
||||
return 2;
|
||||
}
|
||||
|
@ -37,6 +37,9 @@ void printCOFFUnwindInfo(const object::COFFObjectFile* o);
|
||||
void printMachOUnwindInfo(const object::MachOObjectFile* o);
|
||||
void printMachOExportsTrie(const object::MachOObjectFile* o);
|
||||
void printMachORebaseTable(const object::MachOObjectFile* o);
|
||||
void printMachOBindTable(const object::MachOObjectFile* o);
|
||||
void printMachOLazyBindTable(const object::MachOObjectFile* o);
|
||||
void printMachOWeakBindTable(const object::MachOObjectFile* o);
|
||||
void printELFFileHeader(const object::ObjectFile *o);
|
||||
void printCOFFFileHeader(const object::ObjectFile *o);
|
||||
void printMachOFileHeader(const object::ObjectFile *o);
|
||||
|
Loading…
Reference in New Issue
Block a user