#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Config/config.h"
-#include "llvm/DebugInfo/DWARF/DIContext.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
static cl::opt<bool> NoLeadingAddr("no-leading-addr",
cl::desc("Print no leading address"));
-static cl::opt<bool>
- PrintImmHex("print-imm-hex",
- cl::desc("Use hex format for immediate values"));
-
cl::opt<bool> llvm::UniversalHeaders("universal-headers",
cl::desc("Print Mach-O universal headers "
"(requires -macho)"));
cl::desc("Print archive headers for Mach-O archives "
"(requires -macho)"));
+cl::opt<bool>
+ ArchiveMemberOffsets("archive-member-offsets",
+ cl::desc("Print the offset to each archive member for "
+ "Mach-O archives (requires -macho and "
+ "-archive-headers)"));
+
cl::opt<bool>
llvm::IndirectSymbols("indirect-symbols",
cl::desc("Print indirect symbol table for Mach-O "
case MachO::DICE_KIND_DATA:
if (Length >= 4) {
if (!NoShowRawInsn)
- DumpBytes(ArrayRef<uint8_t>(bytes, 4));
+ dumpBytes(ArrayRef<uint8_t>(bytes, 4), outs());
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
Size = 4;
} else if (Length >= 2) {
if (!NoShowRawInsn)
- DumpBytes(ArrayRef<uint8_t>(bytes, 2));
+ dumpBytes(ArrayRef<uint8_t>(bytes, 2), outs());
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << Value;
Size = 2;
} else {
if (!NoShowRawInsn)
- DumpBytes(ArrayRef<uint8_t>(bytes, 2));
+ dumpBytes(ArrayRef<uint8_t>(bytes, 2), outs());
Value = bytes[0];
outs() << "\t.byte " << Value;
Size = 1;
break;
case MachO::DICE_KIND_JUMP_TABLE8:
if (!NoShowRawInsn)
- DumpBytes(ArrayRef<uint8_t>(bytes, 1));
+ dumpBytes(ArrayRef<uint8_t>(bytes, 1), outs());
Value = bytes[0];
outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
Size = 1;
break;
case MachO::DICE_KIND_JUMP_TABLE16:
if (!NoShowRawInsn)
- DumpBytes(ArrayRef<uint8_t>(bytes, 2));
+ dumpBytes(ArrayRef<uint8_t>(bytes, 2), outs());
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << format("%5u", Value & 0xffff)
<< "\t@ KIND_JUMP_TABLE16\n";
case MachO::DICE_KIND_JUMP_TABLE32:
case MachO::DICE_KIND_ABS_JUMP_TABLE32:
if (!NoShowRawInsn)
- DumpBytes(ArrayRef<uint8_t>(bytes, 4));
+ dumpBytes(ArrayRef<uint8_t>(bytes, 4), outs());
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
return Size;
}
-static void getSectionsAndSymbols(const MachO::mach_header Header,
- MachOObjectFile *MachOObj,
+static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
std::vector<SectionRef> &Sections,
std::vector<SymbolRef> &Symbols,
SmallVectorImpl<uint64_t> &FoundFns,
Sections.push_back(Section);
}
- MachOObjectFile::LoadCommandInfo Command =
- MachOObj->getFirstLoadCommandInfo();
bool BaseSegmentAddressSet = false;
- for (unsigned i = 0;; ++i) {
+ for (const auto &Command : MachOObj->load_commands()) {
if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
// We found a function starts segment, parse the addresses for later
// consumption.
BaseSegmentAddress = SLC.vmaddr;
}
}
-
- if (i == Header.ncmds - 1)
- break;
- else
- Command = MachOObj->getNextLoadCommandInfo(Command);
}
}
}
static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
- uint32_t LoadCommandCount = O->getHeader().ncmds;
- MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo();
- for (unsigned I = 0;; ++I) {
+ for (const auto &Load : O->load_commands()) {
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
for (unsigned J = 0; J < Seg.nsects; ++J) {
}
}
}
- if (I == LoadCommandCount - 1)
- break;
- else
- Load = O->getNextLoadCommandInfo(Load);
}
}
}
static void PrintDylibs(MachOObjectFile *O, bool JustId) {
- uint32_t LoadCommandCount = O->getHeader().ncmds;
- MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo();
- for (unsigned I = 0;; ++I) {
+ unsigned Index = 0;
+ for (const auto &Load : O->load_commands()) {
if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
(!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
Load.C.cmd == MachO::LC_LOAD_DYLIB ||
outs() << "LC_LOAD_UPWARD_DYLIB ";
else
outs() << "LC_??? ";
- outs() << "command " << I << "\n";
+ outs() << "command " << Index++ << "\n";
}
}
- if (I == LoadCommandCount - 1)
- break;
- else
- Load = O->getNextLoadCommandInfo(Load);
}
}
// Set the size of the literal pointer.
uint32_t lp_size = O->is64Bit() ? 8 : 4;
- // Collect the external relocation symbols for the the literal pointers.
+ // Collect the external relocation symbols for the literal pointers.
std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
for (const RelocationRef &Reloc : Section.relocations()) {
DataRefImpl Rel;
static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
StringRef DisSegName, StringRef DisSectName);
+static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
+ uint32_t size, uint32_t addr);
static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
bool verbose) {
outs() << sect;
continue;
}
+ if (SegName == "__OBJC" && SectName == "__protocol") {
+ DumpProtocolSection(O, sect, sect_size, sect_addr);
+ continue;
+ }
switch (section_type) {
case MachO::S_REGULAR:
DumpRawSectionContents(O, sect, sect_size, sect_addr);
if (Archive *A = dyn_cast<Archive>(&Bin)) {
outs() << "Archive : " << Filename << "\n";
if (ArchiveHeaders)
- printArchiveHeaders(A, true, false);
+ printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator I = A->child_begin(), E = A->child_end();
I != E; ++I) {
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary();
outs() << " (architecture " << ArchitectureName << ")";
outs() << "\n";
if (ArchiveHeaders)
- printArchiveHeaders(A.get(), true, false);
+ printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
std::unique_ptr<Archive> &A = *AOrErr;
outs() << "Archive : " << Filename << "\n";
if (ArchiveHeaders)
- printArchiveHeaders(A.get(), true, false);
+ printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
outs() << " (architecture " << ArchitectureName << ")";
outs() << "\n";
if (ArchiveHeaders)
- printArchiveHeaders(A.get(), true, false);
+ printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
AI != AE; ++AI) {
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
// it returns a pointer to that string. Else it returns nullptr.
static const char *GuessCstringPointer(uint64_t ReferenceValue,
struct DisassembleInfo *info) {
- uint32_t LoadCommandCount = info->O->getHeader().ncmds;
- MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo();
- for (unsigned I = 0;; ++I) {
+ for (const auto &Load : info->O->load_commands()) {
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
for (unsigned J = 0; J < Seg.nsects; ++J) {
}
}
}
- if (I == LoadCommandCount - 1)
- break;
- else
- Load = info->O->getNextLoadCommandInfo(Load);
}
return nullptr;
}
// symbol name being referenced by the stub or pointer.
static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
struct DisassembleInfo *info) {
- uint32_t LoadCommandCount = info->O->getHeader().ncmds;
- MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo();
MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
- for (unsigned I = 0;; ++I) {
+ for (const auto &Load : info->O->load_commands()) {
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
for (unsigned J = 0; J < Seg.nsects; ++J) {
}
}
}
- if (I == LoadCommandCount - 1)
- break;
- else
- Load = info->O->getNextLoadCommandInfo(Load);
}
return nullptr;
}
selref = false;
msgref = false;
cfstring = false;
- uint32_t LoadCommandCount = info->O->getHeader().ncmds;
- MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo();
- for (unsigned I = 0;; ++I) {
+ for (const auto &Load : info->O->load_commands()) {
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
for (unsigned J = 0; J < Seg.nsects; ++J) {
}
}
// TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
- if (I == LoadCommandCount - 1)
- break;
- else
- Load = info->O->getNextLoadCommandInfo(Load);
}
return 0;
}
// for the specified section offset in the specified section reference.
// If no relocation information is found and a non-zero ReferenceValue for the
// symbol is passed, look up that address in the info's AddrMap.
-static const char *
-get_symbol_64(uint32_t sect_offset, SectionRef S, DisassembleInfo *info,
- uint64_t &n_value,
- uint64_t ReferenceValue = UnknownAddressOrSize) {
+static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
+ DisassembleInfo *info, uint64_t &n_value,
+ uint64_t ReferenceValue = UnknownAddress) {
n_value = 0;
if (!info->verbose)
return nullptr;
const char *SymbolName = nullptr;
if (reloc_found && isExtern) {
Symbol.getAddress(n_value);
- if (n_value == UnknownAddressOrSize)
+ if (n_value == UnknownAddress)
n_value = 0;
StringRef name;
Symbol.getName(name);
// We did not find an external relocation entry so look up the ReferenceValue
// as an address of a symbol and if found return that symbol's name.
- if (ReferenceValue != UnknownAddressOrSize)
+ if (ReferenceValue != UnknownAddress)
SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
return SymbolName;
sys::swapByteOrder(module.size);
sys::swapByteOrder(module.name);
sys::swapByteOrder(module.symtab);
-};
+}
inline void swapStruct(struct objc_symtab_t &symtab) {
sys::swapByteOrder(symtab.sel_ref_cnt);
sys::swapByteOrder(symtab.refs);
sys::swapByteOrder(symtab.cls_def_cnt);
sys::swapByteOrder(symtab.cat_def_cnt);
-};
+}
inline void swapStruct(struct objc_class_t &objc_class) {
sys::swapByteOrder(objc_class.isa);
sys::swapByteOrder(objc_class.methodLists);
sys::swapByteOrder(objc_class.cache);
sys::swapByteOrder(objc_class.protocols);
-};
+}
inline void swapStruct(struct objc_category_t &objc_category) {
sys::swapByteOrder(objc_category.category_name);
sys::swapByteOrder(objc_ivar.ivar_name);
sys::swapByteOrder(objc_ivar.ivar_type);
sys::swapByteOrder(objc_ivar.ivar_offset);
-};
+}
inline void swapStruct(struct objc_method_list_t &method_list) {
sys::swapByteOrder(method_list.obsolete);
return true;
}
+static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
+ uint32_t size, uint32_t addr) {
+ SymbolAddressMap AddrMap;
+ CreateSymbolAddressMap(O, &AddrMap);
+
+ std::vector<SectionRef> Sections;
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ Sections.push_back(Section);
+ }
+
+ struct DisassembleInfo info;
+ // Set up the block of info used by the Symbolizer call backs.
+ info.verbose = true;
+ info.O = O;
+ info.AddrMap = &AddrMap;
+ info.Sections = &Sections;
+ info.class_name = nullptr;
+ info.selector_name = nullptr;
+ info.method = nullptr;
+ info.demangled_name = nullptr;
+ info.bindtable = nullptr;
+ info.adrp_addr = 0;
+ info.adrp_inst = 0;
+
+ const char *p;
+ struct objc_protocol_t protocol;
+ uint32_t left, paddr;
+ for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {
+ memset(&protocol, '\0', sizeof(struct objc_protocol_t));
+ left = size - (p - sect);
+ if (left < sizeof(struct objc_protocol_t)) {
+ outs() << "Protocol extends past end of __protocol section\n";
+ memcpy(&protocol, p, left);
+ } else
+ memcpy(&protocol, p, sizeof(struct objc_protocol_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(protocol);
+ paddr = addr + (p - sect);
+ outs() << "Protocol " << format("0x%" PRIx32, paddr);
+ if (print_protocol(paddr, 0, &info))
+ outs() << "(not in an __OBJC section)\n";
+ }
+}
+
static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
if (O->is64Bit())
printObjc2_64bit_MetaData(O, verbose);
SmallVector<uint64_t, 8> FoundFns;
uint64_t BaseSegmentAddress;
- getSectionsAndSymbols(Header, MachOOF, Sections, Symbols, FoundFns,
+ getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,
BaseSegmentAddress);
// Sort the symbols by address, just in case they didn't come in that way.
}
// Setup the DIContext
- diContext.reset(DIContext::getDWARFContext(*DbgObj));
+ diContext.reset(new DWARFContextInMemory(*DbgObj));
}
if (DumpSections.size() == 0)
DebugOut, Annotations);
if (gotInst) {
if (!NoShowRawInsn) {
- DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size));
+ dumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size), outs());
}
formatted_raw_ostream FormattedOS(outs());
Annotations.flush();
}
if (!NoShowRawInsn) {
outs() << "\t";
- DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, InstSize));
+ dumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, InstSize), outs());
}
IP->printInst(&Inst, outs(), "", *STI);
outs() << "\n";
}
auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
- SectionRef RelocSection = Obj->getRelocationSection(RE);
+ SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
uint64_t SectionAddr = RelocSection.getAddress();
outs() << "\n";
}
-static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds,
- uint32_t filetype, uint32_t cputype,
- bool verbose) {
- if (ncmds == 0)
- return;
+static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
+ uint32_t cputype, bool verbose) {
StringRef Buf = Obj->getData();
- MachOObjectFile::LoadCommandInfo Command = Obj->getFirstLoadCommandInfo();
- for (unsigned i = 0;; ++i) {
- outs() << "Load command " << i << "\n";
+ unsigned Index = 0;
+ for (const auto &Command : Obj->load_commands()) {
+ outs() << "Load command " << Index++ << "\n";
if (Command.C.cmd == MachO::LC_SEGMENT) {
MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);
const char *sg_segname = SLC.segname;
// TODO: get and print the raw bytes of the load command.
}
// TODO: print all the other kinds of load commands.
- if (i == ncmds - 1)
- break;
- else
- Command = Obj->getNextLoadCommandInfo(Command);
}
}
-static void getAndPrintMachHeader(const MachOObjectFile *Obj, uint32_t &ncmds,
+static void getAndPrintMachHeader(const MachOObjectFile *Obj,
uint32_t &filetype, uint32_t &cputype,
bool verbose) {
if (Obj->is64Bit()) {
H_64 = Obj->getHeader64();
PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,
H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);
- ncmds = H_64.ncmds;
filetype = H_64.filetype;
cputype = H_64.cputype;
} else {
H = Obj->getHeader();
PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,
H.sizeofcmds, H.flags, verbose);
- ncmds = H.ncmds;
filetype = H.filetype;
cputype = H.cputype;
}
void llvm::printMachOFileHeader(const object::ObjectFile *Obj) {
const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
- uint32_t ncmds = 0;
uint32_t filetype = 0;
uint32_t cputype = 0;
- getAndPrintMachHeader(file, ncmds, filetype, cputype, !NonVerbose);
- PrintLoadCommands(file, ncmds, filetype, cputype, !NonVerbose);
+ getAndPrintMachHeader(file, filetype, cputype, !NonVerbose);
+ PrintLoadCommands(file, filetype, cputype, !NonVerbose);
}
//===----------------------------------------------------------------------===//