Index: test/tools/llvm-lipo/verify-arch-macho-binary.test =================================================================== --- test/tools/llvm-lipo/verify-arch-macho-binary.test +++ test/tools/llvm-lipo/verify-arch-macho-binary.test @@ -0,0 +1,104 @@ +# RUN: yaml2obj %s > %t + +# RUN: llvm-lipo %t -verify_arch i386 +# RUN: llvm-lipo %t --verify_arch i386 +# RUN: llvm-lipo %t --verify_arch=i386 + +# NO_AARCH64: does not contain aarch64 +# RUN: not llvm-lipo %t -verify_arch aarch64 2>&1 | FileCheck --check-prefix=NO_AARCH64 %s +# RUN: not llvm-lipo %t -verify_arch aarch64 -verify_arch i386 2>&1 | FileCheck --check-prefix=NO_AARCH64 %s + +# INVALID_ARCH: Invalid architecture: aarch101 +# RUN: not llvm-lipo %t -verify_arch aarch101 2>&1 | FileCheck --check-prefix=INVALID_ARCH %s + +# INVALID_OBJ: The file was not recognized as a valid object file +# RUN: touch %t.empty +# RUN: not llvm-lipo %t.empty -verify_arch aarch101 2>&1 | FileCheck --check-prefix=INVALID_OBJ %s + +# MULTIPLE_INPUT_OBJ: verify_arch expects a single input file +# RUN: not llvm-lipo %t %t -verify_arch i386 2>&1 | FileCheck --check-prefix=MULTIPLE_INPUT_OBJ %s + +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 3 + sizeofcmds: 296 + flags: 0x00002000 +LoadCommands: + - cmd: LC_SEGMENT + cmdsize: 192 + segname: '' + vmaddr: 0 + vmsize: 84 + fileoff: 324 + filesize: 84 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 31 + offset: 0x00000144 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __eh_frame + segname: __TEXT + addr: 0x0000000000000020 + size: 52 + offset: 0x00000164 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 408 + nsyms: 1 + stroff: 420 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - '' +... Index: test/tools/llvm-lipo/verify-arch-universal-binary.test =================================================================== --- test/tools/llvm-lipo/verify-arch-universal-binary.test +++ test/tools/llvm-lipo/verify-arch-universal-binary.test @@ -0,0 +1,193 @@ +# RUN: yaml2obj %s > %t + +# RUN: llvm-lipo %t -verify_arch i386 +# RUN: llvm-lipo %t -verify_arch i386 -verify_arch x86_64 + +# NO_AARCH64: does not contain aarch64 +# RUN: not llvm-lipo %t -verify_arch aarch64 2>&1 | FileCheck --check-prefix=NO_AARCH64 %s +# RUN: not llvm-lipo %t -verify_arch aarch64 -verify_arch i386 2>&1 | FileCheck --check-prefix=NO_AARCH64 %s + +--- !fat-mach-o +FatHeader: + magic: 0xCAFEBABE + nfat_arch: 2 +FatArchs: + - cputype: 0x00000007 + cpusubtype: 0x00000003 + offset: 0x0000000000001000 + size: 428 + align: 12 + - cputype: 0x01000007 + cpusubtype: 0x00000003 + offset: 0x0000000000002000 + size: 488 + align: 12 +Slices: + - !mach-o + FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 3 + sizeofcmds: 296 + flags: 0x00002000 + LoadCommands: + - cmd: LC_SEGMENT + cmdsize: 192 + segname: '' + vmaddr: 0 + vmsize: 84 + fileoff: 324 + filesize: 84 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 31 + offset: 0x00000144 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __eh_frame + segname: __TEXT + addr: 0x0000000000000020 + size: 52 + offset: 0x00000164 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 408 + nsyms: 1 + stroff: 420 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 + LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - '' + - !mach-o + FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 3 + sizeofcmds: 336 + flags: 0x00002000 + reserved: 0x00000000 + LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 96 + fileoff: 368 + filesize: 96 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 26 + offset: 0x00000170 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __eh_frame + segname: __TEXT + addr: 0x0000000000000020 + size: 64 + offset: 0x00000190 + align: 3 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 464 + nsyms: 1 + stroff: 480 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 + LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - '' +... Index: tools/llvm-lipo/CMakeLists.txt =================================================================== --- tools/llvm-lipo/CMakeLists.txt +++ tools/llvm-lipo/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Object + Support +) + +add_llvm_tool(llvm-lipo + llvm-lipo.cpp +) Index: tools/llvm-lipo/LLVMBuild.txt =================================================================== --- tools/llvm-lipo/LLVMBuild.txt +++ tools/llvm-lipo/LLVMBuild.txt @@ -0,0 +1,20 @@ +;===- ./tools/llvm-lipo/LLVMBuild.txt --------------------------*- Conf -*--===; +; +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; +[component_0] +type = Tool +name = llvm-lipo +parent = Tools +required_libraries = Object Option Support Index: tools/llvm-lipo/llvm-lipo.cpp =================================================================== --- tools/llvm-lipo/llvm-lipo.cpp +++ tools/llvm-lipo/llvm-lipo.cpp @@ -0,0 +1,114 @@ +//===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A utility for creating / splitting / inspecting universal binaries. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Triple.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/WithColor.h" + +using namespace llvm; +using namespace llvm::object; + +cl::OptionCategory LipoCategory("Specific Options"); + +static cl::list InputFiles(cl::Positional, cl::OneOrMore, + cl::desc(""), + cl::cat(LipoCategory)); + +static cl::list VerifyArch( + "verify_arch", cl::ZeroOrMore, + cl::desc( + "Verify the specified architectures are present in the input files"), + cl::value_desc("architecture"), cl::cat(LipoCategory)); + +static const StringRef ToolName = "llvm-lipo"; + +LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) { + WithColor::error(errs(), ToolName) << Message << "\n"; + errs().flush(); + exit(EXIT_FAILURE); +} + +LLVM_ATTRIBUTE_NORETURN static void reportError(StringRef File, Error E) { + assert(E); + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS); + OS.flush(); + WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf; + exit(EXIT_FAILURE); +} + +static SmallVector, 1> readInputBinaries() { + SmallVector, 1> InputBinaries; + for (StringRef InputFile : InputFiles) { + Expected> BinaryOrErr = + createBinary(InputFile); + if (!BinaryOrErr) + reportError(InputFile, BinaryOrErr.takeError()); + if (!isa(BinaryOrErr->getBinary()) && + !isa(BinaryOrErr->getBinary())) + reportError(Twine("File ") + InputFile + + " has unsupported binary format"); + InputBinaries.push_back(std::move(*BinaryOrErr)); + } + return InputBinaries; +} + +LLVM_ATTRIBUTE_NORETURN +static void +verifyArch(const SmallVector, 1> &InputBinaries) { + assert(!InputBinaries.empty() && + "The list of input binaries should be non-empty"); + if (InputBinaries.size() > 1) + reportError("verify_arch expects a single input file"); + + for (StringRef Arch : VerifyArch) + if (Triple::ArchType::UnknownArch == Triple(Arch).getArch()) + reportError(Twine("Invalid architecture: ") + Arch); + + if (auto UO = + dyn_cast(InputBinaries.front().getBinary())) { + for (StringRef Arch : VerifyArch) { + Expected> Obj = + UO->getObjectForArch(Arch); + if (!Obj) + reportError(UO->getFileName(), Obj.takeError()); + } + } else if (auto O = + dyn_cast(InputBinaries.front().getBinary())) { + for (StringRef Arch : VerifyArch) + if (O->getArch() != Triple(Arch).getArch()) + reportError(Twine(O->getFileName()) + " does not contain " + Arch); + } else { + llvm_unreachable("Unexpected binary format"); + } + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + cl::ParseCommandLineOptions( + argc, argv, + "A tool for creating/splitting/inspecting universal binaries\n"); + + SmallVector, 1> InputBinaries = readInputBinaries(); + if (!VerifyArch.empty()) + verifyArch(InputBinaries); + + return EXIT_SUCCESS; +}