diff --git a/llvm/test/tools/llvm-lipo/archs-macho-binary-unknown.test b/llvm/test/tools/llvm-lipo/archs-macho-binary-unknown.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lipo/archs-macho-binary-unknown.test @@ -0,0 +1,15 @@ +# RUN: yaml2obj %s > %t +# Tests that the output for an unknown architecture is the same as cctools lipo +# RUN: llvm-lipo %t -archs | FileCheck %s +# CHECK: unknown(151,3) + +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000097 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00002000 +... diff --git a/llvm/test/tools/llvm-lipo/archs-macho-binary.test b/llvm/test/tools/llvm-lipo/archs-macho-binary.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lipo/archs-macho-binary.test @@ -0,0 +1,19 @@ +# RUN: yaml2obj %s > %t + +# RUN: llvm-lipo %t -archs | FileCheck --check-prefix=ARCHS %s +# RUN: llvm-lipo %t --archs | FileCheck --check-prefix=ARCHS %s +# ARCHS: i386 + +# RUN: not llvm-lipo %t %t -archs 2>&1 | FileCheck --check-prefix=MULTIPLE_INPUT_OBJ %s +# MULTIPLE_INPUT_OBJ: archs expects a single input file + +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00002000 +... diff --git a/llvm/test/tools/llvm-lipo/archs-universal-binary-arm.test b/llvm/test/tools/llvm-lipo/archs-universal-binary-arm.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lipo/archs-universal-binary-arm.test @@ -0,0 +1,40 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-lipo %t -archs | FileCheck %s +# CHECK: armv7k arm64 + +--- !fat-mach-o +FatHeader: + magic: 0xCAFEBABE + nfat_arch: 2 +FatArchs: + - cputype: 0x0000000C + cpusubtype: 0x0000000C + offset: 0x0000000000004000 + size: 28 + align: 14 + - cputype: 0x0100000C + cpusubtype: 0x00000000 + offset: 0x000000000001C000 + size: 32 + align: 14 +Slices: + - !mach-o + FileHeader: + magic: 0xFEEDFACE + cputype: 0x0000000C + cpusubtype: 0x0000000C + filetype: 0x00000002 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00200085 + - !mach-o + FileHeader: + magic: 0xFEEDFACF + cputype: 0x0100000C + cpusubtype: 0x00000000 + filetype: 0x00000002 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00210085 + reserved: 0x00000000 +... diff --git a/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test b/llvm/test/tools/llvm-lipo/archs-universal-binary-unknown.test copy from llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test copy to llvm/test/tools/llvm-lipo/archs-universal-binary-unknown.test --- a/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test +++ b/llvm/test/tools/llvm-lipo/archs-universal-binary-unknown.test @@ -1,29 +1,26 @@ # RUN: yaml2obj %s > %t - -# RUN: llvm-lipo %t -verify_arch i386 -# RUN: llvm-lipo %t -verify_arch i386 x86_64 - -# RUN: not llvm-lipo %t -verify_arch aarch64 -# RUN: not llvm-lipo %t -verify_arch aarch64 i386 +# Tests that the output for an unknown architecture is the same as cctools lipo +# RUN: llvm-lipo %t -archs 2>&1 | FileCheck %s +# CHECK: i386 unknown(16777367,3) --- !fat-mach-o -FatHeader: +FatHeader: magic: 0xCAFEBABE nfat_arch: 2 -FatArchs: +FatArchs: - cputype: 0x00000007 cpusubtype: 0x00000003 offset: 0x0000000000001000 size: 28 align: 12 - - cputype: 0x01000007 + - cputype: 0x01000097 cpusubtype: 0x00000003 offset: 0x0000000000002000 size: 32 align: 12 -Slices: +Slices: - !mach-o - FileHeader: + FileHeader: magic: 0xFEEDFACE cputype: 0x00000007 cpusubtype: 0x00000003 @@ -32,9 +29,9 @@ sizeofcmds: 0 flags: 0x00002000 - !mach-o - FileHeader: + FileHeader: magic: 0xFEEDFACF - cputype: 0x01000007 + cputype: 0x01000097 cpusubtype: 0x00000003 filetype: 0x00000001 ncmds: 0 diff --git a/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test b/llvm/test/tools/llvm-lipo/archs-universal-binary-x86.test copy from llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test copy to llvm/test/tools/llvm-lipo/archs-universal-binary-x86.test --- a/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test +++ b/llvm/test/tools/llvm-lipo/archs-universal-binary-x86.test @@ -1,16 +1,12 @@ # RUN: yaml2obj %s > %t - -# RUN: llvm-lipo %t -verify_arch i386 -# RUN: llvm-lipo %t -verify_arch i386 x86_64 - -# RUN: not llvm-lipo %t -verify_arch aarch64 -# RUN: not llvm-lipo %t -verify_arch aarch64 i386 +# RUN: llvm-lipo %t -archs | FileCheck %s +# CHECK: i386 x86_64 --- !fat-mach-o -FatHeader: +FatHeader: magic: 0xCAFEBABE nfat_arch: 2 -FatArchs: +FatArchs: - cputype: 0x00000007 cpusubtype: 0x00000003 offset: 0x0000000000001000 @@ -21,9 +17,9 @@ offset: 0x0000000000002000 size: 32 align: 12 -Slices: +Slices: - !mach-o - FileHeader: + FileHeader: magic: 0xFEEDFACE cputype: 0x00000007 cpusubtype: 0x00000003 @@ -32,7 +28,7 @@ sizeofcmds: 0 flags: 0x00002000 - !mach-o - FileHeader: + FileHeader: magic: 0xFEEDFACF cputype: 0x01000007 cpusubtype: 0x00000003 diff --git a/llvm/test/tools/llvm-lipo/help-message.test b/llvm/test/tools/llvm-lipo/help-error-messages.test rename from llvm/test/tools/llvm-lipo/help-message.test rename to llvm/test/tools/llvm-lipo/help-error-messages.test --- a/llvm/test/tools/llvm-lipo/help-message.test +++ b/llvm/test/tools/llvm-lipo/help-error-messages.test @@ -8,6 +8,9 @@ # RUN: not llvm-lipo -abcabc 2>&1 | FileCheck --check-prefix=LIPO-UNKNOWN-ARG %s # RUN: not llvm-lipo --abcabc 2>&1 | FileCheck --check-prefix=LIPO-UNKNOWN-ARG %s +# RUN: not llvm-lipo %t -archs -verify_arch i386 2>&1 | FileCheck --check-prefix=MULTIPLE_FLAGS %s +# MULTIPLE_FLAGS: only one of the following actions can be specified: -archs -verify_arch + # LIPO-USAGE: USAGE: llvm-lipo # LIPO-UNKNOWN-ARG: unknown argument '{{-+}}abcabc' # LIPO-VERSION: {{ version }} diff --git a/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test b/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test --- a/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test +++ b/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test @@ -4,13 +4,15 @@ # RUN: llvm-lipo %t -verify_arch i386 x86_64 # RUN: not llvm-lipo %t -verify_arch aarch64 -# RUN: not llvm-lipo %t -verify_arch aarch64 i386 +# RUN: yaml2obj %s | not llvm-lipo - -verify_arch aarch64 i386 +# lipo does not support this (i.e. yaml2obj %s | not lipo -), included to test function with llvm-lipo +# use the temporary %t when checking tests with lipo --- !fat-mach-o -FatHeader: +FatHeader: magic: 0xCAFEBABE nfat_arch: 2 -FatArchs: +FatArchs: - cputype: 0x00000007 cpusubtype: 0x00000003 offset: 0x0000000000001000 @@ -21,9 +23,9 @@ offset: 0x0000000000002000 size: 32 align: 12 -Slices: +Slices: - !mach-o - FileHeader: + FileHeader: magic: 0xFEEDFACE cputype: 0x00000007 cpusubtype: 0x00000003 @@ -32,7 +34,7 @@ sizeofcmds: 0 flags: 0x00002000 - !mach-o - FileHeader: + FileHeader: magic: 0xFEEDFACF cputype: 0x01000007 cpusubtype: 0x00000003 diff --git a/llvm/tools/llvm-lipo/LipoOpts.td b/llvm/tools/llvm-lipo/LipoOpts.td --- a/llvm/tools/llvm-lipo/LipoOpts.td +++ b/llvm/tools/llvm-lipo/LipoOpts.td @@ -6,5 +6,14 @@ def version : Flag<["-", "--"], "version">, HelpText<"Print the version and exit.">; -def verify_arch : Option<["-", "--"], "verify_arch", KIND_REMAINING_ARGS>, - HelpText<"Verify that the specified arch_types are present in the input file">; +def action_group : OptionGroup<"action group">; + +def verify_arch + : Option<["-", "--"], "verify_arch", KIND_REMAINING_ARGS>, + Group, + HelpText< + "Verify that the specified arch_types are present in the input file">; + +def archs : Option<["-", "--"], "archs", KIND_FLAG>, + Group, + HelpText<"Display the arch_types present in the input file">; diff --git a/llvm/tools/llvm-lipo/llvm-lipo.cpp b/llvm/tools/llvm-lipo/llvm-lipo.cpp --- a/llvm/tools/llvm-lipo/llvm-lipo.cpp +++ b/llvm/tools/llvm-lipo/llvm-lipo.cpp @@ -53,6 +53,8 @@ #undef OPTION }; +// LipoInfoTable below references LIPO_##PREFIX. OptionGroup has prefix nullptr. +const char *const *LIPO_nullptr = nullptr; #define PREFIX(NAME, VALUE) const char *const LIPO_##NAME[] = VALUE; #include "LipoOpts.inc" #undef PREFIX @@ -73,9 +75,15 @@ LipoOptTable() : OptTable(LipoInfoTable) {} }; +enum class LipoAction { + PrintArchs, + VerifyArch, +}; + struct Config { SmallVector InputFiles; SmallVector VerifyArchList; + LipoAction ActionToPerform; }; } // end namespace @@ -113,7 +121,20 @@ if (C.InputFiles.empty()) reportError("at least one input file should be specified"); - if (InputArgs.hasArg(LIPO_verify_arch)) { + SmallVector ActionArgs(InputArgs.filtered(LIPO_action_group)); + if (ActionArgs.empty()) + reportError("at least one action should be specified"); + if (ActionArgs.size() > 1) { + std::string Buf; + raw_string_ostream OS(Buf); + OS << "only one of the following actions can be specified:"; + for (auto Arg : ActionArgs) + OS << " " << Arg->getSpelling(); + reportError(OS.str()); + } + + switch (ActionArgs[0]->getOption().getID()) { + case LIPO_verify_arch: for (auto A : InputArgs.getAllArgValues(LIPO_verify_arch)) C.VerifyArchList.push_back(A); if (C.VerifyArchList.empty()) @@ -121,8 +142,18 @@ "verify_arch requires at least one architecture to be specified"); if (C.InputFiles.size() > 1) reportError("verify_arch expects a single input file"); + C.ActionToPerform = LipoAction::VerifyArch; + return C; + + case LIPO_archs: + if (C.InputFiles.size() > 1) + reportError("archs expects a single input file"); + C.ActionToPerform = LipoAction::PrintArchs; + return C; + + default: + reportError("llvm-lipo action unspecified"); } - return C; } static SmallVector, 1> @@ -144,8 +175,6 @@ LLVM_ATTRIBUTE_NORETURN static void verifyArch(ArrayRef> InputBinaries, ArrayRef VerifyArchList) { - assert(!InputBinaries.empty() && - "The list of input binaries should be non-empty"); assert(!VerifyArchList.empty() && "The list of architectures should be non-empty"); assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); @@ -174,12 +203,54 @@ exit(EXIT_SUCCESS); } +static void printArchOrUnknown(const MachOObjectFile *ObjectFile) { + // Prints trailing space and unknown in this format for compatibility with + // cctools lipo. + const std::string ObjectArch = ObjectFile->getArchTriple().getArchName(); + if (ObjectArch.empty()) { + outs() << "unknown(" << ObjectFile->getHeader().cputype << "," + << ObjectFile->getHeader().cpusubtype << ") "; + } else + outs() << ObjectArch + " "; +} + +LLVM_ATTRIBUTE_NORETURN +static void printArchs(ArrayRef> InputBinaries) { + assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); + const Binary *InputBinary = InputBinaries.front().getBinary(); + if (auto UO = dyn_cast(InputBinary)) { + for (MachOUniversalBinary::object_iterator I = UO->begin_objects(), + E = UO->end_objects(); + I != E; ++I) { + Expected> BinaryOrError = + I->getAsObjectFile(); + if (!BinaryOrError) + reportError(InputBinary->getFileName(), BinaryOrError.takeError()); + printArchOrUnknown(BinaryOrError.get().get()); + } + } else if (auto O = dyn_cast(InputBinary)) { + printArchOrUnknown(O); + } else { + llvm_unreachable("Unexpected binary format"); + } + + outs() << "\n"; + exit(EXIT_SUCCESS); +} + int main(int argc, char **argv) { InitLLVM X(argc, argv); Config C = parseLipoOptions(makeArrayRef(argv + 1, argc)); SmallVector, 1> InputBinaries = readInputBinaries(C.InputFiles); - if (!C.VerifyArchList.empty()) + + switch (C.ActionToPerform) { + case LipoAction::VerifyArch: verifyArch(InputBinaries, C.VerifyArchList); + break; + case LipoAction::PrintArchs: + printArchs(InputBinaries); + break; + } return EXIT_SUCCESS; }