diff --git a/llvm/test/tools/llvm-ifs/output-target-error.test b/llvm/test/tools/llvm-ifs/output-target-error.test --- a/llvm/test/tools/llvm-ifs/output-target-error.test +++ b/llvm/test/tools/llvm-ifs/output-target-error.test @@ -10,6 +10,6 @@ Symbols: [] ... -# MISSING: {{llvm-ifs(\.exe)?}}: for the --output-format option: must be specified at least once! +# MISSING: error: at least one output should be specified. # INVALID: {{llvm-ifs(\.exe)?}}: for the --output-format option: Cannot find option named 'nope'! diff --git a/llvm/test/tools/llvm-ifs/write-stub.test b/llvm/test/tools/llvm-ifs/write-stub.test --- a/llvm/test/tools/llvm-ifs/write-stub.test +++ b/llvm/test/tools/llvm-ifs/write-stub.test @@ -1,35 +1,40 @@ ## Test writing stub elf with minimal sections. -# RUN: llvm-ifs --output-format=ELF --output=%t.elf32l --arch=x86_64 --bitwidth=32 --endianness=little %s +# RUN: llvm-ifs --output-elf=%t.elf32l --arch=x86_64 --bitwidth=32 --endianness=little %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf32l | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="LittleEndian (0x1)" -DHS=52 -DPHES=32 -DSHES=40 -DDYNSYMAL=4 -DDYNSYMES=16 -DDYNAMICAL=4 -DDYNAMICES=8 -DDYNTABZ=0 -# RUN: llvm-ifs --output-format=ELF --output=%t.elf32b --arch=x86_64 --bitwidth=32 --endianness=big %s +# RUN: llvm-ifs --output-elf=%t.elf32b --arch=x86_64 --bitwidth=32 --endianness=big %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf32b | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="BigEndian (0x2)" -DHS=52 -DPHES=32 -DSHES=40 -DDYNSYMAL=4 -DDYNSYMES=16 -DDYNAMICAL=4 -DDYNAMICES=8 -DDYNTABZ=0 -# RUN: llvm-ifs --output-format=ELF --output=%t.elf64l --arch=x86_64 --bitwidth=64 --endianness=little %s +# RUN: llvm-ifs --output-elf=%t.elf64l --arch=x86_64 --bitwidth=64 --endianness=little %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64l | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 -# RUN: llvm-ifs --output-format=ELF --output=%t.elf64l --target=x86_64-linux-gnu %s +# RUN: llvm-ifs --output-elf=%t.elf64l --target=x86_64-linux-gnu %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64l | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 -# RUN: llvm-ifs --output-format=ELF --output=%t.elf64b --arch=x86_64 --bitwidth=64 --endianness=big %s +# RUN: llvm-ifs --output-elf=%t.elf64b --arch=x86_64 --bitwidth=64 --endianness=big %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64b | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="BigEndian (0x2)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 -# RUN: not llvm-ifs --output-format=ELF --output=%t --arch=x86_64 --bitwidth=64 --endianness=big --target=x86_64-linux-gnu %s 2>&1 | FileCheck %s --check-prefix=TRIPLEERR +# RUN: not llvm-ifs --output-elf=%t --arch=x86_64 --bitwidth=64 --endianness=big --target=x86_64-linux-gnu %s 2>&1 | FileCheck %s --check-prefix=TRIPLEERR -# RUN: not llvm-ifs --output-format=ELF --output=%t --bitwidth=64 --endianness=big %s 2>&1 | FileCheck %s -DMSG="Arch" --check-prefix=TARGETERR +# RUN: not llvm-ifs --output-elf=%t --bitwidth=64 --endianness=big %s 2>&1 | FileCheck %s -DMSG="Arch" --check-prefix=TARGETERR -# RUN: not llvm-ifs --output-format=ELF --output=%t --arch=x86_64 --endianness=big %s 2>&1 | FileCheck %s -DMSG="BitWidth" --check-prefix=TARGETERR +# RUN: not llvm-ifs --output-elf=%t --arch=x86_64 --endianness=big %s 2>&1 | FileCheck %s -DMSG="BitWidth" --check-prefix=TARGETERR -# RUN: not llvm-ifs --output-format=ELF --output=%t --arch=x86_64 --bitwidth=64 %s 2>&1 | FileCheck %s -DMSG="Endianness" --check-prefix=TARGETERR +# RUN: not llvm-ifs --output-elf=%t --arch=x86_64 --bitwidth=64 %s 2>&1 | FileCheck %s -DMSG="Endianness" --check-prefix=TARGETERR -# RUN: llvm-ifs --output-format=IFS --output=%t.target --target=x86_64-linux-gnu %s -# RUN: not llvm-ifs --output-format=ELF --output=%t --target=aarch64-linux-gnu %t.target 2>&1 | FileCheck %s -DMSG="Triple" --check-prefix=CONFLICTERR +# RUN: llvm-ifs --output-ifs=%t.target --target=x86_64-linux-gnu %s +# RUN: not llvm-ifs --output-elf=%t --target=aarch64-linux-gnu %t.target 2>&1 | FileCheck %s -DMSG="Triple" --check-prefix=CONFLICTERR -# RUN: llvm-ifs --output-format=IFS --output=%t.target --arch=x86_64 --endianness=little --bitwidth=64 %s -# RUN: not llvm-ifs --output-format=ELF --output=%t --arch=AArch64 %t.target 2>&1 | FileCheck %s -DMSG=Arch --check-prefix=CONFLICTERR -# RUN: not llvm-ifs --output-format=ELF --output=%t --endianness=big %t.target 2>&1 | FileCheck %s -DMSG=Endianness --check-prefix=CONFLICTERR -# RUN: not llvm-ifs --output-format=ELF --output=%t --bitwidth=32 %t.target 2>&1 | FileCheck %s -DMSG=BitWidth --check-prefix=CONFLICTERR +# RUN: llvm-ifs --output-ifs=%t.target --arch=x86_64 --endianness=little --bitwidth=64 %s +# RUN: not llvm-ifs --output-elf=%t --arch=AArch64 %t.target 2>&1 | FileCheck %s -DMSG=Arch --check-prefix=CONFLICTERR +# RUN: not llvm-ifs --output-elf=%t --endianness=big %t.target 2>&1 | FileCheck %s -DMSG=Endianness --check-prefix=CONFLICTERR +# RUN: not llvm-ifs --output-elf=%t --bitwidth=32 %t.target 2>&1 | FileCheck %s -DMSG=BitWidth --check-prefix=CONFLICTERR + +# RUN: llvm-ifs --output-ifs=%t.ifs --output-elf=%t.elf --target=x86_64-linux-gnu %s +# RUN: llvm-ifs --output-elf=%t.elf2 --target=x86_64-linux-gnu %t.ifs +# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 +# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf2 | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 --- !ifs-v1 IfsVersion: 3.0 diff --git a/llvm/tools/llvm-ifs/llvm-ifs.cpp b/llvm/tools/llvm-ifs/llvm-ifs.cpp --- a/llvm/tools/llvm-ifs/llvm-ifs.cpp +++ b/llvm/tools/llvm-ifs/llvm-ifs.cpp @@ -57,11 +57,11 @@ clEnumValN(FileFormat::ELF, "ELF", "ELF object file")), cl::cat(IfsCategory)); cl::opt OutputFormat( - "output-format", cl::desc("Specify the output file format"), + "output-format", cl::desc("Specify the output file format **DEPRECATED**"), cl::values(clEnumValN(FileFormat::IFS, "IFS", "Text based ELF stub file"), clEnumValN(FileFormat::ELF, "ELF", "ELF stub file"), clEnumValN(FileFormat::TBD, "TBD", "Apple TBD text stub file")), - cl::Required, cl::cat(IfsCategory)); + cl::cat(IfsCategory)); cl::opt OptArch("arch", cl::desc("Specify the architecture, e.g. x86_64"), cl::cat(IfsCategory)); @@ -108,10 +108,21 @@ SoName("soname", cl::desc("Manually set the DT_SONAME entry of any emitted files"), cl::value_desc("name"), cl::cat(IfsCategory)); -cl::opt OutputFilePath("output", cl::desc("Output file"), +cl::opt OutputFilePath("output", + cl::desc("Output file **DEPRECATED**"), cl::cat(IfsCategory)); cl::alias OutputFilePathA("o", cl::desc("Alias for --output"), cl::aliasopt(OutputFilePath), cl::cat(IfsCategory)); +cl::opt OutputELFFilePath("output-elf", + cl::desc("Output path for ELF file"), + cl::cat(IfsCategory)); +cl::opt OutputIFSFilePath("output-ifs", + cl::desc("Output path for IFS file"), + cl::cat(IfsCategory)); +cl::opt OutputTBDFilePath("output-tbd", + cl::desc("Output path for TBD file"), + cl::cat(IfsCategory)); + cl::opt WriteIfChanged( "write-if-changed", cl::desc("Write the output file only if it is new or has changed."), @@ -320,8 +331,6 @@ WithColor::error() << "Interface Stub: Target Mismatch." << "\nFilenames: " << PreviousInputFilePath << " " << InputFilePath; - // << "\nTriple Values: " << Stub.Triple << " " - // << TargetStub->Triple << "\n"; return -1; } if (Stub.SoName != TargetStub->SoName) { @@ -408,63 +417,131 @@ if (OverrideError) fatalError(std::move(OverrideError)); - switch (OutputFormat.getValue()) { - case FileFormat::TBD: { - std::error_code SysErr; - raw_fd_ostream Out(OutputFilePath, SysErr); - if (SysErr) { - WithColor::error() << "Couldn't open " << OutputFilePath - << " for writing.\n"; - return -1; + if (OutputFormat.getNumOccurrences() == 0 && + OutputELFFilePath.getNumOccurrences() == 0 && + OutputIFSFilePath.getNumOccurrences() == 0 && + OutputTBDFilePath.getNumOccurrences() == 0) { + WithColor::error() << "at least one output should be specified."; + return -1; + } + if (OutputFormat.getNumOccurrences() == 1) { + // TODO: Remove OutputFormat flag in the next revision. + WithColor::warning() << "--output-format option is deprecated, please use " + "--output-{FILE_FORMAT} options instead\n"; + switch (OutputFormat.getValue()) { + case FileFormat::TBD: { + std::error_code SysErr; + raw_fd_ostream Out(OutputFilePath, SysErr); + if (SysErr) { + WithColor::error() << "Couldn't open " << OutputFilePath + << " for writing.\n"; + return -1; + } + if (!Stub.Target.Triple) { + WithColor::error() + << "Triple should be defined when output format is TBD"; + return -1; + } + return writeTbdStub(llvm::Triple(Stub.Target.Triple.getValue()), + Stub.Symbols, "TBD", Out); } - if (!Stub.Target.Triple) { - WithColor::error() - << "Triple should be defined when output format is TBD"; - return -1; + case FileFormat::IFS: { + Stub.IfsVersion = IfsVersionCurrent; + if (InputFormat.getValue() == FileFormat::ELF && + OptTargetTripleHint.getNumOccurrences() == 1) { + std::error_code HintEC(1, std::generic_category()); + IFSTarget HintTarget = parseTriple(OptTargetTripleHint); + if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue()) + fatalError(make_error( + "Triple hint does not match the actual architecture", HintEC)); + if (Stub.Target.Endianness.getValue() != + HintTarget.Endianness.getValue()) + fatalError(make_error( + "Triple hint does not match the actual endianness", HintEC)); + if (Stub.Target.BitWidth.getValue() != HintTarget.BitWidth.getValue()) + fatalError(make_error( + "Triple hint does not match the actual bit width", HintEC)); + + stripIFSTarget(Stub, true, false, false, false); + Stub.Target.Triple = OptTargetTripleHint.getValue(); + } else { + stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, + StripIFSEndiannessWidth, StripIFSBitWidth); + } + if (StripUndefined) + stripIFSUndefinedSymbols(Stub); + Error IFSWriteError = writeIFS(OutputFilePath.getValue(), Stub); + if (IFSWriteError) + fatalError(std::move(IFSWriteError)); + break; } - return writeTbdStub(llvm::Triple(Stub.Target.Triple.getValue()), - Stub.Symbols, "TBD", Out); - } - case FileFormat::IFS: { - Stub.IfsVersion = IfsVersionCurrent; - if (InputFormat.getValue() == FileFormat::ELF && - OptTargetTripleHint.getNumOccurrences() == 1) { - std::error_code HintEC(1, std::generic_category()); - IFSTarget HintTarget = parseTriple(OptTargetTripleHint); - if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue()) - fatalError(make_error( - "Triple hint does not match the actual architecture", HintEC)); - if (Stub.Target.Endianness.getValue() != - HintTarget.Endianness.getValue()) - fatalError(make_error( - "Triple hint does not match the actual endianness", HintEC)); - if (Stub.Target.BitWidth.getValue() != HintTarget.BitWidth.getValue()) - fatalError(make_error( - "Triple hint does not match the actual bit width", HintEC)); - - stripIFSTarget(Stub, true, false, false, false); - Stub.Target.Triple = OptTargetTripleHint.getValue(); - } else { - stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, - StripIFSEndiannessWidth, StripIFSBitWidth); + case FileFormat::ELF: { + Error TargetError = validateIFSTarget(Stub, true); + if (TargetError) + fatalError(std::move(TargetError)); + Error BinaryWriteError = + writeBinaryStub(OutputFilePath, Stub, WriteIfChanged); + if (BinaryWriteError) + fatalError(std::move(BinaryWriteError)); + break; + } + } + } else { + // Check if output path for individual format. + if (OutputELFFilePath.getNumOccurrences() == 1) { + Error TargetError = validateIFSTarget(Stub, true); + if (TargetError) + fatalError(std::move(TargetError)); + Error BinaryWriteError = + writeBinaryStub(OutputELFFilePath, Stub, WriteIfChanged); + if (BinaryWriteError) + fatalError(std::move(BinaryWriteError)); + } + if (OutputIFSFilePath.getNumOccurrences() == 1) { + Stub.IfsVersion = IfsVersionCurrent; + if (InputFormat.getValue() == FileFormat::ELF && + OptTargetTripleHint.getNumOccurrences() == 1) { + std::error_code HintEC(1, std::generic_category()); + IFSTarget HintTarget = parseTriple(OptTargetTripleHint); + if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue()) + fatalError(make_error( + "Triple hint does not match the actual architecture", HintEC)); + if (Stub.Target.Endianness.getValue() != + HintTarget.Endianness.getValue()) + fatalError(make_error( + "Triple hint does not match the actual endianness", HintEC)); + if (Stub.Target.BitWidth.getValue() != HintTarget.BitWidth.getValue()) + fatalError(make_error( + "Triple hint does not match the actual bit width", HintEC)); + + stripIFSTarget(Stub, true, false, false, false); + Stub.Target.Triple = OptTargetTripleHint.getValue(); + } else { + stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, + StripIFSEndiannessWidth, StripIFSBitWidth); + } + if (StripUndefined) + stripIFSUndefinedSymbols(Stub); + Error IFSWriteError = writeIFS(OutputIFSFilePath.getValue(), Stub); + if (IFSWriteError) + fatalError(std::move(IFSWriteError)); + } + if (OutputTBDFilePath.getNumOccurrences() == 1) { + std::error_code SysErr; + raw_fd_ostream Out(OutputTBDFilePath, SysErr); + if (SysErr) { + WithColor::error() << "Couldn't open " << OutputTBDFilePath + << " for writing.\n"; + return -1; + } + if (!Stub.Target.Triple) { + WithColor::error() + << "Triple should be defined when output format is TBD"; + return -1; + } + return writeTbdStub(llvm::Triple(Stub.Target.Triple.getValue()), + Stub.Symbols, "TBD", Out); } - if (StripUndefined) - stripIFSUndefinedSymbols(Stub); - Error IFSWriteError = writeIFS(OutputFilePath.getValue(), Stub); - if (IFSWriteError) - fatalError(std::move(IFSWriteError)); - break; - } - case FileFormat::ELF: { - Error TargetError = validateIFSTarget(Stub, true); - if (TargetError) - fatalError(std::move(TargetError)); - Error BinaryWriteError = - writeBinaryStub(OutputFilePath, Stub, WriteIfChanged); - if (BinaryWriteError) - fatalError(std::move(BinaryWriteError)); - break; - } } return 0; }