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/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.test copy from llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test copy to llvm/test/tools/llvm-lipo/archs-universal-binary.test --- a/llvm/test/tools/llvm-lipo/verify-arch-universal-binary.test +++ b/llvm/test/tools/llvm-lipo/archs-universal-binary.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 2>&1 | 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/command-line.test rename from llvm/test/tools/llvm-lipo/help-message.test rename to llvm/test/tools/llvm-lipo/command-line.test --- a/llvm/test/tools/llvm-lipo/help-message.test +++ b/llvm/test/tools/llvm-lipo/command-line.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,48 @@ exit(EXIT_SUCCESS); } +static void printArchFromCPUType(uint32_t CPUType, uint32_t CPUSubType) { + // Prints trailing space and unknown in this format for compatibility with + // cctools lipo. + Triple::ArchType Arch = MachOObjectFile::getArch(CPUType); + if (Arch == Triple::ArchType::UnknownArch) + outs() << "unknown(" << CPUType << "," + << (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) << ") "; + else + outs() << Triple::getArchTypeName(Arch).str() << " "; +} + +LLVM_ATTRIBUTE_NORETURN +static void printArchs(ArrayRef> InputBinaries) { + assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); + + if (auto UO = + dyn_cast(InputBinaries.front().getBinary())) + for (const MachOUniversalBinary::ObjectForArch &Obj : UO->objects()) + printArchFromCPUType(Obj.getCPUType(), Obj.getCPUSubType()); + else if (auto O = + dyn_cast(InputBinaries.front().getBinary())) + printArchFromCPUType(O->getHeader().cputype, O->getHeader().cpusubtype); + 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; }