Index: test/tools/llvm-objdump/X86/macho-private-headers.test =================================================================== --- test/tools/llvm-objdump/X86/macho-private-headers.test +++ test/tools/llvm-objdump/X86/macho-private-headers.test @@ -19,6 +19,8 @@ // RUN: | FileCheck %s -check-prefix=THREAD // RUN: llvm-objdump -macho -p -arch i386 %p/Inputs/macho-universal.x86_64.i386 \ // RUN: | FileCheck %s -check-prefix=FATi386 +// RUN: llvm-objdump -p -arch i386 %p/Inputs/macho-universal.x86_64.i386 \ +// RUN: | FileCheck %s -check-prefix=FATi386 // RUN: llvm-objdump -p -non-verbose %p/Inputs/hello.obj.macho-x86_64 \ // RUN: | FileCheck %s -check-prefix=NON_VERBOSE // RUN: llvm-objdump -p %p/Inputs/codesig.macho-x86_64 \ Index: test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test =================================================================== --- test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test +++ test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test @@ -1,5 +1,7 @@ RUN: llvm-objdump %p/Inputs/macho-universal.x86_64.i386 -d -m -no-show-raw-insn -full-leading-addr -print-imm-hex -arch all \ RUN: | FileCheck %s -check-prefix UEXE-all +RUN: llvm-objdump %p/Inputs/macho-universal.x86_64.i386 -d -no-show-raw-insn -full-leading-addr -print-imm-hex -arch all \ +RUN: | FileCheck %s -check-prefix UEXE-all RUN: llvm-objdump %p/Inputs/macho-universal-archive.x86_64.i386 -d -m -no-show-raw-insn -full-leading-addr -print-imm-hex -arch i386 \ RUN: | FileCheck %s -check-prefix UArchive-i386 RUN: llvm-objdump %p/Inputs/macho-universal.x86_64.i386 -universal-headers -m \ Index: tools/llvm-objdump/MachODump.cpp =================================================================== --- tools/llvm-objdump/MachODump.cpp +++ tools/llvm-objdump/MachODump.cpp @@ -1937,11 +1937,7 @@ report_error(StringRef(), Filename, std::move(Err), ArchitectureName); } -// ParseInputMachO() parses the named Mach-O file in Filename and handles the -// -arch flags selecting just those slices as specified by them and also parses -// archive files. Then for each individual Mach-O file ProcessMachO() is -// called to process the file based on the command line options. -void llvm::ParseInputMachO(StringRef Filename) { +static bool ValidateArchFlags() { // Check for -arch all and verifiy the -arch flags are valid. for (unsigned i = 0; i < ArchFlags.size(); ++i) { if (ArchFlags[i] == "all") { @@ -1950,10 +1946,20 @@ if (!MachOObjectFile::isValidArch(ArchFlags[i])) { errs() << "llvm-objdump: Unknown architecture named '" + ArchFlags[i] + "'for the -arch option\n"; - return; + return false; } } } + return true; +} + +// ParseInputMachO() parses the named Mach-O file in Filename and handles the +// -arch flags selecting just those slices as specified by them and also parses +// archive files. Then for each individual Mach-O file ProcessMachO() is +// called to process the file based on the command line options. +void llvm::ParseInputMachO(StringRef Filename) { + if (!ValidateArchFlags()) + return; // Attempt to open the binary. Expected> BinaryOrErr = createBinary(Filename); @@ -1989,191 +1995,199 @@ report_error(Filename, std::move(Err)); return; } - if (UniversalHeaders) { - if (MachOUniversalBinary *UB = dyn_cast(&Bin)) - printMachOUniversalHeaders(UB, !NonVerbose); - } if (MachOUniversalBinary *UB = dyn_cast(&Bin)) { - // If we have a list of architecture flags specified dump only those. - if (!ArchAll && ArchFlags.size() != 0) { - // Look for a slice in the universal binary that matches each ArchFlag. - bool ArchFound; - for (unsigned i = 0; i < ArchFlags.size(); ++i) { - ArchFound = false; - for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), - E = UB->end_objects(); - I != E; ++I) { - if (ArchFlags[i] == I->getArchFlagName()) { - ArchFound = true; - Expected> ObjOrErr = - I->getAsObjectFile(); - std::string ArchitectureName = ""; - if (ArchFlags.size() > 1) - ArchitectureName = I->getArchFlagName(); - if (ObjOrErr) { - ObjectFile &O = *ObjOrErr.get(); - if (MachOObjectFile *MachOOF = dyn_cast(&O)) - ProcessMachO(Filename, MachOOF, "", ArchitectureName); - } else if (auto E = isNotObjectErrorInvalidFileType( - ObjOrErr.takeError())) { - report_error(Filename, StringRef(), std::move(E), - ArchitectureName); - continue; - } else if (Expected> AOrErr = - I->getAsArchive()) { - std::unique_ptr &A = *AOrErr; - outs() << "Archive : " << Filename; - if (!ArchitectureName.empty()) - outs() << " (architecture " << ArchitectureName << ")"; - outs() << "\n"; - if (ArchiveHeaders) - printArchiveHeaders(Filename, A.get(), !NonVerbose, - ArchiveMemberOffsets, ArchitectureName); - Error Err = Error::success(); - for (auto &C : A->children(Err)) { - Expected> 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(&*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->getArchFlagName()) + - " is not a Mach-O file or an archive file"); - } - } - } - if (!ArchFound) { - errs() << "llvm-objdump: file: " + Filename + " does not contain " - << "architecture: " + ArchFlags[i] + "\n"; - return; - } - } + ParseInputMachO(UB); + return; + } + if (ObjectFile *O = dyn_cast(&Bin)) { + if (!checkMachOAndArchFlags(O, Filename)) return; - } - // No architecture flags were specified so if this contains a slice that - // matches the host architecture dump only that. - if (!ArchAll) { + if (MachOObjectFile *MachOOF = dyn_cast(&*O)) + ProcessMachO(Filename, MachOOF); + else + errs() << "llvm-objdump: '" << Filename << "': " + << "Object is not a Mach-O file type.\n"; + return; + } + llvm_unreachable("Input object can't be invalid at this point"); +} + +void llvm::ParseInputMachO(MachOUniversalBinary *UB) { + if (!ValidateArchFlags()) + return; + + auto Filename = UB->getFileName(); + + if (UniversalHeaders) + printMachOUniversalHeaders(UB, !NonVerbose); + + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && ArchFlags.size() != 0) { + // Look for a slice in the universal binary that matches each ArchFlag. + bool ArchFound; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + ArchFound = false; for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), - E = UB->end_objects(); - I != E; ++I) { - if (MachOObjectFile::getHostArch().getArchName() == - I->getArchFlagName()) { - Expected> ObjOrErr = I->getAsObjectFile(); - std::string ArchiveName; - ArchiveName.clear(); + E = UB->end_objects(); + I != E; ++I) { + if (ArchFlags[i] == I->getArchFlagName()) { + ArchFound = true; + Expected> ObjOrErr = + I->getAsObjectFile(); + std::string ArchitectureName = ""; + if (ArchFlags.size() > 1) + ArchitectureName = I->getArchFlagName(); if (ObjOrErr) { ObjectFile &O = *ObjOrErr.get(); if (MachOObjectFile *MachOOF = dyn_cast(&O)) - ProcessMachO(Filename, MachOOF); + ProcessMachO(Filename, MachOOF, "", ArchitectureName); } else if (auto E = isNotObjectErrorInvalidFileType( - ObjOrErr.takeError())) { - report_error(Filename, std::move(E)); + ObjOrErr.takeError())) { + report_error(Filename, StringRef(), std::move(E), + ArchitectureName); continue; } else if (Expected> AOrErr = - I->getAsArchive()) { + I->getAsArchive()) { std::unique_ptr &A = *AOrErr; - outs() << "Archive : " << Filename << "\n"; + outs() << "Archive : " << Filename; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << "\n"; if (ArchiveHeaders) printArchiveHeaders(Filename, A.get(), !NonVerbose, - ArchiveMemberOffsets); + ArchiveMemberOffsets, ArchitectureName); Error Err = Error::success(); for (auto &C : A->children(Err)) { Expected> ChildOrErr = C.getAsBinary(); if (!ChildOrErr) { if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) - report_error(Filename, C, std::move(E)); + report_error(Filename, C, std::move(E), ArchitectureName); continue; } if (MachOObjectFile *O = dyn_cast(&*ChildOrErr.get())) - ProcessMachO(Filename, O, O->getFileName()); + 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->getArchFlagName()) + + error("Mach-O universal file: " + Filename + " for " + + "architecture " + StringRef(I->getArchFlagName()) + " is not a Mach-O file or an archive file"); } - return; } } + if (!ArchFound) { + errs() << "llvm-objdump: file: " + Filename + " does not contain " + << "architecture: " + ArchFlags[i] + "\n"; + return; + } } - // Either all architectures have been specified or none have been specified - // and this does not contain the host architecture so dump all the slices. - bool moreThanOneArch = UB->getNumberOfObjects() > 1; + return; + } + // No architecture flags were specified so if this contains a slice that + // matches the host architecture dump only that. + if (!ArchAll) { for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), - E = UB->end_objects(); - I != E; ++I) { - Expected> ObjOrErr = I->getAsObjectFile(); - std::string ArchitectureName = ""; - if (moreThanOneArch) - ArchitectureName = I->getArchFlagName(); - if (ObjOrErr) { - ObjectFile &Obj = *ObjOrErr.get(); - if (MachOObjectFile *MachOOF = dyn_cast(&Obj)) - ProcessMachO(Filename, MachOOF, "", ArchitectureName); - } else if (auto E = isNotObjectErrorInvalidFileType( - ObjOrErr.takeError())) { - report_error(StringRef(), Filename, std::move(E), ArchitectureName); - continue; - } else if (Expected> AOrErr = - I->getAsArchive()) { - std::unique_ptr &A = *AOrErr; - outs() << "Archive : " << Filename; - if (!ArchitectureName.empty()) - outs() << " (architecture " << ArchitectureName << ")"; - outs() << "\n"; - if (ArchiveHeaders) - printArchiveHeaders(Filename, A.get(), !NonVerbose, - ArchiveMemberOffsets, ArchitectureName); - Error Err = Error::success(); - for (auto &C : A->children(Err)) { - Expected> 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(&*ChildOrErr.get())) { - if (MachOObjectFile *MachOOF = dyn_cast(O)) - ProcessMachO(Filename, MachOOF, MachOOF->getFileName(), - ArchitectureName); + E = UB->end_objects(); + I != E; ++I) { + if (MachOObjectFile::getHostArch().getArchName() == + I->getArchFlagName()) { + Expected> ObjOrErr = I->getAsObjectFile(); + std::string ArchiveName; + ArchiveName.clear(); + if (ObjOrErr) { + ObjectFile &O = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&O)) + ProcessMachO(Filename, MachOOF); + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(Filename, std::move(E)); + continue; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; + outs() << "Archive : " << Filename << "\n"; + if (ArchiveHeaders) + printArchiveHeaders(Filename, A.get(), !NonVerbose, + ArchiveMemberOffsets); + Error Err = Error::success(); + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E)); + continue; + } + if (MachOObjectFile *O = + dyn_cast(&*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->getArchFlagName()) + + " is not a Mach-O file or an archive file"); } - if (Err) - report_error(Filename, std::move(Err)); - } else { - consumeError(AOrErr.takeError()); - error("Mach-O universal file: " + Filename + " for architecture " + - StringRef(I->getArchFlagName()) + - " is not a Mach-O file or an archive file"); + return; } } - return; } - if (ObjectFile *O = dyn_cast(&Bin)) { - if (!checkMachOAndArchFlags(O, Filename)) - return; - if (MachOObjectFile *MachOOF = dyn_cast(&*O)) { - ProcessMachO(Filename, MachOOF); - } else - errs() << "llvm-objdump: '" << Filename << "': " - << "Object is not a Mach-O file type.\n"; - return; + // Either all architectures have been specified or none have been specified + // and this does not contain the host architecture so dump all the slices. + bool moreThanOneArch = UB->getNumberOfObjects() > 1; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + Expected> ObjOrErr = I->getAsObjectFile(); + std::string ArchitectureName = ""; + if (moreThanOneArch) + ArchitectureName = I->getArchFlagName(); + if (ObjOrErr) { + ObjectFile &Obj = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&Obj)) + ProcessMachO(Filename, MachOOF, "", ArchitectureName); + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(StringRef(), Filename, std::move(E), ArchitectureName); + continue; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; + outs() << "Archive : " << Filename; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << "\n"; + if (ArchiveHeaders) + printArchiveHeaders(Filename, A.get(), !NonVerbose, + ArchiveMemberOffsets, ArchitectureName); + Error Err = Error::success(); + for (auto &C : A->children(Err)) { + Expected> 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(&*ChildOrErr.get())) { + if (MachOObjectFile *MachOOF = dyn_cast(O)) + ProcessMachO(Filename, MachOOF, MachOOF->getFileName(), + ArchitectureName); + } + } + if (Err) + report_error(Filename, std::move(Err)); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + Filename + " for architecture " + + StringRef(I->getArchFlagName()) + + " is not a Mach-O file or an archive file"); + } } - llvm_unreachable("Input object can't be invalid at this point"); } // The block of info used by the Symbolizer call backs. Index: tools/llvm-objdump/llvm-objdump.h =================================================================== --- tools/llvm-objdump/llvm-objdump.h +++ tools/llvm-objdump/llvm-objdump.h @@ -22,6 +22,7 @@ class COFFObjectFile; class COFFImportFile; class MachOObjectFile; + class MachOUniversalBinary; class ObjectFile; class Archive; class RelocationRef; @@ -70,6 +71,7 @@ void error(std::error_code ec); bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b); void ParseInputMachO(StringRef Filename); +void ParseInputMachO(object::MachOUniversalBinary *UB); void printCOFFUnwindInfo(const object::COFFObjectFile* o); void printMachOUnwindInfo(const object::MachOObjectFile* o); void printMachOExportsTrie(const object::MachOObjectFile* o); Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -41,6 +41,7 @@ #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/Wasm.h" #include "llvm/Support/Casting.h" @@ -2331,6 +2332,8 @@ DumpArchive(a); else if (ObjectFile *o = dyn_cast(&Binary)) DumpObject(o); + else if (MachOUniversalBinary *UB = dyn_cast(&Binary)) + ParseInputMachO(UB); else report_error(file, object_error::invalid_file_type); }