summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/llvm-objdump/MachODump.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/llvm-objdump/MachODump.cpp')
-rw-r--r--contrib/llvm/tools/llvm-objdump/MachODump.cpp1156
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)
OpenPOWER on IntegriCloud