diff options
author | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
commit | 06210ae42d418d50d8d9365d5c9419308ae9e7ee (patch) | |
tree | ab60b4cdd6e430dda1f292a46a77ddb744723f31 /contrib/llvm/tools/llvm-objdump/MachODump.cpp | |
parent | 2dd166267f53df1c3748b4325d294b9b839de74b (diff) | |
download | FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.zip FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.tar.gz |
MFC r309124:
Upgrade our copies of clang, llvm, lldb, compiler-rt and libc++ to 3.9.0
release, and add lld 3.9.0. Also completely revamp the build system for
clang, llvm, lldb and their related tools.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld are available here:
<http://llvm.org/releases/3.9.0/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/clang/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Bryan Drewery, Andrew Turner, Antoine Brodin and Jan
Beich for their help.
Relnotes: yes
MFC r309147:
Pull in r282174 from upstream llvm trunk (by Krzysztof Parzyszek):
[PPC] Set SP after loading data from stack frame, if no red zone is
present
Follow-up to r280705: Make sure that the SP is only restored after
all data is loaded from the stack frame, if there is no red zone.
This completes the fix for
https://llvm.org/bugs/show_bug.cgi?id=26519.
Differential Revision: https://reviews.llvm.org/D24466
Reported by: Mark Millard
PR: 214433
MFC r309149:
Pull in r283060 from upstream llvm trunk (by Hal Finkel):
[PowerPC] Refactor soft-float support, and enable PPC64 soft float
This change enables soft-float for PowerPC64, and also makes
soft-float disable all vector instruction sets for both 32-bit and
64-bit modes. This latter part is necessary because the PPC backend
canonicalizes many Altivec vector types to floating-point types, and
so soft-float breaks scalarization support for many operations. Both
for embedded targets and for operating-system kernels desiring
soft-float support, it seems reasonable that disabling hardware
floating-point also disables vector instructions (embedded targets
without hardware floating point support are unlikely to have Altivec,
etc. and operating system kernels desiring not to use floating-point
registers to lower syscall cost are unlikely to want to use vector
registers either). If someone needs this to work, we'll need to
change the fact that we promote many Altivec operations to act on
v4f32. To make it possible to disable Altivec when soft-float is
enabled, hardware floating-point support needs to be expressed as a
positive feature, like the others, and not a negative feature,
because target features cannot have dependencies on the disabling of
some other feature. So +soft-float has now become -hard-float.
Fixes PR26970.
Pull in r283061 from upstream clang trunk (by Hal Finkel):
[PowerPC] Enable soft-float for PPC64, and +soft-float -> -hard-float
Enable soft-float support on PPC64, as the backend now supports it.
Also, the backend now uses -hard-float instead of +soft-float, so set
the target features accordingly.
Fixes PR26970.
Reported by: Mark Millard
PR: 214433
MFC r309212:
Add a few missed clang 3.9.0 files to OptionalObsoleteFiles.
MFC r309262:
Fix packaging for clang, lldb and lld 3.9.0
During the upgrade of clang/llvm etc to 3.9.0 in r309124, the PACKAGE
directive in the usr.bin/clang/*.mk files got dropped accidentally.
Restore it, with a few minor changes and additions:
* Correct license in clang.ucl to NCSA
* Add PACKAGE=clang for clang and most of the "ll" tools
* Put lldb in its own package
* Put lld in its own package
Reviewed by: gjb, jmallett
Differential Revision: https://reviews.freebsd.org/D8666
MFC r309656:
During the bootstrap phase, when building the minimal llvm library on
PowerPC, add lib/Support/Atomic.cpp. This is needed because upstream
llvm revision r271821 disabled the use of std::call_once, which causes
some fallback functions from Atomic.cpp to be used instead.
Reported by: Mark Millard
PR: 214902
MFC r309835:
Tentatively apply https://reviews.llvm.org/D18730 to work around gcc PR
70528 (bogus error: constructor required before non-static data member).
This should fix buildworld with the external gcc package.
Reported by: https://jenkins.freebsd.org/job/FreeBSD_HEAD_amd64_gcc/
MFC r310194:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
3.9.1 release.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/3.9.1/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/lld/docs/ReleaseNotes.html>
Relnotes: yes
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) |