Index: llvm/trunk/test/tools/llvm-lipo/info-invalid.test =================================================================== --- llvm/trunk/test/tools/llvm-lipo/info-invalid.test +++ llvm/trunk/test/tools/llvm-lipo/info-invalid.test @@ -0,0 +1,37 @@ +# RUN: yaml2obj %s > %t +# RUN: not llvm-lipo %t -info 2>&1 | FileCheck %s +# CHECK: has unsupported binary format + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 + Entry: 0x0000000000001000 +Sections: + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000230 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Info: 0x0000000000000003 + Entries: + - Version: 1 + Flags: 1 + VersionNdx: 1 + Hash: 123456789 + Names: + - foo + - Version: 1 + Flags: 2 + VersionNdx: 2 + Hash: 987654321 + Names: + - VERSION_1 + - VERSION_2 +DynamicSymbols: + - Name: bar + Binding: STB_GLOBAL +... Index: llvm/trunk/test/tools/llvm-lipo/info.test =================================================================== --- llvm/trunk/test/tools/llvm-lipo/info.test +++ llvm/trunk/test/tools/llvm-lipo/info.test @@ -0,0 +1,13 @@ +# RUN: yaml2obj %p/Inputs/i386-slice.yaml > %t-i386.o +# RUN: yaml2obj %p/Inputs/x86_64-slice.yaml > %t-x86_64.o +# RUN: yaml2obj %p/Inputs/i386-x86_64-universal.yaml > %t-universal.o + +# RUN: llvm-lipo %t-universal.o %t-i386.o %t-universal.o %t-x86_64.o -info | FileCheck %s +# CHECK: Architectures in the fat file: +# CHECK: i386 x86_64 +# CHECK-NEXT: Architectures in the fat file: +# CHECK: i386 x86_64 +# CHECK-NEXT: Non-fat file: +# CHECK: is architecture: i386 +# CHECK-NEXT: Non-fat file: +# CHECK: is architecture: x86_64 Index: llvm/trunk/tools/llvm-lipo/LipoOpts.td =================================================================== --- llvm/trunk/tools/llvm-lipo/LipoOpts.td +++ llvm/trunk/tools/llvm-lipo/LipoOpts.td @@ -18,6 +18,12 @@ Group, HelpText<"Display the arch_types present in the input file">; +def info : Option<["-", "--"], "info", KIND_FLAG>, + Group, + HelpText<"Display descriptions of each input file including " + "filename and arch_types. Groups universal binaries " + "together followed by thin files">; + def thin : Option<["-", "--"], "thin", KIND_SEPARATE>, Group, HelpText<"Create a thin output file of specified arch_type from the " Index: llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp =================================================================== --- llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp +++ llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp @@ -78,6 +78,7 @@ enum class LipoAction { PrintArchs, + PrintInfo, VerifyArch, ThinArch, CreateUniversal, @@ -184,6 +185,10 @@ C.ActionToPerform = LipoAction::PrintArchs; return C; + case LIPO_info: + C.ActionToPerform = LipoAction::PrintInfo; + return C; + case LIPO_thin: if (C.InputFiles.size() > 1) reportError("thin expects a single input file"); @@ -269,26 +274,49 @@ .str(); } -LLVM_ATTRIBUTE_NORETURN -static void printArchs(ArrayRef> InputBinaries) { +static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) { // Prints trailing space for compatibility with cctools lipo. - assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); - const Binary *InputBinary = InputBinaries.front().getBinary(); - if (auto UO = dyn_cast(InputBinary)) { + if (auto UO = dyn_cast(Binary)) { for (const auto &O : UO->objects()) { Expected> BinaryOrError = O.getAsObjectFile(); if (!BinaryOrError) - reportError(InputBinary->getFileName(), BinaryOrError.takeError()); - outs() << getArchString(*BinaryOrError.get().get()) << " "; + reportError(Binary->getFileName(), BinaryOrError.takeError()); + OS << getArchString(*BinaryOrError.get().get()) << " "; } - } else if (auto O = dyn_cast(InputBinary)) { - outs() << getArchString(*O) << " "; - } else { - llvm_unreachable("Unexpected binary format"); + OS << "\n"; + return; } + OS << getArchString(*cast(Binary)) << " \n"; +} + +LLVM_ATTRIBUTE_NORETURN +static void printArchs(ArrayRef> InputBinaries) { + assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); + printBinaryArchs(InputBinaries.front().getBinary(), outs()); + exit(EXIT_SUCCESS); +} - outs() << "\n"; +LLVM_ATTRIBUTE_NORETURN +static void printInfo(ArrayRef> InputBinaries) { + // Group universal and thin files together for compatibility with cctools lipo + for (auto &IB : InputBinaries) { + const Binary *Binary = IB.getBinary(); + if (Binary->isMachOUniversalBinary()) { + outs() << "Architectures in the fat file: " << Binary->getFileName() + << " are: "; + printBinaryArchs(Binary, outs()); + } + } + for (auto &IB : InputBinaries) { + const Binary *Binary = IB.getBinary(); + if (!Binary->isMachOUniversalBinary()) { + assert(Binary->isMachO() && "expected MachO binary"); + outs() << "Non-fat file: " << Binary->getFileName() + << " is architecture: "; + printBinaryArchs(Binary, outs()); + } + } exit(EXIT_SUCCESS); } @@ -470,8 +498,8 @@ OutFile->getBufferStart() + FatArchList[Index].offset); } - // FatArchs written after Slices in order reduce the number of swaps for the - // LittleEndian case + // FatArchs written after Slices in order to reduce the number of swaps for + // the LittleEndian case if (sys::IsLittleEndianHost) for (MachO::fat_arch &FA : FatArchList) MachO::swapStruct(FA); @@ -510,6 +538,9 @@ case LipoAction::PrintArchs: printArchs(InputBinaries); break; + case LipoAction::PrintInfo: + printInfo(InputBinaries); + break; case LipoAction::ThinArch: extractSlice(InputBinaries, C.ThinArchType, C.OutputFile); break;