aboutsummaryrefslogtreecommitdiffstats
path: root/tools/llvm-objdump/MachODump.cpp
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2015-04-01 18:49:24 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-04-01 18:49:26 +0000
commit3fa16bd6062e23bcdb82ed4dd965674792e6b761 (patch)
tree9348fc507292f7e8715d22d64ce5a32131b4f875 /tools/llvm-objdump/MachODump.cpp
parentbeed47390a60f6f0c77532b3d3f76bb47ef49423 (diff)
parentebe69fe11e48d322045d5949c83283927a0d790b (diff)
downloadexternal_llvm-3fa16bd6062e23bcdb82ed4dd965674792e6b761.zip
external_llvm-3fa16bd6062e23bcdb82ed4dd965674792e6b761.tar.gz
external_llvm-3fa16bd6062e23bcdb82ed4dd965674792e6b761.tar.bz2
Merge "Update aosp/master LLVM for rebase to r230699."
Diffstat (limited to 'tools/llvm-objdump/MachODump.cpp')
-rw-r--r--tools/llvm-objdump/MachODump.cpp2052
1 files changed, 1960 insertions, 92 deletions
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index 3a28703..cae4356 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -17,7 +17,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Config/config.h"
-#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DIContext.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
@@ -28,15 +28,17 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Object/MachO.h"
+#include "llvm/Object/MachOUniversal.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
@@ -65,6 +67,40 @@ 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::opt<bool>
+ llvm::ArchiveHeaders("archive-headers",
+ cl::desc("Print archive headers for Mach-O archives "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ llvm::IndirectSymbols("indirect-symbols",
+ cl::desc("Print indirect symbol table for Mach-O "
+ "objects (requires -macho)"));
+
+cl::opt<bool>
+ llvm::DataInCode("data-in-code",
+ cl::desc("Print the data in code table for Mach-O objects "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ llvm::LinkOptHints("link-opt-hints",
+ cl::desc("Print the linker optimization hints for "
+ "Mach-O objects (requires -macho)"));
+
+cl::list<std::string>
+ llvm::DumpSections("section",
+ cl::desc("Prints the specified segment,section for "
+ "Mach-O objects (requires -macho)"));
+
+static cl::list<std::string>
+ ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
+ cl::ZeroOrMore);
+bool ArchAll = false;
+
static std::string ThumbTripleName;
static const Target *GetTarget(const MachOObjectFile *MachOObj,
@@ -205,8 +241,12 @@ static void getSectionsAndSymbols(const MachO::mach_header Header,
std::vector<SymbolRef> &Symbols,
SmallVectorImpl<uint64_t> &FoundFns,
uint64_t &BaseSegmentAddress) {
- for (const SymbolRef &Symbol : MachOObj->symbols())
- Symbols.push_back(Symbol);
+ for (const SymbolRef &Symbol : MachOObj->symbols()) {
+ StringRef SymName;
+ Symbol.getName(SymName);
+ if (!SymName.startswith("ltmp"))
+ Symbols.push_back(Symbol);
+ }
for (const SectionRef &Section : MachOObj->sections()) {
StringRef SectName;
@@ -241,25 +281,1298 @@ static void getSectionsAndSymbols(const MachO::mach_header Header,
}
}
-static void DisassembleInputMachO2(StringRef Filename,
- MachOObjectFile *MachOOF);
+static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
+ uint32_t n, uint32_t count,
+ uint32_t stride, uint64_t addr) {
+ MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
+ uint32_t nindirectsyms = Dysymtab.nindirectsyms;
+ if (n > nindirectsyms)
+ outs() << " (entries start past the end of the indirect symbol "
+ "table) (reserved1 field greater than the table size)";
+ else if (n + count > nindirectsyms)
+ outs() << " (entries extends past the end of the indirect symbol "
+ "table)";
+ outs() << "\n";
+ uint32_t cputype = O->getHeader().cputype;
+ if (cputype & MachO::CPU_ARCH_ABI64)
+ outs() << "address index";
+ else
+ outs() << "address index";
+ if (verbose)
+ outs() << " name\n";
+ else
+ outs() << "\n";
+ for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
+ if (cputype & MachO::CPU_ARCH_ABI64)
+ outs() << format("0x%016" PRIx64, addr + j * stride) << " ";
+ else
+ outs() << format("0x%08" PRIx32, addr + j * stride) << " ";
+ MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
+ uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);
+ if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
+ outs() << "LOCAL\n";
+ continue;
+ }
+ if (indirect_symbol ==
+ (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
+ outs() << "LOCAL ABSOLUTE\n";
+ continue;
+ }
+ if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
+ outs() << "ABSOLUTE\n";
+ continue;
+ }
+ outs() << format("%5u ", indirect_symbol);
+ MachO::symtab_command Symtab = O->getSymtabLoadCommand();
+ if (indirect_symbol < Symtab.nsyms) {
+ symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
+ SymbolRef Symbol = *Sym;
+ StringRef SymName;
+ Symbol.getName(SymName);
+ outs() << SymName;
+ } else {
+ outs() << "?";
+ }
+ outs() << "\n";
+ }
+}
-void llvm::DisassembleInputMachO(StringRef Filename) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
- MemoryBuffer::getFileOrSTDIN(Filename);
- if (std::error_code EC = BuffOrErr.getError()) {
- errs() << "llvm-objdump: " << Filename << ": " << EC.message() << "\n";
- return;
+static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
+ uint32_t LoadCommandCount = O->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo();
+ for (unsigned I = 0;; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = O->getSection64(Load, J);
+ uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
+ if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
+ section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
+ section_type == MachO::S_SYMBOL_STUBS) {
+ uint32_t stride;
+ if (section_type == MachO::S_SYMBOL_STUBS)
+ stride = Sec.reserved2;
+ else
+ stride = 8;
+ if (stride == 0) {
+ outs() << "Can't print indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") "
+ << "(size of stubs in reserved2 field is zero)\n";
+ continue;
+ }
+ uint32_t count = Sec.size / stride;
+ outs() << "Indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") " << count << " entries";
+ uint32_t n = Sec.reserved1;
+ PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
+ }
+ }
+ } else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = O->getSection(Load, J);
+ uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
+ if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
+ section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
+ section_type == MachO::S_SYMBOL_STUBS) {
+ uint32_t stride;
+ if (section_type == MachO::S_SYMBOL_STUBS)
+ stride = Sec.reserved2;
+ else
+ stride = 4;
+ if (stride == 0) {
+ outs() << "Can't print indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") "
+ << "(size of stubs in reserved2 field is zero)\n";
+ continue;
+ }
+ uint32_t count = Sec.size / stride;
+ outs() << "Indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") " << count << " entries";
+ uint32_t n = Sec.reserved1;
+ PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
+ }
+ }
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = O->getNextLoadCommandInfo(Load);
}
- std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get());
+}
- std::unique_ptr<MachOObjectFile> MachOOF = std::move(
- ObjectFile::createMachOObjectFile(Buff.get()->getMemBufferRef()).get());
+static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
+ MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
+ uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
+ outs() << "Data in code table (" << nentries << " entries)\n";
+ outs() << "offset length kind\n";
+ for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
+ ++DI) {
+ uint32_t Offset;
+ DI->getOffset(Offset);
+ outs() << format("0x%08" PRIx32, Offset) << " ";
+ uint16_t Length;
+ DI->getLength(Length);
+ outs() << format("%6u", Length) << " ";
+ uint16_t Kind;
+ DI->getKind(Kind);
+ if (verbose) {
+ switch (Kind) {
+ case MachO::DICE_KIND_DATA:
+ outs() << "DATA";
+ break;
+ case MachO::DICE_KIND_JUMP_TABLE8:
+ outs() << "JUMP_TABLE8";
+ break;
+ case MachO::DICE_KIND_JUMP_TABLE16:
+ outs() << "JUMP_TABLE16";
+ break;
+ case MachO::DICE_KIND_JUMP_TABLE32:
+ outs() << "JUMP_TABLE32";
+ break;
+ case MachO::DICE_KIND_ABS_JUMP_TABLE32:
+ outs() << "ABS_JUMP_TABLE32";
+ break;
+ default:
+ outs() << format("0x%04" PRIx32, Kind);
+ break;
+ }
+ } else
+ outs() << format("0x%04" PRIx32, Kind);
+ outs() << "\n";
+ }
+}
+
+static void PrintLinkOptHints(MachOObjectFile *O) {
+ MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
+ const char *loh = O->getData().substr(LohLC.dataoff, 1).data();
+ uint32_t nloh = LohLC.datasize;
+ outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
+ for (uint32_t i = 0; i < nloh;) {
+ unsigned n;
+ uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);
+ i += n;
+ outs() << " identifier " << identifier << " ";
+ if (i >= nloh)
+ return;
+ switch (identifier) {
+ case 1:
+ outs() << "AdrpAdrp\n";
+ break;
+ case 2:
+ outs() << "AdrpLdr\n";
+ break;
+ case 3:
+ outs() << "AdrpAddLdr\n";
+ break;
+ case 4:
+ outs() << "AdrpLdrGotLdr\n";
+ break;
+ case 5:
+ outs() << "AdrpAddStr\n";
+ break;
+ case 6:
+ outs() << "AdrpLdrGotStr\n";
+ break;
+ case 7:
+ outs() << "AdrpAdd\n";
+ break;
+ case 8:
+ outs() << "AdrpLdrGot\n";
+ break;
+ default:
+ outs() << "Unknown identifier value\n";
+ break;
+ }
+ uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);
+ i += n;
+ outs() << " narguments " << narguments << "\n";
+ if (i >= nloh)
+ return;
- DisassembleInputMachO2(Filename, MachOOF.get());
+ for (uint32_t j = 0; j < narguments; j++) {
+ uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);
+ i += n;
+ outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";
+ if (i >= nloh)
+ return;
+ }
+ }
}
typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
+
+static void CreateSymbolAddressMap(MachOObjectFile *O,
+ SymbolAddressMap *AddrMap) {
+ // Create a map of symbol addresses to symbol names.
+ for (const SymbolRef &Symbol : O->symbols()) {
+ SymbolRef::Type ST;
+ Symbol.getType(ST);
+ if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
+ ST == SymbolRef::ST_Other) {
+ uint64_t Address;
+ Symbol.getAddress(Address);
+ StringRef SymName;
+ Symbol.getName(SymName);
+ (*AddrMap)[Address] = SymName;
+ }
+ }
+}
+
+// GuessSymbolName is passed the address of what might be a symbol and a
+// pointer to the SymbolAddressMap. It returns the name of a symbol
+// with that address or nullptr if no symbol is found with that address.
+static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
+ const char *SymbolName = nullptr;
+ // A DenseMap can't lookup up some values.
+ if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
+ StringRef name = AddrMap->lookup(value);
+ if (!name.empty())
+ SymbolName = name.data();
+ }
+ return SymbolName;
+}
+
+static void DumpCstringChar(const char c) {
+ char p[2];
+ p[0] = c;
+ p[1] = '\0';
+ outs().write_escaped(p);
+}
+
+static void DumpCstringSection(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i++) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ for (; i < sect_size && sect[i] != '\0'; i++)
+ DumpCstringChar(sect[i]);
+ if (i < sect_size && sect[i] == '\0')
+ outs() << "\n";
+ }
+}
+
+static void DumpLiteral4(uint32_t l, float f) {
+ outs() << format("0x%08" PRIx32, l);
+ if ((l & 0x7f800000) != 0x7f800000)
+ outs() << format(" (%.16e)\n", f);
+ else {
+ if (l == 0x7f800000)
+ outs() << " (+Infinity)\n";
+ else if (l == 0xff800000)
+ outs() << " (-Infinity)\n";
+ else if ((l & 0x00400000) == 0x00400000)
+ outs() << " (non-signaling Not-a-Number)\n";
+ else
+ outs() << " (signaling Not-a-Number)\n";
+ }
+}
+
+static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ float f;
+ memcpy(&f, sect + i, sizeof(float));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(f);
+ uint32_t l;
+ memcpy(&l, sect + i, sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(l);
+ DumpLiteral4(l, f);
+ }
+}
+
+static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
+ double d) {
+ outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);
+ uint32_t Hi, Lo;
+ if (O->isLittleEndian()) {
+ Hi = l1;
+ Lo = l0;
+ } else {
+ Hi = l0;
+ Lo = l1;
+ }
+ // Hi is the high word, so this is equivalent to if(isfinite(d))
+ if ((Hi & 0x7ff00000) != 0x7ff00000)
+ outs() << format(" (%.16e)\n", d);
+ else {
+ if (Hi == 0x7ff00000 && Lo == 0)
+ outs() << " (+Infinity)\n";
+ else if (Hi == 0xfff00000 && Lo == 0)
+ outs() << " (-Infinity)\n";
+ else if ((Hi & 0x00080000) == 0x00080000)
+ outs() << " (non-signaling Not-a-Number)\n";
+ else
+ outs() << " (signaling Not-a-Number)\n";
+ }
+}
+
+static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ double d;
+ memcpy(&d, sect + i, sizeof(double));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(d);
+ uint32_t l0, l1;
+ memcpy(&l0, sect + i, sizeof(uint32_t));
+ memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ }
+ DumpLiteral8(O, l0, l1, d);
+ }
+}
+
+static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
+ outs() << format("0x%08" PRIx32, l0) << " ";
+ outs() << format("0x%08" PRIx32, l1) << " ";
+ outs() << format("0x%08" PRIx32, l2) << " ";
+ outs() << format("0x%08" PRIx32, l3) << "\n";
+}
+
+static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i += 16) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ uint32_t l0, l1, l2, l3;
+ memcpy(&l0, sect + i, sizeof(uint32_t));
+ memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
+ memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));
+ memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ sys::swapByteOrder(l2);
+ sys::swapByteOrder(l3);
+ }
+ DumpLiteral16(l0, l1, l2, l3);
+ }
+}
+
+static void DumpLiteralPointerSection(MachOObjectFile *O,
+ const SectionRef &Section,
+ const char *sect, uint32_t sect_size,
+ uint64_t sect_addr,
+ bool print_addresses) {
+ // Collect the literal sections in this Mach-O file.
+ std::vector<SectionRef> LiteralSections;
+ for (const SectionRef &Section : O->sections()) {
+ DataRefImpl Ref = Section.getRawDataRefImpl();
+ uint32_t section_type;
+ if (O->is64Bit()) {
+ const MachO::section_64 Sec = O->getSection64(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ } else {
+ const MachO::section Sec = O->getSection(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ }
+ if (section_type == MachO::S_CSTRING_LITERALS ||
+ section_type == MachO::S_4BYTE_LITERALS ||
+ section_type == MachO::S_8BYTE_LITERALS ||
+ section_type == MachO::S_16BYTE_LITERALS)
+ LiteralSections.push_back(Section);
+ }
+
+ // 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.
+ std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ Rel = Reloc.getRawDataRefImpl();
+ RE = O->getRelocation(Rel);
+ isExtern = O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
+ }
+ }
+ array_pod_sort(Relocs.begin(), Relocs.end());
+
+ // Dump each literal pointer.
+ for (uint32_t i = 0; i < sect_size; i += lp_size) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ uint64_t lp;
+ if (O->is64Bit()) {
+ memcpy(&lp, sect + i, sizeof(uint64_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(lp);
+ } else {
+ uint32_t li;
+ memcpy(&li, sect + i, sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(li);
+ lp = li;
+ }
+
+ // First look for an external relocation entry for this literal pointer.
+ bool reloc_found = false;
+ for (unsigned j = 0, e = Relocs.size(); j != e; ++j) {
+ if (Relocs[i].first == i) {
+ symbol_iterator RelocSym = Relocs[j].second;
+ StringRef SymName;
+ RelocSym->getName(SymName);
+ outs() << "external relocation entry for symbol:" << SymName << "\n";
+ reloc_found = true;
+ }
+ }
+ if (reloc_found == true)
+ continue;
+
+ // For local references see what the section the literal pointer points to.
+ bool found = false;
+ for (unsigned SectIdx = 0; SectIdx != LiteralSections.size(); SectIdx++) {
+ uint64_t SectAddress = LiteralSections[SectIdx].getAddress();
+ uint64_t SectSize = LiteralSections[SectIdx].getSize();
+ if (lp >= SectAddress && lp < SectAddress + SectSize) {
+ found = true;
+
+ StringRef SectName;
+ LiteralSections[SectIdx].getName(SectName);
+ DataRefImpl Ref = LiteralSections[SectIdx].getRawDataRefImpl();
+ StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
+ outs() << SegmentName << ":" << SectName << ":";
+
+ uint32_t section_type;
+ if (O->is64Bit()) {
+ const MachO::section_64 Sec = O->getSection64(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ } else {
+ const MachO::section Sec = O->getSection(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ }
+
+ StringRef BytesStr;
+ LiteralSections[SectIdx].getContents(BytesStr);
+ const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
+
+ switch (section_type) {
+ case MachO::S_CSTRING_LITERALS:
+ for (uint64_t i = lp - SectAddress;
+ i < SectSize && Contents[i] != '\0'; i++) {
+ DumpCstringChar(Contents[i]);
+ }
+ outs() << "\n";
+ break;
+ case MachO::S_4BYTE_LITERALS:
+ float f;
+ memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
+ uint32_t l;
+ memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(f);
+ sys::swapByteOrder(l);
+ }
+ DumpLiteral4(l, f);
+ break;
+ case MachO::S_8BYTE_LITERALS: {
+ double d;
+ memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
+ uint32_t l0, l1;
+ memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
+ memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
+ sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(f);
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ }
+ DumpLiteral8(O, l0, l1, d);
+ break;
+ }
+ case MachO::S_16BYTE_LITERALS: {
+ uint32_t l0, l1, l2, l3;
+ memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
+ memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
+ sizeof(uint32_t));
+ memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
+ sizeof(uint32_t));
+ memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
+ sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ sys::swapByteOrder(l2);
+ sys::swapByteOrder(l3);
+ }
+ DumpLiteral16(l0, l1, l2, l3);
+ break;
+ }
+ }
+ }
+ }
+ if (found == false)
+ outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";
+ }
+}
+
+static void DumpInitTermPointerSection(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ SymbolAddressMap *AddrMap,
+ bool verbose) {
+ uint32_t stride;
+ if (O->is64Bit())
+ stride = sizeof(uint64_t);
+ else
+ stride = sizeof(uint32_t);
+ for (uint32_t i = 0; i < sect_size; i += stride) {
+ const char *SymbolName = nullptr;
+ if (O->is64Bit()) {
+ outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";
+ uint64_t pointer_value;
+ memcpy(&pointer_value, sect + i, stride);
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(pointer_value);
+ outs() << format("0x%016" PRIx64, pointer_value);
+ if (verbose)
+ SymbolName = GuessSymbolName(pointer_value, AddrMap);
+ } else {
+ outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";
+ uint32_t pointer_value;
+ memcpy(&pointer_value, sect + i, stride);
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(pointer_value);
+ outs() << format("0x%08" PRIx32, pointer_value);
+ if (verbose)
+ SymbolName = GuessSymbolName(pointer_value, AddrMap);
+ }
+ if (SymbolName)
+ outs() << " " << SymbolName;
+ outs() << "\n";
+ }
+}
+
+static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
+ uint32_t size, uint64_t addr) {
+ uint32_t cputype = O->getHeader().cputype;
+ if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
+ uint32_t j;
+ for (uint32_t i = 0; i < size; i += j, addr += j) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, addr) << "\t";
+ else
+ outs() << format("%08" PRIx64, sect) << "\t";
+ for (j = 0; j < 16 && i + j < size; j++) {
+ uint8_t byte_word = *(sect + i + j);
+ outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
+ }
+ outs() << "\n";
+ }
+ } else {
+ uint32_t j;
+ for (uint32_t i = 0; i < size; i += j, addr += j) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, addr) << "\t";
+ else
+ outs() << format("%08" PRIx64, sect) << "\t";
+ for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
+ j += sizeof(int32_t)) {
+ if (i + j + sizeof(int32_t) < size) {
+ uint32_t long_word;
+ memcpy(&long_word, sect + i + j, sizeof(int32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(long_word);
+ outs() << format("%08" PRIx32, long_word) << " ";
+ } else {
+ for (uint32_t k = 0; i + j + k < size; k++) {
+ uint8_t byte_word = *(sect + i + j);
+ outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
+ }
+ }
+ }
+ outs() << "\n";
+ }
+ }
+}
+
+static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
+ StringRef DisSegName, StringRef DisSectName);
+
+static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
+ bool verbose) {
+ SymbolAddressMap AddrMap;
+ if (verbose)
+ CreateSymbolAddressMap(O, &AddrMap);
+
+ for (unsigned i = 0; i < DumpSections.size(); ++i) {
+ StringRef DumpSection = DumpSections[i];
+ std::pair<StringRef, StringRef> DumpSegSectName;
+ DumpSegSectName = DumpSection.split(',');
+ StringRef DumpSegName, DumpSectName;
+ if (DumpSegSectName.second.size()) {
+ DumpSegName = DumpSegSectName.first;
+ DumpSectName = DumpSegSectName.second;
+ } else {
+ DumpSegName = "";
+ DumpSectName = DumpSegSectName.first;
+ }
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ DataRefImpl Ref = Section.getRawDataRefImpl();
+ StringRef SegName = O->getSectionFinalSegmentName(Ref);
+ if ((DumpSegName.empty() || SegName == DumpSegName) &&
+ (SectName == DumpSectName)) {
+ outs() << "Contents of (" << SegName << "," << SectName
+ << ") section\n";
+ uint32_t section_flags;
+ if (O->is64Bit()) {
+ const MachO::section_64 Sec = O->getSection64(Ref);
+ section_flags = Sec.flags;
+
+ } else {
+ const MachO::section Sec = O->getSection(Ref);
+ section_flags = Sec.flags;
+ }
+ uint32_t section_type = section_flags & MachO::SECTION_TYPE;
+
+ StringRef BytesStr;
+ Section.getContents(BytesStr);
+ const char *sect = reinterpret_cast<const char *>(BytesStr.data());
+ uint32_t sect_size = BytesStr.size();
+ uint64_t sect_addr = Section.getAddress();
+
+ if (verbose) {
+ if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
+ (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
+ DisassembleMachO(Filename, O, SegName, SectName);
+ continue;
+ }
+ switch (section_type) {
+ case MachO::S_REGULAR:
+ DumpRawSectionContents(O, sect, sect_size, sect_addr);
+ break;
+ case MachO::S_ZEROFILL:
+ outs() << "zerofill section and has no contents in the file\n";
+ break;
+ case MachO::S_CSTRING_LITERALS:
+ DumpCstringSection(O, sect, sect_size, sect_addr, verbose);
+ break;
+ case MachO::S_4BYTE_LITERALS:
+ DumpLiteral4Section(O, sect, sect_size, sect_addr, verbose);
+ break;
+ case MachO::S_8BYTE_LITERALS:
+ DumpLiteral8Section(O, sect, sect_size, sect_addr, verbose);
+ break;
+ case MachO::S_16BYTE_LITERALS:
+ DumpLiteral16Section(O, sect, sect_size, sect_addr, verbose);
+ break;
+ case MachO::S_LITERAL_POINTERS:
+ DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
+ verbose);
+ break;
+ case MachO::S_MOD_INIT_FUNC_POINTERS:
+ case MachO::S_MOD_TERM_FUNC_POINTERS:
+ DumpInitTermPointerSection(O, sect, sect_size, sect_addr, &AddrMap,
+ verbose);
+ break;
+ default:
+ outs() << "Unknown section type ("
+ << format("0x%08" PRIx32, section_type) << ")\n";
+ DumpRawSectionContents(O, sect, sect_size, sect_addr);
+ break;
+ }
+ } else {
+ if (section_type == MachO::S_ZEROFILL)
+ outs() << "zerofill section and has no contents in the file\n";
+ else
+ DumpRawSectionContents(O, sect, sect_size, sect_addr);
+ }
+ }
+ }
+ }
+}
+
+// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
+// and if it is and there is a list of architecture flags is specified then
+// check to make sure this Mach-O file is one of those architectures or all
+// architectures were specified. If not then an error is generated and this
+// routine returns false. Else it returns true.
+static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
+ if (isa<MachOObjectFile>(O) && !ArchAll && ArchFlags.size() != 0) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O);
+ bool ArchFound = false;
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ Triple T;
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
+ }
+ unsigned i;
+ for (i = 0; i < ArchFlags.size(); ++i) {
+ if (ArchFlags[i] == T.getArchName())
+ ArchFound = true;
+ break;
+ }
+ if (!ArchFound) {
+ errs() << "llvm-objdump: file: " + Filename + " does not contain "
+ << "architecture: " + ArchFlags[i] + "\n";
+ return false;
+ }
+ }
+ return true;
+}
+
+// ProcessMachO() is passed a single opened Mach-O file, which may be an
+// archive member and or in a slice of a universal file. It prints the
+// the file name and header info and then processes it according to the
+// command line options.
+static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
+ StringRef ArchiveMemberName = StringRef(),
+ StringRef ArchitectureName = StringRef()) {
+ // If we are doing some processing here on the Mach-O file print the header
+ // info. And don't print it otherwise like in the case of printing the
+ // UniversalHeaders or ArchiveHeaders.
+ if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind ||
+ LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints ||
+ DumpSections.size() != 0) {
+ outs() << Filename;
+ if (!ArchiveMemberName.empty())
+ outs() << '(' << ArchiveMemberName << ')';
+ if (!ArchitectureName.empty())
+ outs() << " (architecture " << ArchitectureName << ")";
+ outs() << ":\n";
+ }
+
+ if (Disassemble)
+ DisassembleMachO(Filename, MachOOF, "__TEXT", "__text");
+ if (IndirectSymbols)
+ PrintIndirectSymbols(MachOOF, true);
+ if (DataInCode)
+ PrintDataInCodeTable(MachOOF, true);
+ if (LinkOptHints)
+ PrintLinkOptHints(MachOOF);
+ if (Relocations)
+ PrintRelocations(MachOOF);
+ if (SectionHeaders)
+ PrintSectionHeaders(MachOOF);
+ if (SectionContents)
+ PrintSectionContents(MachOOF);
+ if (DumpSections.size() != 0)
+ DumpSectionContents(Filename, MachOOF, true);
+ if (SymbolTable)
+ PrintSymbolTable(MachOOF);
+ if (UnwindInfo)
+ printMachOUnwindInfo(MachOOF);
+ if (PrivateHeaders)
+ printMachOFileHeader(MachOOF);
+ if (ExportsTrie)
+ printExportsTrie(MachOOF);
+ if (Rebase)
+ printRebaseTable(MachOOF);
+ if (Bind)
+ printBindTable(MachOOF);
+ if (LazyBind)
+ printLazyBindTable(MachOOF);
+ if (WeakBind)
+ printWeakBindTable(MachOOF);
+}
+
+// printUnknownCPUType() helps print_fat_headers for unknown CPU's.
+static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {
+ outs() << " cputype (" << cputype << ")\n";
+ outs() << " cpusubtype (" << cpusubtype << ")\n";
+}
+
+// printCPUType() helps print_fat_headers by printing the cputype and
+// pusubtype (symbolically for the one's it knows about).
+static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
+ switch (cputype) {
+ case MachO::CPU_TYPE_I386:
+ switch (cpusubtype) {
+ case MachO::CPU_SUBTYPE_I386_ALL:
+ outs() << " cputype CPU_TYPE_I386\n";
+ outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";
+ break;
+ default:
+ printUnknownCPUType(cputype, cpusubtype);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_X86_64:
+ switch (cpusubtype) {
+ case MachO::CPU_SUBTYPE_X86_64_ALL:
+ outs() << " cputype CPU_TYPE_X86_64\n";
+ outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";
+ break;
+ case MachO::CPU_SUBTYPE_X86_64_H:
+ outs() << " cputype CPU_TYPE_X86_64\n";
+ outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";
+ break;
+ default:
+ printUnknownCPUType(cputype, cpusubtype);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_ARM:
+ switch (cpusubtype) {
+ case MachO::CPU_SUBTYPE_ARM_ALL:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V4T:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V5TEJ:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_XSCALE:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V6:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V6M:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7EM:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7K:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7M:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7S:
+ outs() << " cputype CPU_TYPE_ARM\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";
+ break;
+ default:
+ printUnknownCPUType(cputype, cpusubtype);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_ARM64:
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM64_ALL:
+ outs() << " cputype CPU_TYPE_ARM64\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
+ break;
+ default:
+ printUnknownCPUType(cputype, cpusubtype);
+ break;
+ }
+ break;
+ default:
+ printUnknownCPUType(cputype, cpusubtype);
+ break;
+ }
+}
+
+static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
+ bool verbose) {
+ outs() << "Fat headers\n";
+ if (verbose)
+ outs() << "fat_magic FAT_MAGIC\n";
+ else
+ outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n";
+
+ uint32_t nfat_arch = UB->getNumberOfObjects();
+ StringRef Buf = UB->getData();
+ uint64_t size = Buf.size();
+ uint64_t big_size = sizeof(struct MachO::fat_header) +
+ nfat_arch * sizeof(struct MachO::fat_arch);
+ outs() << "nfat_arch " << UB->getNumberOfObjects();
+ if (nfat_arch == 0)
+ outs() << " (malformed, contains zero architecture types)\n";
+ else if (big_size > size)
+ outs() << " (malformed, architectures past end of file)\n";
+ else
+ outs() << "\n";
+
+ for (uint32_t i = 0; i < nfat_arch; ++i) {
+ MachOUniversalBinary::ObjectForArch OFA(UB, i);
+ uint32_t cputype = OFA.getCPUType();
+ uint32_t cpusubtype = OFA.getCPUSubType();
+ outs() << "architecture ";
+ for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {
+ MachOUniversalBinary::ObjectForArch other_OFA(UB, j);
+ uint32_t other_cputype = other_OFA.getCPUType();
+ uint32_t other_cpusubtype = other_OFA.getCPUSubType();
+ if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&
+ (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==
+ (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {
+ outs() << "(illegal duplicate architecture) ";
+ break;
+ }
+ }
+ if (verbose) {
+ outs() << OFA.getArchTypeName() << "\n";
+ printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ } else {
+ outs() << i << "\n";
+ outs() << " cputype " << cputype << "\n";
+ outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
+ << "\n";
+ }
+ if (verbose &&
+ (cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64)
+ outs() << " capabilities CPU_SUBTYPE_LIB64\n";
+ else
+ outs() << " capabilities "
+ << format("0x%" PRIx32,
+ (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";
+ outs() << " offset " << OFA.getOffset();
+ if (OFA.getOffset() > size)
+ outs() << " (past end of file)";
+ if (OFA.getOffset() % (1 << OFA.getAlign()) != 0)
+ outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";
+ outs() << "\n";
+ outs() << " size " << OFA.getSize();
+ big_size = OFA.getOffset() + OFA.getSize();
+ if (big_size > size)
+ outs() << " (past end of file)";
+ outs() << "\n";
+ outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())
+ << ")\n";
+ }
+}
+
+static void printArchiveChild(Archive::Child &C, bool verbose,
+ bool print_offset) {
+ if (print_offset)
+ outs() << C.getChildOffset() << "\t";
+ sys::fs::perms Mode = C.getAccessMode();
+ if (verbose) {
+ // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
+ // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
+ outs() << "-";
+ if (Mode & sys::fs::owner_read)
+ outs() << "r";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::owner_write)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::owner_exe)
+ outs() << "x";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::group_read)
+ outs() << "r";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::group_write)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::group_exe)
+ outs() << "x";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::others_read)
+ outs() << "r";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::others_write)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::others_exe)
+ outs() << "x";
+ else
+ outs() << "-";
+ } else {
+ outs() << format("0%o ", Mode);
+ }
+
+ unsigned UID = C.getUID();
+ outs() << format("%3d/", UID);
+ unsigned GID = C.getGID();
+ outs() << format("%-3d ", GID);
+ uint64_t Size = C.getRawSize();
+ outs() << format("%5" PRId64, Size) << " ";
+
+ StringRef RawLastModified = C.getRawLastModified();
+ if (verbose) {
+ unsigned Seconds;
+ if (RawLastModified.getAsInteger(10, Seconds))
+ outs() << "(date: \"%s\" contains non-decimal chars) " << RawLastModified;
+ else {
+ // Since cime(3) returns a 26 character string of the form:
+ // "Sun Sep 16 01:03:52 1973\n\0"
+ // just print 24 characters.
+ time_t t = Seconds;
+ outs() << format("%.24s ", ctime(&t));
+ }
+ } else {
+ outs() << RawLastModified << " ";
+ }
+
+ if (verbose) {
+ ErrorOr<StringRef> NameOrErr = C.getName();
+ if (NameOrErr.getError()) {
+ StringRef RawName = C.getRawName();
+ outs() << RawName << "\n";
+ } else {
+ StringRef Name = NameOrErr.get();
+ outs() << Name << "\n";
+ }
+ } else {
+ StringRef RawName = C.getRawName();
+ outs() << RawName << "\n";
+ }
+}
+
+static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) {
+ if (A->hasSymbolTable()) {
+ Archive::child_iterator S = A->getSymbolTableChild();
+ Archive::Child C = *S;
+ printArchiveChild(C, verbose, print_offset);
+ }
+ for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E;
+ ++I) {
+ Archive::Child C = *I;
+ printArchiveChild(C, verbose, print_offset);
+ }
+}
+
+// ParseInputMachO() parses the named Mach-O file in Filename and handles the
+// -arch flags selecting just those slices as specified by them and also parses
+// archive files. Then for each individual Mach-O file ProcessMachO() is
+// called to process the file based on the command line options.
+void llvm::ParseInputMachO(StringRef Filename) {
+ // Check for -arch all and verifiy the -arch flags are valid.
+ for (unsigned i = 0; i < ArchFlags.size(); ++i) {
+ if (ArchFlags[i] == "all") {
+ ArchAll = true;
+ } else {
+ if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
+ errs() << "llvm-objdump: Unknown architecture named '" + ArchFlags[i] +
+ "'for the -arch option\n";
+ return;
+ }
+ }
+ }
+
+ // Attempt to open the binary.
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
+ if (std::error_code EC = BinaryOrErr.getError()) {
+ errs() << "llvm-objdump: '" << Filename << "': " << EC.message() << ".\n";
+ return;
+ }
+ Binary &Bin = *BinaryOrErr.get().getBinary();
+
+ if (Archive *A = dyn_cast<Archive>(&Bin)) {
+ outs() << "Archive : " << Filename << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A, true, false);
+ for (Archive::child_iterator I = A->child_begin(), E = A->child_end();
+ I != E; ++I) {
+ ErrorOr<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
+ if (!checkMachOAndArchFlags(O, Filename))
+ return;
+ ProcessMachO(Filename, O, O->getFileName());
+ }
+ }
+ return;
+ }
+ if (UniversalHeaders) {
+ if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin))
+ printMachOUniversalHeaders(UB, true);
+ }
+ if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
+ // If we have a list of architecture flags specified dump only those.
+ if (!ArchAll && ArchFlags.size() != 0) {
+ // Look for a slice in the universal binary that matches each ArchFlag.
+ bool ArchFound;
+ for (unsigned i = 0; i < ArchFlags.size(); ++i) {
+ ArchFound = false;
+ for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
+ E = UB->end_objects();
+ I != E; ++I) {
+ if (ArchFlags[i] == I->getArchTypeName()) {
+ ArchFound = true;
+ ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
+ I->getAsObjectFile();
+ std::string ArchitectureName = "";
+ if (ArchFlags.size() > 1)
+ ArchitectureName = I->getArchTypeName();
+ if (ObjOrErr) {
+ ObjectFile &O = *ObjOrErr.get();
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
+ ProcessMachO(Filename, MachOOF, "", ArchitectureName);
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &A = *AOrErr;
+ outs() << "Archive : " << Filename;
+ if (!ArchitectureName.empty())
+ outs() << " (architecture " << ArchitectureName << ")";
+ outs() << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A.get(), true, false);
+ for (Archive::child_iterator AI = A->child_begin(),
+ AE = A->child_end();
+ AI != AE; ++AI) {
+ ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O =
+ dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
+ ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
+ }
+ }
+ }
+ }
+ if (!ArchFound) {
+ errs() << "llvm-objdump: file: " + Filename + " does not contain "
+ << "architecture: " + ArchFlags[i] + "\n";
+ return;
+ }
+ }
+ return;
+ }
+ // No architecture flags were specified so if this contains a slice that
+ // matches the host architecture dump only that.
+ if (!ArchAll) {
+ for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
+ E = UB->end_objects();
+ I != E; ++I) {
+ if (MachOObjectFile::getHostArch().getArchName() ==
+ I->getArchTypeName()) {
+ ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
+ std::string ArchiveName;
+ ArchiveName.clear();
+ if (ObjOrErr) {
+ ObjectFile &O = *ObjOrErr.get();
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
+ ProcessMachO(Filename, MachOOF);
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &A = *AOrErr;
+ outs() << "Archive : " << Filename << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A.get(), true, false);
+ for (Archive::child_iterator AI = A->child_begin(),
+ AE = A->child_end();
+ AI != AE; ++AI) {
+ ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O =
+ dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
+ ProcessMachO(Filename, O, O->getFileName());
+ }
+ }
+ return;
+ }
+ }
+ }
+ // Either all architectures have been specified or none have been specified
+ // and this does not contain the host architecture so dump all the slices.
+ bool moreThanOneArch = UB->getNumberOfObjects() > 1;
+ for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
+ E = UB->end_objects();
+ I != E; ++I) {
+ ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
+ std::string ArchitectureName = "";
+ if (moreThanOneArch)
+ ArchitectureName = I->getArchTypeName();
+ if (ObjOrErr) {
+ ObjectFile &Obj = *ObjOrErr.get();
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
+ ProcessMachO(Filename, MachOOF, "", ArchitectureName);
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
+ std::unique_ptr<Archive> &A = *AOrErr;
+ outs() << "Archive : " << Filename;
+ if (!ArchitectureName.empty())
+ outs() << " (architecture " << ArchitectureName << ")";
+ outs() << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A.get(), true, false);
+ for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
+ AI != AE; ++AI) {
+ ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O =
+ dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
+ ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
+ ArchitectureName);
+ }
+ }
+ }
+ }
+ return;
+ }
+ if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
+ if (!checkMachOAndArchFlags(O, Filename))
+ return;
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O)) {
+ ProcessMachO(Filename, MachOOF);
+ } else
+ errs() << "llvm-objdump: '" << Filename << "': "
+ << "Object is not a Mach-O file type.\n";
+ } else
+ errs() << "llvm-objdump: '" << Filename << "': "
+ << "Unrecognized file type.\n";
+}
+
typedef std::pair<uint64_t, const char *> BindInfoEntry;
typedef std::vector<BindInfoEntry> BindTable;
typedef BindTable::iterator bind_table_iterator;
@@ -280,21 +1593,6 @@ struct DisassembleInfo {
BindTable *bindtable;
};
-// GuessSymbolName is passed the address of what might be a symbol and a
-// pointer to the DisassembleInfo struct. It returns the name of a symbol
-// with that address or nullptr if no symbol is found with that address.
-static const char *GuessSymbolName(uint64_t value,
- struct DisassembleInfo *info) {
- const char *SymbolName = nullptr;
- // A DenseMap can't lookup up some values.
- if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
- StringRef name = info->AddrMap->lookup(value);
- if (!name.empty())
- SymbolName = name.data();
- }
- return SymbolName;
-}
-
// SymbolizerGetOpInfo() is the operand information call back function.
// This is called to get the symbolic information for operand(s) of an
// instruction when it is being done. This routine does this from
@@ -385,8 +1683,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
}
if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
- const char *add = GuessSymbolName(r_value, info);
- const char *sub = GuessSymbolName(pair_r_value, info);
+ const char *add = GuessSymbolName(r_value, info->AddrMap);
+ const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
uint32_t offset = value - (r_value - pair_r_value);
op_info->AddSymbol.Present = 1;
if (add != nullptr)
@@ -527,34 +1825,18 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
const char *name = SymName.data();
op_info->AddSymbol.Present = 1;
op_info->AddSymbol.Name = name;
- if (value != 0) {
- switch (r_type) {
- case MachO::ARM_RELOC_HALF:
- if ((r_length & 0x1) == 1) {
- op_info->Value = value << 16 | other_half;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
- } else {
- op_info->Value = other_half << 16 | value;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
- }
- break;
- default:
- break;
- }
- } else {
- switch (r_type) {
- case MachO::ARM_RELOC_HALF:
- if ((r_length & 0x1) == 1) {
- op_info->Value = value << 16 | other_half;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
- } else {
- op_info->Value = other_half << 16 | value;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
- }
- break;
- default:
- break;
+ switch (r_type) {
+ case MachO::ARM_RELOC_HALF:
+ if ((r_length & 0x1) == 1) {
+ op_info->Value = value << 16 | other_half;
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
+ } else {
+ op_info->Value = other_half << 16 | value;
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
}
+ break;
+ default:
+ break;
}
return 1;
}
@@ -587,8 +1869,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
else
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
- const char *add = GuessSymbolName(r_value, info);
- const char *sub = GuessSymbolName(pair_r_value, info);
+ const char *add = GuessSymbolName(r_value, info->AddrMap);
+ const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
int32_t offset = value - (r_value - pair_r_value);
op_info->AddSymbol.Present = 1;
if (add != nullptr)
@@ -617,7 +1899,7 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
}
}
- const char *add = GuessSymbolName(value, info);
+ const char *add = GuessSymbolName(value, info->AddrMap);
if (add != nullptr) {
op_info->AddSymbol.Name = add;
return 1;
@@ -1078,7 +2360,7 @@ const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
//
// NOTE: need add passing the ReferenceValue to this routine. Then that code
// would simply be this:
- // SymbolName = GuessSymbolName(ReferenceValue, info);
+ // SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
return SymbolName;
}
@@ -1421,7 +2703,7 @@ const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue,
return nullptr;
}
- const char *SymbolName = GuessSymbolName(ReferenceValue, info);
+ const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
*ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
@@ -1585,8 +2867,8 @@ static void emitComments(raw_svector_ostream &CommentStream,
CommentStream.resync();
}
-static void DisassembleInputMachO2(StringRef Filename,
- MachOObjectFile *MachOOF) {
+static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
+ StringRef DisSegName, StringRef DisSectName) {
const char *McpuDefault = nullptr;
const Target *ThumbTarget = nullptr;
const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
@@ -1628,7 +2910,7 @@ static void DisassembleInputMachO2(StringRef Filename,
if (RelInfo) {
Symbolizer.reset(TheTarget->createMCSymbolizer(
TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
- &SymbolizerInfo, &Ctx, RelInfo.release()));
+ &SymbolizerInfo, &Ctx, std::move(RelInfo)));
DisAsm->setSymbolizer(std::move(Symbolizer));
}
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
@@ -1639,6 +2921,12 @@ static void DisassembleInputMachO2(StringRef Filename,
// Comment stream and backing vector.
SmallString<128> CommentsToEmit;
raw_svector_ostream CommentStream(CommentsToEmit);
+ // FIXME: Setting the CommentStream in the InstPrinter is problematic in that
+ // if it is done then arm64 comments for string literals don't get printed
+ // and some constant get printed instead and not setting it causes intel
+ // (32-bit and 64-bit) comments printed with different spacing before the
+ // comment causing different diffs with the 'C' disassembler library API.
+ // IP->setCommentStream(CommentStream);
if (!AsmInfo || !STI || !DisAsm || !IP) {
errs() << "error: couldn't initialize disassembler for target "
@@ -1670,7 +2958,7 @@ static void DisassembleInputMachO2(StringRef Filename,
if (ThumbRelInfo) {
ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(
ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
- &ThumbSymbolizerInfo, PtrThumbCtx, ThumbRelInfo.release()));
+ &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));
ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
}
int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
@@ -1687,8 +2975,6 @@ static void DisassembleInputMachO2(StringRef Filename,
return;
}
- outs() << '\n' << Filename << ":\n\n";
-
MachO::mach_header Header = MachOOF->getHeader();
// FIXME: Using the -cfg command line option, this code used to be able to
@@ -1750,20 +3036,18 @@ static void DisassembleInputMachO2(StringRef Filename,
diContext.reset(DIContext::getDWARFContext(*DbgObj));
}
- for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
-
- bool SectIsText = Sections[SectIdx].isText();
- if (SectIsText == false)
- continue;
+ if (DumpSections.size() == 0)
+ outs() << "(" << DisSegName << "," << DisSectName << ") section\n";
+ for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
StringRef SectName;
- if (Sections[SectIdx].getName(SectName) || SectName != "__text")
- continue; // Skip non-text sections
+ if (Sections[SectIdx].getName(SectName) || SectName != DisSectName)
+ continue;
DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
- if (SegmentName != "__TEXT")
+ if (SegmentName != DisSegName)
continue;
StringRef BytesStr;
@@ -2013,6 +3297,11 @@ static void DisassembleInputMachO2(StringRef Filename,
}
}
}
+ // The TripleName's need to be reset if we are called again for a different
+ // archtecture.
+ TripleName = "";
+ ThumbTripleName = "";
+
if (SymbolizerInfo.method != nullptr)
free(SymbolizerInfo.method);
if (SymbolizerInfo.demangled_name != nullptr)
@@ -2504,12 +3793,17 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype,
break;
case MachO::CPU_TYPE_X86_64:
outs() << " X86_64";
- case MachO::CPU_SUBTYPE_X86_64_ALL:
- outs() << " ALL";
- break;
- case MachO::CPU_SUBTYPE_X86_64_H:
- outs() << " Haswell";
- outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_X86_64_ALL:
+ outs() << " ALL";
+ break;
+ case MachO::CPU_SUBTYPE_X86_64_H:
+ outs() << " Haswell";
+ break;
+ default:
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ break;
+ }
break;
case MachO::CPU_TYPE_ARM:
outs() << " ARM";
@@ -2774,8 +4068,8 @@ static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";
outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n";
} else {
- outs() << " vmaddr " << format("0x%08" PRIx32, vmaddr) << "\n";
- outs() << " vmsize " << format("0x%08" PRIx32, vmsize) << "\n";
+ outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";
+ outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n";
}
outs() << " fileoff " << fileoff;
if (fileoff > object_size)
@@ -2878,8 +4172,8 @@ static void PrintSection(const char *sectname, const char *segname,
outs() << " addr " << format("0x%016" PRIx64, addr) << "\n";
outs() << " size " << format("0x%016" PRIx64, size);
} else {
- outs() << " addr " << format("0x%08" PRIx32, addr) << "\n";
- outs() << " size " << format("0x%08" PRIx32, size);
+ outs() << " addr " << format("0x%08" PRIx64, addr) << "\n";
+ outs() << " size " << format("0x%08" PRIx64, size);
}
if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)
outs() << " (past end of file)\n";
@@ -3299,6 +4593,21 @@ static void PrintUuidLoadCommand(MachO::uuid_command uuid) {
outs() << "\n";
}
+static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {
+ outs() << " cmd LC_RPATH\n";
+ outs() << " cmdsize " << rpath.cmdsize;
+ if (rpath.cmdsize < sizeof(struct MachO::rpath_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ if (rpath.path >= rpath.cmdsize)
+ outs() << " path ?(bad offset " << rpath.path << ")\n";
+ else {
+ const char *P = (const char *)(Ptr) + rpath.path;
+ outs() << " path " << P << " (offset " << rpath.path << ")\n";
+ }
+}
+
static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
if (vd.cmd == MachO::LC_VERSION_MIN_MACOSX)
outs() << " cmd LC_VERSION_MIN_MACOSX\n";
@@ -3317,7 +4626,7 @@ static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
outs() << "." << (vd.version & 0xff);
outs() << "\n";
if (vd.sdk == 0)
- outs() << " sdk n/a\n";
+ outs() << " sdk n/a";
else {
outs() << " sdk " << ((vd.sdk >> 16) & 0xffff) << "."
<< ((vd.sdk >> 8) & 0xff);
@@ -3360,6 +4669,525 @@ static void PrintEntryPointCommand(MachO::entry_point_command ep) {
outs() << " stacksize " << ep.stacksize << "\n";
}
+static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,
+ uint32_t object_size) {
+ outs() << " cmd LC_ENCRYPTION_INFO\n";
+ outs() << " cmdsize " << ec.cmdsize;
+ if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " cryptoff " << ec.cryptoff;
+ if (ec.cryptoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " cryptsize " << ec.cryptsize;
+ if (ec.cryptsize > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " cryptid " << ec.cryptid << "\n";
+}
+
+static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,
+ uint32_t object_size) {
+ outs() << " cmd LC_ENCRYPTION_INFO_64\n";
+ outs() << " cmdsize " << ec.cmdsize;
+ if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " cryptoff " << ec.cryptoff;
+ if (ec.cryptoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " cryptsize " << ec.cryptsize;
+ if (ec.cryptsize > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " cryptid " << ec.cryptid << "\n";
+ outs() << " pad " << ec.pad << "\n";
+}
+
+static void PrintLinkerOptionCommand(MachO::linker_option_command lo,
+ const char *Ptr) {
+ outs() << " cmd LC_LINKER_OPTION\n";
+ outs() << " cmdsize " << lo.cmdsize;
+ if (lo.cmdsize < sizeof(struct MachO::linker_option_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " count " << lo.count << "\n";
+ const char *string = Ptr + sizeof(struct MachO::linker_option_command);
+ uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);
+ uint32_t i = 0;
+ while (left > 0) {
+ while (*string == '\0' && left > 0) {
+ string++;
+ left--;
+ }
+ if (left > 0) {
+ i++;
+ outs() << " string #" << i << " " << format("%.*s\n", left, string);
+ uint32_t NullPos = StringRef(string, left).find('\0');
+ uint32_t len = std::min(NullPos, left) + 1;
+ string += len;
+ left -= len;
+ }
+ }
+ if (lo.count != i)
+ outs() << " count " << lo.count << " does not match number of strings "
+ << i << "\n";
+}
+
+static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,
+ const char *Ptr) {
+ outs() << " cmd LC_SUB_FRAMEWORK\n";
+ outs() << " cmdsize " << sub.cmdsize;
+ if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ if (sub.umbrella < sub.cmdsize) {
+ const char *P = Ptr + sub.umbrella;
+ outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";
+ } else {
+ outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";
+ }
+}
+
+static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,
+ const char *Ptr) {
+ outs() << " cmd LC_SUB_UMBRELLA\n";
+ outs() << " cmdsize " << sub.cmdsize;
+ if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ if (sub.sub_umbrella < sub.cmdsize) {
+ const char *P = Ptr + sub.sub_umbrella;
+ outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";
+ } else {
+ outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";
+ }
+}
+
+static void PrintSubLibraryCommand(MachO::sub_library_command sub,
+ const char *Ptr) {
+ outs() << " cmd LC_SUB_LIBRARY\n";
+ outs() << " cmdsize " << sub.cmdsize;
+ if (sub.cmdsize < sizeof(struct MachO::sub_library_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ if (sub.sub_library < sub.cmdsize) {
+ const char *P = Ptr + sub.sub_library;
+ outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";
+ } else {
+ outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";
+ }
+}
+
+static void PrintSubClientCommand(MachO::sub_client_command sub,
+ const char *Ptr) {
+ outs() << " cmd LC_SUB_CLIENT\n";
+ outs() << " cmdsize " << sub.cmdsize;
+ if (sub.cmdsize < sizeof(struct MachO::sub_client_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ if (sub.client < sub.cmdsize) {
+ const char *P = Ptr + sub.client;
+ outs() << " client " << P << " (offset " << sub.client << ")\n";
+ } else {
+ outs() << " client ?(bad offset " << sub.client << ")\n";
+ }
+}
+
+static void PrintRoutinesCommand(MachO::routines_command r) {
+ outs() << " cmd LC_ROUTINES\n";
+ outs() << " cmdsize " << r.cmdsize;
+ if (r.cmdsize != sizeof(struct MachO::routines_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n";
+ outs() << " init_module " << r.init_module << "\n";
+ outs() << " reserved1 " << r.reserved1 << "\n";
+ outs() << " reserved2 " << r.reserved2 << "\n";
+ outs() << " reserved3 " << r.reserved3 << "\n";
+ outs() << " reserved4 " << r.reserved4 << "\n";
+ outs() << " reserved5 " << r.reserved5 << "\n";
+ outs() << " reserved6 " << r.reserved6 << "\n";
+}
+
+static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
+ outs() << " cmd LC_ROUTINES_64\n";
+ outs() << " cmdsize " << r.cmdsize;
+ if (r.cmdsize != sizeof(struct MachO::routines_command_64))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n";
+ outs() << " init_module " << r.init_module << "\n";
+ outs() << " reserved1 " << r.reserved1 << "\n";
+ outs() << " reserved2 " << r.reserved2 << "\n";
+ outs() << " reserved3 " << r.reserved3 << "\n";
+ outs() << " reserved4 " << r.reserved4 << "\n";
+ outs() << " reserved5 " << r.reserved5 << "\n";
+ outs() << " reserved6 " << r.reserved6 << "\n";
+}
+
+static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
+ outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);
+ outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);
+ outs() << " rcx " << format("0x%016" PRIx64, cpu64.rcx) << "\n";
+ outs() << " rdx " << format("0x%016" PRIx64, cpu64.rdx);
+ outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi);
+ outs() << " rsi " << format("0x%016" PRIx64, cpu64.rsi) << "\n";
+ outs() << " rbp " << format("0x%016" PRIx64, cpu64.rbp);
+ outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp);
+ outs() << " r8 " << format("0x%016" PRIx64, cpu64.r8) << "\n";
+ outs() << " r9 " << format("0x%016" PRIx64, cpu64.r9);
+ outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10);
+ outs() << " r11 " << format("0x%016" PRIx64, cpu64.r11) << "\n";
+ outs() << " r12 " << format("0x%016" PRIx64, cpu64.r12);
+ outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13);
+ outs() << " r14 " << format("0x%016" PRIx64, cpu64.r14) << "\n";
+ outs() << " r15 " << format("0x%016" PRIx64, cpu64.r15);
+ outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n";
+ outs() << "rflags " << format("0x%016" PRIx64, cpu64.rflags);
+ outs() << " cs " << format("0x%016" PRIx64, cpu64.cs);
+ outs() << " fs " << format("0x%016" PRIx64, cpu64.fs) << "\n";
+ outs() << " gs " << format("0x%016" PRIx64, cpu64.gs) << "\n";
+}
+
+static void Print_mmst_reg(MachO::mmst_reg_t &r) {
+ uint32_t f;
+ outs() << "\t mmst_reg ";
+ for (f = 0; f < 10; f++)
+ outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " ";
+ outs() << "\n";
+ outs() << "\t mmst_rsrv ";
+ for (f = 0; f < 6; f++)
+ outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " ";
+ outs() << "\n";
+}
+
+static void Print_xmm_reg(MachO::xmm_reg_t &r) {
+ uint32_t f;
+ outs() << "\t xmm_reg ";
+ for (f = 0; f < 16; f++)
+ outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " ";
+ outs() << "\n";
+}
+
+static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {
+ outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];
+ outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";
+ outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;
+ outs() << " denorm " << fpu.fpu_fcw.denorm;
+ outs() << " zdiv " << fpu.fpu_fcw.zdiv;
+ outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;
+ outs() << " undfl " << fpu.fpu_fcw.undfl;
+ outs() << " precis " << fpu.fpu_fcw.precis << "\n";
+ outs() << "\t\t pc ";
+ if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)
+ outs() << "FP_PREC_24B ";
+ else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)
+ outs() << "FP_PREC_53B ";
+ else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)
+ outs() << "FP_PREC_64B ";
+ else
+ outs() << fpu.fpu_fcw.pc << " ";
+ outs() << "rc ";
+ if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)
+ outs() << "FP_RND_NEAR ";
+ else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)
+ outs() << "FP_RND_DOWN ";
+ else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)
+ outs() << "FP_RND_UP ";
+ else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)
+ outs() << "FP_CHOP ";
+ outs() << "\n";
+ outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;
+ outs() << " denorm " << fpu.fpu_fsw.denorm;
+ outs() << " zdiv " << fpu.fpu_fsw.zdiv;
+ outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;
+ outs() << " undfl " << fpu.fpu_fsw.undfl;
+ outs() << " precis " << fpu.fpu_fsw.precis;
+ outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";
+ outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;
+ outs() << " c0 " << fpu.fpu_fsw.c0;
+ outs() << " c1 " << fpu.fpu_fsw.c1;
+ outs() << " c2 " << fpu.fpu_fsw.c2;
+ outs() << " tos " << fpu.fpu_fsw.tos;
+ outs() << " c3 " << fpu.fpu_fsw.c3;
+ outs() << " busy " << fpu.fpu_fsw.busy << "\n";
+ outs() << "\t fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw);
+ outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1);
+ outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop);
+ outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n";
+ outs() << "\t fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs);
+ outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2);
+ outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp);
+ outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n";
+ outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3);
+ outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr);
+ outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask);
+ outs() << "\n";
+ outs() << "\t fpu_stmm0:\n";
+ Print_mmst_reg(fpu.fpu_stmm0);
+ outs() << "\t fpu_stmm1:\n";
+ Print_mmst_reg(fpu.fpu_stmm1);
+ outs() << "\t fpu_stmm2:\n";
+ Print_mmst_reg(fpu.fpu_stmm2);
+ outs() << "\t fpu_stmm3:\n";
+ Print_mmst_reg(fpu.fpu_stmm3);
+ outs() << "\t fpu_stmm4:\n";
+ Print_mmst_reg(fpu.fpu_stmm4);
+ outs() << "\t fpu_stmm5:\n";
+ Print_mmst_reg(fpu.fpu_stmm5);
+ outs() << "\t fpu_stmm6:\n";
+ Print_mmst_reg(fpu.fpu_stmm6);
+ outs() << "\t fpu_stmm7:\n";
+ Print_mmst_reg(fpu.fpu_stmm7);
+ outs() << "\t fpu_xmm0:\n";
+ Print_xmm_reg(fpu.fpu_xmm0);
+ outs() << "\t fpu_xmm1:\n";
+ Print_xmm_reg(fpu.fpu_xmm1);
+ outs() << "\t fpu_xmm2:\n";
+ Print_xmm_reg(fpu.fpu_xmm2);
+ outs() << "\t fpu_xmm3:\n";
+ Print_xmm_reg(fpu.fpu_xmm3);
+ outs() << "\t fpu_xmm4:\n";
+ Print_xmm_reg(fpu.fpu_xmm4);
+ outs() << "\t fpu_xmm5:\n";
+ Print_xmm_reg(fpu.fpu_xmm5);
+ outs() << "\t fpu_xmm6:\n";
+ Print_xmm_reg(fpu.fpu_xmm6);
+ outs() << "\t fpu_xmm7:\n";
+ Print_xmm_reg(fpu.fpu_xmm7);
+ outs() << "\t fpu_xmm8:\n";
+ Print_xmm_reg(fpu.fpu_xmm8);
+ outs() << "\t fpu_xmm9:\n";
+ Print_xmm_reg(fpu.fpu_xmm9);
+ outs() << "\t fpu_xmm10:\n";
+ Print_xmm_reg(fpu.fpu_xmm10);
+ outs() << "\t fpu_xmm11:\n";
+ Print_xmm_reg(fpu.fpu_xmm11);
+ outs() << "\t fpu_xmm12:\n";
+ Print_xmm_reg(fpu.fpu_xmm12);
+ outs() << "\t fpu_xmm13:\n";
+ Print_xmm_reg(fpu.fpu_xmm13);
+ outs() << "\t fpu_xmm14:\n";
+ Print_xmm_reg(fpu.fpu_xmm14);
+ outs() << "\t fpu_xmm15:\n";
+ Print_xmm_reg(fpu.fpu_xmm15);
+ outs() << "\t fpu_rsrv4:\n";
+ for (uint32_t f = 0; f < 6; f++) {
+ outs() << "\t ";
+ for (uint32_t g = 0; g < 16; g++)
+ outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " ";
+ outs() << "\n";
+ }
+ outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1);
+ outs() << "\n";
+}
+
+static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {
+ outs() << "\t trapno " << format("0x%08" PRIx32, exc64.trapno);
+ outs() << " err " << format("0x%08" PRIx32, exc64.err);
+ outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n";
+}
+
+static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
+ bool isLittleEndian, uint32_t cputype) {
+ if (t.cmd == MachO::LC_THREAD)
+ outs() << " cmd LC_THREAD\n";
+ else if (t.cmd == MachO::LC_UNIXTHREAD)
+ outs() << " cmd LC_UNIXTHREAD\n";
+ else
+ outs() << " cmd " << t.cmd << " (unknown)\n";
+ outs() << " cmdsize " << t.cmdsize;
+ if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+
+ const char *begin = Ptr + sizeof(struct MachO::thread_command);
+ const char *end = Ptr + t.cmdsize;
+ uint32_t flavor, count, left;
+ if (cputype == MachO::CPU_TYPE_X86_64) {
+ while (begin < end) {
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&flavor, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ flavor = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(flavor);
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&count, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ count = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(count);
+ if (flavor == MachO::x86_THREAD_STATE64) {
+ outs() << " flavor x86_THREAD_STATE64\n";
+ if (count == MachO::x86_THREAD_STATE64_COUNT)
+ outs() << " count x86_THREAD_STATE64_COUNT\n";
+ else
+ outs() << " count " << count
+ << " (not x86_THREAD_STATE64_COUNT)\n";
+ MachO::x86_thread_state64_t cpu64;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_thread_state64_t)) {
+ memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));
+ begin += sizeof(MachO::x86_thread_state64_t);
+ } else {
+ memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));
+ memcpy(&cpu64, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(cpu64);
+ Print_x86_thread_state64_t(cpu64);
+ } else if (flavor == MachO::x86_THREAD_STATE) {
+ outs() << " flavor x86_THREAD_STATE\n";
+ if (count == MachO::x86_THREAD_STATE_COUNT)
+ outs() << " count x86_THREAD_STATE_COUNT\n";
+ else
+ outs() << " count " << count
+ << " (not x86_THREAD_STATE_COUNT)\n";
+ struct MachO::x86_thread_state_t ts;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_thread_state_t)) {
+ memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
+ begin += sizeof(MachO::x86_thread_state_t);
+ } else {
+ memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
+ memcpy(&ts, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(ts);
+ if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {
+ outs() << "\t tsh.flavor x86_THREAD_STATE64 ";
+ if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)
+ outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";
+ else
+ outs() << "tsh.count " << ts.tsh.count
+ << " (not x86_THREAD_STATE64_COUNT\n";
+ Print_x86_thread_state64_t(ts.uts.ts64);
+ } else {
+ outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
+ << ts.tsh.count << "\n";
+ }
+ } else if (flavor == MachO::x86_FLOAT_STATE) {
+ outs() << " flavor x86_FLOAT_STATE\n";
+ if (count == MachO::x86_FLOAT_STATE_COUNT)
+ outs() << " count x86_FLOAT_STATE_COUNT\n";
+ else
+ outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";
+ struct MachO::x86_float_state_t fs;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_float_state_t)) {
+ memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));
+ begin += sizeof(MachO::x86_float_state_t);
+ } else {
+ memset(&fs, '\0', sizeof(MachO::x86_float_state_t));
+ memcpy(&fs, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(fs);
+ if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {
+ outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";
+ if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)
+ outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";
+ else
+ outs() << "fsh.count " << fs.fsh.count
+ << " (not x86_FLOAT_STATE64_COUNT\n";
+ Print_x86_float_state_t(fs.ufs.fs64);
+ } else {
+ outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "
+ << fs.fsh.count << "\n";
+ }
+ } else if (flavor == MachO::x86_EXCEPTION_STATE) {
+ outs() << " flavor x86_EXCEPTION_STATE\n";
+ if (count == MachO::x86_EXCEPTION_STATE_COUNT)
+ outs() << " count x86_EXCEPTION_STATE_COUNT\n";
+ else
+ outs() << " count " << count
+ << " (not x86_EXCEPTION_STATE_COUNT)\n";
+ struct MachO::x86_exception_state_t es;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_exception_state_t)) {
+ memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));
+ begin += sizeof(MachO::x86_exception_state_t);
+ } else {
+ memset(&es, '\0', sizeof(MachO::x86_exception_state_t));
+ memcpy(&es, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(es);
+ if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {
+ outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";
+ if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)
+ outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";
+ else
+ outs() << "\t esh.count " << es.esh.count
+ << " (not x86_EXCEPTION_STATE64_COUNT\n";
+ Print_x86_exception_state_t(es.ues.es64);
+ } else {
+ outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "
+ << es.esh.count << "\n";
+ }
+ } else {
+ outs() << " flavor " << flavor << " (unknown)\n";
+ outs() << " count " << count << "\n";
+ outs() << " state (unknown)\n";
+ begin += count * sizeof(uint32_t);
+ }
+ }
+ } else {
+ while (begin < end) {
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&flavor, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ flavor = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(flavor);
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&count, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ count = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(count);
+ outs() << " flavor " << flavor << "\n";
+ outs() << " count " << count << "\n";
+ outs() << " state (Unknown cputype/cpusubtype)\n";
+ begin += count * sizeof(uint32_t);
+ }
+ }
+}
+
static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {
if (dl.cmd == MachO::LC_ID_DYLIB)
outs() << " cmd LC_ID_DYLIB\n";
@@ -3443,6 +5271,8 @@ static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,
static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds,
uint32_t filetype, uint32_t cputype,
bool verbose) {
+ if (ncmds == 0)
+ return;
StringRef Buf = Obj->getData();
MachOObjectFile::LoadCommandInfo Command = Obj->getFirstLoadCommandInfo();
for (unsigned i = 0;; ++i) {
@@ -3455,7 +5285,7 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds,
SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),
verbose);
for (unsigned j = 0; j < SLC.nsects; j++) {
- MachO::section_64 S = Obj->getSection64(Command, j);
+ MachO::section S = Obj->getSection(Command, j);
PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,
S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,
SLC.cmd, sg_segname, filetype, Buf.size(), verbose);
@@ -3494,7 +5324,11 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds,
} else if (Command.C.cmd == MachO::LC_UUID) {
MachO::uuid_command Uuid = Obj->getUuidCommand(Command);
PrintUuidLoadCommand(Uuid);
- } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX) {
+ } else if (Command.C.cmd == MachO::LC_RPATH) {
+ MachO::rpath_command Rpath = Obj->getRpathCommand(Command);
+ PrintRpathLoadCommand(Rpath, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||
+ Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) {
MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
PrintVersionMinLoadCommand(Vd);
} else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
@@ -3503,6 +5337,40 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds,
} else if (Command.C.cmd == MachO::LC_MAIN) {
MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);
PrintEntryPointCommand(Ep);
+ } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {
+ MachO::encryption_info_command Ei =
+ Obj->getEncryptionInfoCommand(Command);
+ PrintEncryptionInfoCommand(Ei, Buf.size());
+ } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
+ MachO::encryption_info_command_64 Ei =
+ Obj->getEncryptionInfoCommand64(Command);
+ PrintEncryptionInfoCommand64(Ei, Buf.size());
+ } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {
+ MachO::linker_option_command Lo =
+ Obj->getLinkerOptionLoadCommand(Command);
+ PrintLinkerOptionCommand(Lo, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {
+ MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);
+ PrintSubFrameworkCommand(Sf, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {
+ MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);
+ PrintSubUmbrellaCommand(Sf, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {
+ MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);
+ PrintSubLibraryCommand(Sl, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {
+ MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);
+ PrintSubClientCommand(Sc, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_ROUTINES) {
+ MachO::routines_command Rc = Obj->getRoutinesCommand(Command);
+ PrintRoutinesCommand(Rc);
+ } else if (Command.C.cmd == MachO::LC_ROUTINES_64) {
+ MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);
+ PrintRoutinesCommand64(Rc);
+ } else if (Command.C.cmd == MachO::LC_THREAD ||
+ Command.C.cmd == MachO::LC_UNIXTHREAD) {
+ MachO::thread_command Tc = Obj->getThreadCommand(Command);
+ PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);
} else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||
Command.C.cmd == MachO::LC_ID_DYLIB ||
Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||