diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-objdump/MachODump.cpp')
-rw-r--r-- | contrib/llvm/tools/llvm-objdump/MachODump.cpp | 1156 |
1 files changed, 765 insertions, 391 deletions
diff --git a/contrib/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm/tools/llvm-objdump/MachODump.cpp index 258c0b5..4d950f1 100644 --- a/contrib/llvm/tools/llvm-objdump/MachODump.cpp +++ b/contrib/llvm/tools/llvm-objdump/MachODump.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Object/MachO.h" #include "llvm-objdump.h" #include "llvm-c/Disassembler.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" @@ -22,14 +22,13 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #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" @@ -43,6 +42,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstring> @@ -52,6 +52,12 @@ #include <cxxabi.h> #endif +#ifdef HAVE_LIBXAR +extern "C" { +#include <xar/xar.h> +} +#endif + using namespace llvm; using namespace object; @@ -143,11 +149,18 @@ static const Target *GetTarget(const MachOObjectFile *MachOObj, const char **McpuDefault, const Target **ThumbTarget) { // Figure out the target triple. + llvm::Triple TT(TripleName); if (TripleName.empty()) { - llvm::Triple TT("unknown-unknown-unknown"); - llvm::Triple ThumbTriple = Triple(); - TT = MachOObj->getArch(McpuDefault, &ThumbTriple); + TT = MachOObj->getArchTriple(McpuDefault); TripleName = TT.str(); + } + + if (TT.getArch() == Triple::arm) { + // We've inferred a 32-bit ARM target from the object file. All MachO CPUs + // that support ARM are also capable of Thumb mode. + llvm::Triple ThumbTriple = TT; + std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str(); + ThumbTriple.setArchName(ThumbName); ThumbTripleName = ThumbTriple.str(); } @@ -172,8 +185,26 @@ static const Target *GetTarget(const MachOObjectFile *MachOObj, struct SymbolSorter { bool operator()(const SymbolRef &A, const SymbolRef &B) { - uint64_t AAddr = (A.getType() != SymbolRef::ST_Function) ? 0 : A.getValue(); - uint64_t BAddr = (B.getType() != SymbolRef::ST_Function) ? 0 : B.getValue(); + Expected<SymbolRef::Type> ATypeOrErr = A.getType(); + if (!ATypeOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(ATypeOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + SymbolRef::Type AType = *ATypeOrErr; + Expected<SymbolRef::Type> BTypeOrErr = B.getType(); + if (!BTypeOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(BTypeOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + SymbolRef::Type BType = *BTypeOrErr; + uint64_t AAddr = (AType != SymbolRef::ST_Function) ? 0 : A.getValue(); + uint64_t BAddr = (BType != SymbolRef::ST_Function) ? 0 : B.getValue(); return AAddr < BAddr; } }; @@ -266,9 +297,14 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj, SmallVectorImpl<uint64_t> &FoundFns, uint64_t &BaseSegmentAddress) { for (const SymbolRef &Symbol : MachOObj->symbols()) { - ErrorOr<StringRef> SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } if (!SymName->startswith("ltmp")) Symbols.push_back(Symbol); } @@ -324,7 +360,7 @@ static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose, if (cputype & MachO::CPU_ARCH_ABI64) outs() << format("0x%016" PRIx64, addr + j * stride) << " "; else - outs() << format("0x%08" PRIx32, addr + j * stride) << " "; + outs() << format("0x%08" PRIx32, (uint32_t)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) { @@ -346,9 +382,14 @@ static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose, if (indirect_symbol < Symtab.nsyms) { symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol); SymbolRef Symbol = *Sym; - ErrorOr<StringRef> SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } outs() << *SymName; } else { outs() << "?"; @@ -573,13 +614,26 @@ 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(); + Expected<SymbolRef::Type> STOrErr = Symbol.getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + SymbolRef::Type ST = *STOrErr; if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data || ST == SymbolRef::ST_Other) { uint64_t Address = Symbol.getValue(); - ErrorOr<StringRef> SymNameOrErr = Symbol.getName(); - if (std::error_code EC = SymNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymNameOrErr = Symbol.getName(); + if (!SymNameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef SymName = *SymNameOrErr; if (!SymName.startswith(".objc")) (*AddrMap)[Address] = SymName; @@ -813,9 +867,14 @@ static void DumpLiteralPointerSection(MachOObjectFile *O, [&](const std::pair<uint64_t, SymbolRef> &P) { return P.first == i; }); if (Reloc != Relocs.end()) { symbol_iterator RelocSym = Reloc->second; - ErrorOr<StringRef> SymName = RelocSym->getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = RelocSym->getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } outs() << "external relocation entry for symbol:" << *SymName << "\n"; continue; } @@ -964,10 +1023,10 @@ static void DumpRawSectionContents(MachOObjectFile *O, const char *sect, if (O->is64Bit()) outs() << format("%016" PRIx64, addr) << "\t"; else - outs() << format("%08" PRIx64, sect) << "\t"; + outs() << format("%08" PRIx64, addr) << "\t"; for (j = 0; j < 4 * sizeof(int32_t) && i + j < size; j += sizeof(int32_t)) { - if (i + j + sizeof(int32_t) < size) { + 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) @@ -975,7 +1034,7 @@ static void DumpRawSectionContents(MachOObjectFile *O, const char *sect, outs() << format("%08" PRIx32, long_word) << " "; } else { for (uint32_t k = 0; i + j + k < size; k++) { - uint8_t byte_word = *(sect + i + j); + uint8_t byte_word = *(sect + i + j + k); outs() << format("%02" PRIx32, (uint32_t)byte_word) << " "; } } @@ -989,6 +1048,12 @@ 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); +#ifdef HAVE_LIBXAR +static void DumpBitcodeSection(MachOObjectFile *O, const char *sect, + uint32_t size, bool verbose, + bool PrintXarHeader, bool PrintXarFileHeaders, + std::string XarMemberName); +#endif // defined(HAVE_LIBXAR) static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, bool verbose) { @@ -1050,6 +1115,13 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, DumpProtocolSection(O, sect, sect_size, sect_addr); continue; } +#ifdef HAVE_LIBXAR + if (SegName == "__LLVM" && SectName == "__bundle") { + DumpBitcodeSection(O, sect, sect_size, verbose, !NoSymbolicOperands, + ArchiveHeaders, ""); + continue; + } +#endif // defined(HAVE_LIBXAR) switch (section_type) { case MachO::S_REGULAR: DumpRawSectionContents(O, sect, sect_size, sect_addr); @@ -1127,10 +1199,10 @@ static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { Triple T; if (MachO->is64Bit()) { H_64 = MachO->MachOObjectFile::getHeader64(); - T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); } else { H = MachO->MachOObjectFile::getHeader(); - T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); } unsigned i; for (i = 0; i < ArchFlags.size(); ++i) { @@ -1159,7 +1231,7 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, // 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 || + if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints || DylibsUsed || DylibId || ObjcMetaData || (FilterSections.size() != 0)) { outs() << Filename; @@ -1192,8 +1264,10 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, PrintDylibs(MachOOF, false); if (DylibId) PrintDylibs(MachOOF, true); - if (SymbolTable) - PrintSymbolTable(MachOOF); + if (SymbolTable) { + StringRef ArchiveName = ArchiveMemberName == StringRef() ? "" : Filename; + PrintSymbolTable(MachOOF, ArchiveName, ArchitectureName); + } if (UnwindInfo) printMachOUnwindInfo(MachOOF); if (PrivateHeaders) { @@ -1214,6 +1288,12 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, printLazyBindTable(MachOOF); if (WeakBind) printWeakBindTable(MachOOF); + + if (DwarfDumpType != DIDT_Null) { + std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*MachOOF)); + // Dump the complete DWARF structure. + DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */); + } } // printUnknownCPUType() helps print_fat_headers for unknown CPU's. @@ -1323,9 +1403,12 @@ static void printCPUType(uint32_t cputype, uint32_t cpusubtype) { static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB, bool verbose) { outs() << "Fat headers\n"; - if (verbose) - outs() << "fat_magic FAT_MAGIC\n"; - else + if (verbose) { + if (UB->getMagic() == MachO::FAT_MAGIC) + outs() << "fat_magic FAT_MAGIC\n"; + else // UB->getMagic() == MachO::FAT_MAGIC_64 + outs() << "fat_magic FAT_MAGIC_64\n"; + } else outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n"; uint32_t nfat_arch = UB->getNumberOfObjects(); @@ -1452,13 +1535,11 @@ static void printArchiveChild(const Archive::Child &C, bool verbose, } static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) { - for (Archive::child_iterator I = A->child_begin(false), E = A->child_end(); - I != E; ++I) { - if (std::error_code EC = I->getError()) - report_fatal_error(EC.message()); - const Archive::Child &C = **I; + Error Err; + for (const auto &C : A->children(Err, false)) printArchiveChild(C, verbose, print_offset); - } + if (Err) + report_fatal_error(std::move(Err)); } // ParseInputMachO() parses the named Mach-O file in Filename and handles the @@ -1480,29 +1561,31 @@ void llvm::ParseInputMachO(StringRef Filename) { } // Attempt to open the binary. - ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename); - if (std::error_code EC = BinaryOrErr.getError()) - report_error(Filename, EC); + Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename); + if (!BinaryOrErr) + report_error(Filename, BinaryOrErr.takeError()); Binary &Bin = *BinaryOrErr.get().getBinary(); if (Archive *A = dyn_cast<Archive>(&Bin)) { outs() << "Archive : " << Filename << "\n"; if (ArchiveHeaders) printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); - I != E; ++I) { - if (std::error_code EC = I->getError()) - report_error(Filename, EC); - auto &C = I->get(); - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E)); continue; + } if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) { if (!checkMachOAndArchFlags(O, Filename)) return; ProcessMachO(Filename, O, O->getFileName()); } } + if (Err) + report_error(Filename, std::move(Err)); return; } if (UniversalHeaders) { @@ -1521,7 +1604,7 @@ void llvm::ParseInputMachO(StringRef Filename) { I != E; ++I) { if (ArchFlags[i] == I->getArchTypeName()) { ArchFound = true; - ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = + Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); std::string ArchitectureName = ""; if (ArchFlags.size() > 1) @@ -1530,7 +1613,12 @@ void llvm::ParseInputMachO(StringRef Filename) { ObjectFile &O = *ObjOrErr.get(); if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O)) ProcessMachO(Filename, MachOOF, "", ArchitectureName); - } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(Filename, StringRef(), std::move(E), + ArchitectureName); + continue; + } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) { std::unique_ptr<Archive> &A = *AOrErr; outs() << "Archive : " << Filename; @@ -1539,19 +1627,25 @@ void llvm::ParseInputMachO(StringRef Filename) { outs() << "\n"; if (ArchiveHeaders) printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator AI = A->child_begin(), - AE = A->child_end(); - AI != AE; ++AI) { - if (std::error_code EC = AI->getError()) - report_error(Filename, EC); - auto &C = AI->get(); - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E), ArchitectureName); continue; + } if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) ProcessMachO(Filename, O, O->getFileName(), ArchitectureName); } + if (Err) + report_error(Filename, std::move(Err)); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + Filename + " for " + + "architecture " + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } } } @@ -1571,32 +1665,42 @@ void llvm::ParseInputMachO(StringRef Filename) { I != E; ++I) { if (MachOObjectFile::getHostArch().getArchName() == I->getArchTypeName()) { - ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); + Expected<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 = + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(Filename, std::move(E)); + continue; + } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) { std::unique_ptr<Archive> &A = *AOrErr; outs() << "Archive : " << Filename << "\n"; if (ArchiveHeaders) printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator AI = A->child_begin(), - AE = A->child_end(); - AI != AE; ++AI) { - if (std::error_code EC = AI->getError()) - report_error(Filename, EC); - auto &C = AI->get(); - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E)); continue; + } if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) ProcessMachO(Filename, O, O->getFileName()); } + if (Err) + report_error(Filename, std::move(Err)); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + Filename + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } return; } @@ -1608,7 +1712,7 @@ void llvm::ParseInputMachO(StringRef Filename) { for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { - ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); + Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); std::string ArchitectureName = ""; if (moreThanOneArch) ArchitectureName = I->getArchTypeName(); @@ -1616,7 +1720,12 @@ void llvm::ParseInputMachO(StringRef Filename) { 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()) { + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(StringRef(), Filename, std::move(E), ArchitectureName); + continue; + } else if (Expected<std::unique_ptr<Archive>> AOrErr = + I->getAsArchive()) { std::unique_ptr<Archive> &A = *AOrErr; outs() << "Archive : " << Filename; if (!ArchitectureName.empty()) @@ -1624,14 +1733,14 @@ void llvm::ParseInputMachO(StringRef Filename) { outs() << "\n"; if (ArchiveHeaders) printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); - AI != AE; ++AI) { - if (std::error_code EC = AI->getError()) - report_error(Filename, EC); - auto &C = AI->get(); - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E), ArchitectureName); continue; + } if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) { if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O)) @@ -1639,6 +1748,13 @@ void llvm::ParseInputMachO(StringRef Filename) { ArchitectureName); } } + if (Err) + report_error(Filename, std::move(Err)); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + Filename + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } } return; @@ -1762,9 +1878,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, } } if (reloc_found && isExtern) { - ErrorOr<StringRef> SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); op_info->AddSymbol.Present = 1; op_info->AddSymbol.Name = name; @@ -1832,9 +1953,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // is the offset from the external symbol. if (info->O->getAnyRelocationPCRel(RE)) op_info->Value -= Pc + Offset + Size; - ErrorOr<StringRef> SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); unsigned Type = info->O->getAnyRelocationType(RE); if (Type == MachO::X86_64_RELOC_SUBTRACTOR) { @@ -1849,9 +1975,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, op_info->SubtractSymbol.Name = name; symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum); Symbol = *RelocSymNext; - ErrorOr<StringRef> SymNameNext = Symbol.getName(); - if (std::error_code EC = SymNameNext.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymNameNext = Symbol.getName(); + if (!SymNameNext) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameNext.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } name = SymNameNext->data(); } } @@ -1922,9 +2053,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, } if (isExtern) { - ErrorOr<StringRef> SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); op_info->AddSymbol.Present = 1; op_info->AddSymbol.Name = name; @@ -2042,9 +2178,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // NOTE: Scattered relocations don't exist on arm64. if (!info->O->getPlainRelocationExternal(RE)) return 0; - ErrorOr<StringRef> SymName = Reloc->getSymbol()->getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Reloc->getSymbol()->getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); op_info->AddSymbol.Present = 1; op_info->AddSymbol.Name = name; @@ -2172,9 +2313,14 @@ static const char *GuessIndirectSymbol(uint64_t ReferenceValue, if (indirect_symbol < Symtab.nsyms) { symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol); SymbolRef Symbol = *Sym; - ErrorOr<StringRef> SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); return name; } @@ -2207,9 +2353,14 @@ static const char *GuessIndirectSymbol(uint64_t ReferenceValue, if (indirect_symbol < Symtab.nsyms) { symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol); SymbolRef Symbol = *Sym; - ErrorOr<StringRef> SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); return name; } @@ -2436,9 +2587,14 @@ static const char *get_symbol_64(uint32_t sect_offset, SectionRef S, const char *SymbolName = nullptr; if (reloc_found && isExtern) { n_value = Symbol.getValue(); - ErrorOr<StringRef> NameOrError = Symbol.getName(); - if (std::error_code EC = NameOrError.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> NameOrError = Symbol.getName(); + if (!NameOrError) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(NameOrError.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef Name = *NameOrError; if (!Name.empty()) { SymbolName = Name.data(); @@ -5058,6 +5214,9 @@ static void print_image_info32(SectionRef S, struct DisassembleInfo *info) { struct objc_image_info32 o; const char *r; + if (S == SectionRef()) + return; + StringRef SectName; S.getName(SectName); DataRefImpl Ref = S.getRawDataRefImpl(); @@ -5530,6 +5689,373 @@ static void DumpProtocolSection(MachOObjectFile *O, const char *sect, } } +#ifdef HAVE_LIBXAR +inline void swapStruct(struct xar_header &xar) { + sys::swapByteOrder(xar.magic); + sys::swapByteOrder(xar.size); + sys::swapByteOrder(xar.version); + sys::swapByteOrder(xar.toc_length_compressed); + sys::swapByteOrder(xar.toc_length_uncompressed); + sys::swapByteOrder(xar.cksum_alg); +} + +static void PrintModeVerbose(uint32_t mode) { + switch(mode & S_IFMT){ + case S_IFDIR: + outs() << "d"; + break; + case S_IFCHR: + outs() << "c"; + break; + case S_IFBLK: + outs() << "b"; + break; + case S_IFREG: + outs() << "-"; + break; + case S_IFLNK: + outs() << "l"; + break; + case S_IFSOCK: + outs() << "s"; + break; + default: + outs() << "?"; + break; + } + + /* owner permissions */ + if(mode & S_IREAD) + outs() << "r"; + else + outs() << "-"; + if(mode & S_IWRITE) + outs() << "w"; + else + outs() << "-"; + if(mode & S_ISUID) + outs() << "s"; + else if(mode & S_IEXEC) + outs() << "x"; + else + outs() << "-"; + + /* group permissions */ + if(mode & (S_IREAD >> 3)) + outs() << "r"; + else + outs() << "-"; + if(mode & (S_IWRITE >> 3)) + outs() << "w"; + else + outs() << "-"; + if(mode & S_ISGID) + outs() << "s"; + else if(mode & (S_IEXEC >> 3)) + outs() << "x"; + else + outs() << "-"; + + /* other permissions */ + if(mode & (S_IREAD >> 6)) + outs() << "r"; + else + outs() << "-"; + if(mode & (S_IWRITE >> 6)) + outs() << "w"; + else + outs() << "-"; + if(mode & S_ISVTX) + outs() << "t"; + else if(mode & (S_IEXEC >> 6)) + outs() << "x"; + else + outs() << "-"; +} + +static void PrintXarFilesSummary(const char *XarFilename, xar_t xar) { + xar_iter_t xi; + xar_file_t xf; + xar_iter_t xp; + const char *key, *type, *mode, *user, *group, *size, *mtime, *name, *m; + char *endp; + uint32_t mode_value; + + xi = xar_iter_new(); + if (!xi) { + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename << "\n"; + return; + } + + // Go through the xar's files. + for (xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)) { + xp = xar_iter_new(); + if(!xp){ + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename << "\n"; + return; + } + type = nullptr; + mode = nullptr; + user = nullptr; + group = nullptr; + size = nullptr; + mtime = nullptr; + name = nullptr; + for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){ + const char *val = nullptr; + xar_prop_get(xf, key, &val); +#if 0 // Useful for debugging. + outs() << "key: " << key << " value: " << val << "\n"; +#endif + if(strcmp(key, "type") == 0) + type = val; + if(strcmp(key, "mode") == 0) + mode = val; + if(strcmp(key, "user") == 0) + user = val; + if(strcmp(key, "group") == 0) + group = val; + if(strcmp(key, "data/size") == 0) + size = val; + if(strcmp(key, "mtime") == 0) + mtime = val; + if(strcmp(key, "name") == 0) + name = val; + } + if(mode != nullptr){ + mode_value = strtoul(mode, &endp, 8); + if(*endp != '\0') + outs() << "(mode: \"" << mode << "\" contains non-octal chars) "; + if(strcmp(type, "file") == 0) + mode_value |= S_IFREG; + PrintModeVerbose(mode_value); + outs() << " "; + } + if(user != nullptr) + outs() << format("%10s/", user); + if(group != nullptr) + outs() << format("%-10s ", group); + if(size != nullptr) + outs() << format("%7s ", size); + if(mtime != nullptr){ + for(m = mtime; *m != 'T' && *m != '\0'; m++) + outs() << *m; + if(*m == 'T') + m++; + outs() << " "; + for( ; *m != 'Z' && *m != '\0'; m++) + outs() << *m; + outs() << " "; + } + if(name != nullptr) + outs() << name; + outs() << "\n"; + } +} + +static void DumpBitcodeSection(MachOObjectFile *O, const char *sect, + uint32_t size, bool verbose, + bool PrintXarHeader, bool PrintXarFileHeaders, + std::string XarMemberName) { + if(size < sizeof(struct xar_header)) { + outs() << "size of (__LLVM,__bundle) section too small (smaller than size " + "of struct xar_header)\n"; + return; + } + struct xar_header XarHeader; + memcpy(&XarHeader, sect, sizeof(struct xar_header)); + if (sys::IsLittleEndianHost) + swapStruct(XarHeader); + if (PrintXarHeader) { + if (!XarMemberName.empty()) + outs() << "In xar member " << XarMemberName << ": "; + else + outs() << "For (__LLVM,__bundle) section: "; + outs() << "xar header\n"; + if (XarHeader.magic == XAR_HEADER_MAGIC) + outs() << " magic XAR_HEADER_MAGIC\n"; + else + outs() << " magic " + << format_hex(XarHeader.magic, 10, true) + << " (not XAR_HEADER_MAGIC)\n"; + outs() << " size " << XarHeader.size << "\n"; + outs() << " version " << XarHeader.version << "\n"; + outs() << " toc_length_compressed " << XarHeader.toc_length_compressed + << "\n"; + outs() << "toc_length_uncompressed " << XarHeader.toc_length_uncompressed + << "\n"; + outs() << " cksum_alg "; + switch (XarHeader.cksum_alg) { + case XAR_CKSUM_NONE: + outs() << "XAR_CKSUM_NONE\n"; + break; + case XAR_CKSUM_SHA1: + outs() << "XAR_CKSUM_SHA1\n"; + break; + case XAR_CKSUM_MD5: + outs() << "XAR_CKSUM_MD5\n"; + break; +#ifdef XAR_CKSUM_SHA256 + case XAR_CKSUM_SHA256: + outs() << "XAR_CKSUM_SHA256\n"; + break; +#endif +#ifdef XAR_CKSUM_SHA512 + case XAR_CKSUM_SHA512: + outs() << "XAR_CKSUM_SHA512\n"; + break; +#endif + default: + outs() << XarHeader.cksum_alg << "\n"; + } + } + + SmallString<128> XarFilename; + int FD; + std::error_code XarEC = + sys::fs::createTemporaryFile("llvm-objdump", "xar", FD, XarFilename); + if (XarEC) { + errs() << XarEC.message() << "\n"; + return; + } + tool_output_file XarFile(XarFilename, FD); + raw_fd_ostream &XarOut = XarFile.os(); + StringRef XarContents(sect, size); + XarOut << XarContents; + XarOut.close(); + if (XarOut.has_error()) + return; + + xar_t xar = xar_open(XarFilename.c_str(), READ); + if (!xar) { + errs() << "Can't create temporary xar archive " << XarFilename << "\n"; + return; + } + + SmallString<128> TocFilename; + std::error_code TocEC = + sys::fs::createTemporaryFile("llvm-objdump", "toc", TocFilename); + if (TocEC) { + errs() << TocEC.message() << "\n"; + return; + } + xar_serialize(xar, TocFilename.c_str()); + + if (PrintXarFileHeaders) { + if (!XarMemberName.empty()) + outs() << "In xar member " << XarMemberName << ": "; + else + outs() << "For (__LLVM,__bundle) section: "; + outs() << "xar archive files:\n"; + PrintXarFilesSummary(XarFilename.c_str(), xar); + } + + ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = + MemoryBuffer::getFileOrSTDIN(TocFilename.c_str()); + if (std::error_code EC = FileOrErr.getError()) { + errs() << EC.message() << "\n"; + return; + } + std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get(); + + if (!XarMemberName.empty()) + outs() << "In xar member " << XarMemberName << ": "; + else + outs() << "For (__LLVM,__bundle) section: "; + outs() << "xar table of contents:\n"; + outs() << Buffer->getBuffer() << "\n"; + + // TODO: Go through the xar's files. + xar_iter_t xi = xar_iter_new(); + if(!xi){ + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename.c_str() << "\n"; + xar_close(xar); + return; + } + for(xar_file_t xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)){ + const char *key; + xar_iter_t xp; + const char *member_name, *member_type, *member_size_string; + size_t member_size; + + xp = xar_iter_new(); + if(!xp){ + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename.c_str() << "\n"; + xar_close(xar); + return; + } + member_name = NULL; + member_type = NULL; + member_size_string = NULL; + for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){ + const char *val = nullptr; + xar_prop_get(xf, key, &val); +#if 0 // Useful for debugging. + outs() << "key: " << key << " value: " << val << "\n"; +#endif + if(strcmp(key, "name") == 0) + member_name = val; + if(strcmp(key, "type") == 0) + member_type = val; + if(strcmp(key, "data/size") == 0) + member_size_string = val; + } + /* + * If we find a file with a name, date/size and type properties + * and with the type being "file" see if that is a xar file. + */ + if (member_name != NULL && member_type != NULL && + strcmp(member_type, "file") == 0 && + member_size_string != NULL){ + // Extract the file into a buffer. + char *endptr; + member_size = strtoul(member_size_string, &endptr, 10); + if (*endptr == '\0' && member_size != 0) { + char *buffer = (char *) ::operator new (member_size); + if (xar_extract_tobuffersz(xar, xf, &buffer, &member_size) == 0) { +#if 0 // Useful for debugging. + outs() << "xar member: " << member_name << " extracted\n"; +#endif + // Set the XarMemberName we want to see printed in the header. + std::string OldXarMemberName; + // If XarMemberName is already set this is nested. So + // save the old name and create the nested name. + if (!XarMemberName.empty()) { + OldXarMemberName = XarMemberName; + XarMemberName = + (Twine("[") + XarMemberName + "]" + member_name).str(); + } else { + OldXarMemberName = ""; + XarMemberName = member_name; + } + // See if this is could be a xar file (nested). + if (member_size >= sizeof(struct xar_header)) { +#if 0 // Useful for debugging. + outs() << "could be a xar file: " << member_name << "\n"; +#endif + memcpy((char *)&XarHeader, buffer, sizeof(struct xar_header)); + if (sys::IsLittleEndianHost) + swapStruct(XarHeader); + if(XarHeader.magic == XAR_HEADER_MAGIC) + DumpBitcodeSection(O, buffer, member_size, verbose, + PrintXarHeader, PrintXarFileHeaders, + XarMemberName); + } + XarMemberName = OldXarMemberName; + } + delete buffer; + } + } + xar_iter_free(xp); + } + xar_close(xar); +} +#endif // defined(HAVE_LIBXAR) + static void printObjcMetaData(MachOObjectFile *O, bool verbose) { if (O->is64Bit()) printObjc2_64bit_MetaData(O, verbose); @@ -5948,7 +6474,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, return; } - // Set up thumb disassembler. + // Set up separate thumb disassembler if needed. std::unique_ptr<const MCRegisterInfo> ThumbMRI; std::unique_ptr<const MCAsmInfo> ThumbAsmInfo; std::unique_ptr<const MCSubtargetInfo> ThumbSTI; @@ -6077,13 +6603,26 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, SymbolAddressMap AddrMap; bool DisSymNameFound = false; for (const SymbolRef &Symbol : MachOOF->symbols()) { - SymbolRef::Type ST = Symbol.getType(); + Expected<SymbolRef::Type> STOrErr = Symbol.getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + SymbolRef::Type ST = *STOrErr; if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data || ST == SymbolRef::ST_Other) { uint64_t Address = Symbol.getValue(); - ErrorOr<StringRef> SymNameOrErr = Symbol.getName(); - if (std::error_code EC = SymNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymNameOrErr = Symbol.getName(); + if (!SymNameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef SymName = *SymNameOrErr; AddrMap[Address] = SymName; if (!DisSymName.empty() && DisSymName == SymName) @@ -6121,20 +6660,61 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, ThumbSymbolizerInfo.adrp_addr = 0; ThumbSymbolizerInfo.adrp_inst = 0; + unsigned int Arch = MachOOF->getArch(); + + // Skip all symbols if this is a stubs file. + if (Bytes.size() == 0) + return; + // Disassemble symbol by symbol. for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) { - ErrorOr<StringRef> SymNameOrErr = Symbols[SymIdx].getName(); - if (std::error_code EC = SymNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> SymNameOrErr = Symbols[SymIdx].getName(); + if (!SymNameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef SymName = *SymNameOrErr; - SymbolRef::Type ST = Symbols[SymIdx].getType(); + Expected<SymbolRef::Type> STOrErr = Symbols[SymIdx].getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + SymbolRef::Type ST = *STOrErr; if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data) continue; // Make sure the symbol is defined in this section. bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]); - if (!containsSym) + if (!containsSym) { + if (!DisSymName.empty() && DisSymName == SymName) { + outs() << "-dis-symname: " << DisSymName << " not in the section\n"; + return; + } + continue; + } + // The __mh_execute_header is special and we need to deal with that fact + // this symbol is before the start of the (__TEXT,__text) section and at the + // address of the start of the __TEXT segment. This is because this symbol + // is an N_SECT symbol in the (__TEXT,__text) but its address is before the + // start of the section in a standard MH_EXECUTE filetype. + if (!DisSymName.empty() && DisSymName == "__mh_execute_header") { + outs() << "-dis-symname: __mh_execute_header not in any section\n"; + return; + } + // When this code is trying to disassemble a symbol at a time and in the + // case there is only the __mh_execute_header symbol left as in a stripped + // executable, we need to deal with this by ignoring this symbol so the + // whole section is disassembled and this symbol is then not displayed. + if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" || + SymName == "__mh_bundle_header" || SymName == "__mh_object_header" || + SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header") continue; // If we are only disassembling one symbol see if this is that symbol. @@ -6142,17 +6722,32 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, continue; // Start at the address of the symbol relative to the section's address. + uint64_t SectSize = Sections[SectIdx].getSize(); uint64_t Start = Symbols[SymIdx].getValue(); uint64_t SectionAddress = Sections[SectIdx].getAddress(); Start -= SectionAddress; + if (Start > SectSize) { + outs() << "section data ends, " << SymName + << " lies outside valid range\n"; + return; + } + // Stop disassembling either at the beginning of the next symbol or at // the end of the section. bool containsNextSym = false; uint64_t NextSym = 0; uint64_t NextSymIdx = SymIdx + 1; while (Symbols.size() > NextSymIdx) { - SymbolRef::Type NextSymType = Symbols[NextSymIdx].getType(); + Expected<SymbolRef::Type> STOrErr = Symbols[NextSymIdx].getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + SymbolRef::Type NextSymType = *STOrErr; if (NextSymType == SymbolRef::ST_Function) { containsNextSym = Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]); @@ -6163,15 +6758,17 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, ++NextSymIdx; } - uint64_t SectSize = Sections[SectIdx].getSize(); - uint64_t End = containsNextSym ? NextSym : SectSize; + uint64_t End = containsNextSym ? std::min(NextSym, SectSize) : SectSize; uint64_t Size; symbolTableWorked = true; DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl(); - bool isThumb = - (MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb) && ThumbTarget; + bool IsThumb = MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb; + + // We only need the dedicated Thumb target if there's a real choice + // (i.e. we're not targeting M-class) and the function is Thumb. + bool UseThumbTarget = IsThumb && ThumbTarget; outs() << SymName << ":\n"; DILineInfo lastLine; @@ -6189,7 +6786,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, outs() << format("%8" PRIx64 ":", PC); } } - if (!NoShowRawInsn) + if (!NoShowRawInsn || Arch == Triple::arm) outs() << "\t"; // Check the data in code table here to see if this is data not an @@ -6215,19 +6812,19 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, raw_svector_ostream Annotations(AnnotationsBytes); bool gotInst; - if (isThumb) + if (UseThumbTarget) gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC, DebugOut, Annotations); else gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC, DebugOut, Annotations); if (gotInst) { - if (!NoShowRawInsn) { + if (!NoShowRawInsn || Arch == Triple::arm) { dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs()); } formatted_raw_ostream FormattedOS(outs()); StringRef AnnotationsStr = Annotations.str(); - if (isThumb) + if (UseThumbTarget) ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI); else IP->printInst(&Inst, FormattedOS, AnnotationsStr, *STI); @@ -6249,14 +6846,21 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, outs() << format("\t.byte 0x%02x #bad opcode\n", *(Bytes.data() + Index) & 0xff); Size = 1; // skip exactly one illegible byte and move on. - } else if (Arch == Triple::aarch64) { + } else if (Arch == Triple::aarch64 || + (Arch == Triple::arm && !IsThumb)) { uint32_t opcode = (*(Bytes.data() + Index) & 0xff) | (*(Bytes.data() + Index + 1) & 0xff) << 8 | (*(Bytes.data() + Index + 2) & 0xff) << 16 | (*(Bytes.data() + Index + 3) & 0xff) << 24; outs() << format("\t.long\t0x%08x\n", opcode); Size = 4; - } else { + } else if (Arch == Triple::arm) { + assert(IsThumb && "ARM mode should have been dealt with above"); + uint32_t opcode = (*(Bytes.data() + Index) & 0xff) | + (*(Bytes.data() + Index + 1) & 0xff) << 8; + outs() << format("\t.short\t0x%04x\n", opcode); + Size = 2; + } else{ errs() << "llvm-objdump: warning: invalid instruction encoding\n"; if (Size == 0) Size = 1; // skip illegible bytes @@ -6285,7 +6889,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, outs() << format("%8" PRIx64 ":", PC); } } - if (!NoShowRawInsn) { + if (!NoShowRawInsn || Arch == Triple::arm) { outs() << "\t"; dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs()); } @@ -6387,9 +6991,14 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj, const RelocationRef &Reloc, uint64_t Addr, StringRef &Name, uint64_t &Addend) { if (Reloc.getSymbol() != Obj->symbol_end()) { - ErrorOr<StringRef> NameOrErr = Reloc.getSymbol()->getName(); - if (std::error_code EC = NameOrErr.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> NameOrErr = Reloc.getSymbol()->getName(); + if (!NameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(NameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } Name = *NameOrErr; Addend = Addr; return; @@ -6412,12 +7021,25 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj, // Go back one so that SymbolAddress <= Addr. --Sym; - section_iterator SymSection = *Sym->second.getSection(); + auto SectOrErr = Sym->second.getSection(); + if (!SectOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SectOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + section_iterator SymSection = *SectOrErr; if (RelocSection == *SymSection) { // There's a valid symbol in the same section before this reference. - ErrorOr<StringRef> NameOrErr = Sym->second.getName(); - if (std::error_code EC = NameOrErr.getError()) - report_fatal_error(EC.message()); + Expected<StringRef> NameOrErr = Sym->second.getName(); + if (!NameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(NameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } Name = *NameOrErr; Addend = Addr - Sym->first; return; @@ -6750,268 +7372,18 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, } } -static unsigned getSizeForEncoding(bool is64Bit, - unsigned symbolEncoding) { - unsigned format = symbolEncoding & 0x0f; - switch (format) { - default: llvm_unreachable("Unknown Encoding"); - case dwarf::DW_EH_PE_absptr: - case dwarf::DW_EH_PE_signed: - return is64Bit ? 8 : 4; - case dwarf::DW_EH_PE_udata2: - case dwarf::DW_EH_PE_sdata2: - return 2; - case dwarf::DW_EH_PE_udata4: - case dwarf::DW_EH_PE_sdata4: - return 4; - case dwarf::DW_EH_PE_udata8: - case dwarf::DW_EH_PE_sdata8: - return 8; - } -} - -static uint64_t readPointer(const char *&Pos, bool is64Bit, unsigned Encoding) { - switch (getSizeForEncoding(is64Bit, Encoding)) { - case 2: - return readNext<uint16_t>(Pos); - break; - case 4: - return readNext<uint32_t>(Pos); - break; - case 8: - return readNext<uint64_t>(Pos); - break; - default: - llvm_unreachable("Illegal data size"); - } -} - -static void printMachOEHFrameSection(const MachOObjectFile *Obj, - std::map<uint64_t, SymbolRef> &Symbols, - const SectionRef &EHFrame) { - if (!Obj->isLittleEndian()) { - outs() << "warning: cannot handle big endian __eh_frame section\n"; - return; - } - - bool is64Bit = Obj->is64Bit(); - - outs() << "Contents of __eh_frame section:\n"; - - StringRef Contents; - EHFrame.getContents(Contents); - - /// A few fields of the CIE are used when decoding the FDE's. This struct - /// will cache those fields we need so that we don't have to decode it - /// repeatedly for each FDE that references it. - struct DecodedCIE { - Optional<uint32_t> FDEPointerEncoding; - Optional<uint32_t> LSDAPointerEncoding; - bool hasAugmentationLength; - }; - - // Map from the start offset of the CIE to the cached data for that CIE. - DenseMap<uint64_t, DecodedCIE> CachedCIEs; - - for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) { - - const char *EntryStartPos = Pos; - - uint64_t Length = readNext<uint32_t>(Pos); - if (Length == 0xffffffff) - Length = readNext<uint64_t>(Pos); - - // Save the Pos so that we can check the length we encoded against what we - // end up decoding. - const char *PosAfterLength = Pos; - const char *EntryEndPos = PosAfterLength + Length; - - assert(EntryEndPos <= End && - "__eh_frame entry length exceeds section size"); - - uint32_t ID = readNext<uint32_t>(Pos); - if (ID == 0) { - // This is a CIE. - - uint32_t Version = readNext<uint8_t>(Pos); - - // Parse a null terminated augmentation string - SmallString<8> AugmentationString; - for (uint8_t Char = readNext<uint8_t>(Pos); Char; - Char = readNext<uint8_t>(Pos)) - AugmentationString.push_back(Char); - - // Optionally parse the EH data if the augmentation string says it's there. - Optional<uint64_t> EHData; - if (StringRef(AugmentationString).count("eh")) - EHData = is64Bit ? readNext<uint64_t>(Pos) : readNext<uint32_t>(Pos); - - unsigned ULEBByteCount; - uint64_t CodeAlignmentFactor = decodeULEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - int64_t DataAlignmentFactor = decodeSLEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - uint32_t ReturnAddressRegister = readNext<uint8_t>(Pos); - - Optional<uint64_t> AugmentationLength; - Optional<uint32_t> LSDAPointerEncoding; - Optional<uint32_t> PersonalityEncoding; - Optional<uint64_t> Personality; - Optional<uint32_t> FDEPointerEncoding; - if (!AugmentationString.empty() && AugmentationString.front() == 'z') { - AugmentationLength = decodeULEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - // Walk the augmentation string to get all the augmentation data. - for (unsigned i = 1, e = AugmentationString.size(); i != e; ++i) { - char Char = AugmentationString[i]; - switch (Char) { - case 'e': - assert((i + 1) != e && AugmentationString[i + 1] == 'h' && - "Expected 'eh' in augmentation string"); - break; - case 'L': - assert(!LSDAPointerEncoding && "Duplicate LSDA encoding"); - LSDAPointerEncoding = readNext<uint8_t>(Pos); - break; - case 'P': { - assert(!Personality && "Duplicate personality"); - PersonalityEncoding = readNext<uint8_t>(Pos); - Personality = readPointer(Pos, is64Bit, *PersonalityEncoding); - break; - } - case 'R': - assert(!FDEPointerEncoding && "Duplicate FDE encoding"); - FDEPointerEncoding = readNext<uint8_t>(Pos); - break; - case 'z': - llvm_unreachable("'z' must be first in the augmentation string"); - } - } - } - - outs() << "CIE:\n"; - outs() << " Length: " << Length << "\n"; - outs() << " CIE ID: " << ID << "\n"; - outs() << " Version: " << Version << "\n"; - outs() << " Augmentation String: " << AugmentationString << "\n"; - if (EHData) - outs() << " EHData: " << *EHData << "\n"; - outs() << " Code Alignment Factor: " << CodeAlignmentFactor << "\n"; - outs() << " Data Alignment Factor: " << DataAlignmentFactor << "\n"; - outs() << " Return Address Register: " << ReturnAddressRegister << "\n"; - if (AugmentationLength) { - outs() << " Augmentation Data Length: " << *AugmentationLength << "\n"; - if (LSDAPointerEncoding) { - outs() << " FDE LSDA Pointer Encoding: " - << *LSDAPointerEncoding << "\n"; - } - if (Personality) { - outs() << " Personality Encoding: " << *PersonalityEncoding << "\n"; - outs() << " Personality: " << *Personality << "\n"; - } - if (FDEPointerEncoding) { - outs() << " FDE Address Pointer Encoding: " - << *FDEPointerEncoding << "\n"; - } - } - // FIXME: Handle instructions. - // For now just emit some bytes - outs() << " Instructions:\n "; - dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos), - outs()); - outs() << "\n"; - Pos = EntryEndPos; - - // Cache this entry. - uint64_t Offset = EntryStartPos - Contents.data(); - CachedCIEs[Offset] = { FDEPointerEncoding, LSDAPointerEncoding, - AugmentationLength.hasValue() }; - continue; - } - - // This is an FDE. - // The CIE pointer for an FDE is the same location as the ID which we - // already read. - uint32_t CIEPointer = ID; - - const char *CIEStart = PosAfterLength - CIEPointer; - assert(CIEStart >= Contents.data() && - "FDE points to CIE before the __eh_frame start"); - - uint64_t CIEOffset = CIEStart - Contents.data(); - auto CIEIt = CachedCIEs.find(CIEOffset); - if (CIEIt == CachedCIEs.end()) - llvm_unreachable("Couldn't find CIE at offset in to __eh_frame section"); - - const DecodedCIE &CIE = CIEIt->getSecond(); - assert(CIE.FDEPointerEncoding && - "FDE references CIE which did not set pointer encoding"); - - uint64_t PCPointerSize = getSizeForEncoding(is64Bit, - *CIE.FDEPointerEncoding); - - uint64_t PCBegin = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding); - uint64_t PCRange = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding); - - Optional<uint64_t> AugmentationLength; - uint32_t LSDAPointerSize; - Optional<uint64_t> LSDAPointer; - if (CIE.hasAugmentationLength) { - unsigned ULEBByteCount; - AugmentationLength = decodeULEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - // Decode the LSDA if the CIE augmentation string said we should. - if (CIE.LSDAPointerEncoding) { - LSDAPointerSize = getSizeForEncoding(is64Bit, *CIE.LSDAPointerEncoding); - LSDAPointer = readPointer(Pos, is64Bit, *CIE.LSDAPointerEncoding); - } - } - - outs() << "FDE:\n"; - outs() << " Length: " << Length << "\n"; - outs() << " CIE Offset: " << CIEOffset << "\n"; - - if (PCPointerSize == 8) { - outs() << format(" PC Begin: %016" PRIx64, PCBegin) << "\n"; - outs() << format(" PC Range: %016" PRIx64, PCRange) << "\n"; - } else { - outs() << format(" PC Begin: %08" PRIx64, PCBegin) << "\n"; - outs() << format(" PC Range: %08" PRIx64, PCRange) << "\n"; - } - if (AugmentationLength) { - outs() << " Augmentation Data Length: " << *AugmentationLength << "\n"; - if (LSDAPointer) { - if (LSDAPointerSize == 8) - outs() << format(" LSDA Pointer: %016\n" PRIx64, *LSDAPointer); - else - outs() << format(" LSDA Pointer: %08\n" PRIx64, *LSDAPointer); - } - } - - // FIXME: Handle instructions. - // For now just emit some bytes - outs() << " Instructions:\n "; - dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos), - outs()); - outs() << "\n"; - Pos = EntryEndPos; - } -} - void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) { std::map<uint64_t, SymbolRef> Symbols; for (const SymbolRef &SymRef : Obj->symbols()) { // Discard any undefined or absolute symbols. They're not going to take part // in the convenience lookup for unwind info and just take up resources. - section_iterator Section = *SymRef.getSection(); + auto SectOrErr = SymRef.getSection(); + if (!SectOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SectOrErr.takeError()); + continue; + } + section_iterator Section = *SectOrErr; if (Section == Obj->section_end()) continue; @@ -7026,8 +7398,6 @@ void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) { printMachOCompactUnwindSection(Obj, Symbols, Section); else if (SectName == "__unwind_info") printMachOUnwindInfoSection(Obj, Symbols, Section); - else if (SectName == "__eh_frame") - printMachOEHFrameSection(Obj, Symbols, Section); } } @@ -7145,6 +7515,10 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype, break; } break; + default: + outs() << format(" %7d", cputype); + outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK); + break; } if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) { outs() << " LIB64"; @@ -8488,7 +8862,7 @@ static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) { static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld, uint32_t object_size) { if (ld.cmd == MachO::LC_CODE_SIGNATURE) - outs() << " cmd LC_FUNCTION_STARTS\n"; + outs() << " cmd LC_CODE_SIGNATURE\n"; else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO) outs() << " cmd LC_SEGMENT_SPLIT_INFO\n"; else if (ld.cmd == MachO::LC_FUNCTION_STARTS) |