[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:
Nick Kledzik 2014-09-16 01:41:51 +00:00
parent 2e363ece75
commit 367cf70f27
11 changed files with 544 additions and 3 deletions

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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

View 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

View 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

View File

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

View File

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

View File

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