[ifs] Switch to using OptTable

Differential revision: https://reviews.llvm.org/D125658
This commit is contained in:
Alex Brachet 2022-05-20 15:28:18 +00:00
parent aed49eac87
commit 480dcdc897
4 changed files with 267 additions and 158 deletions

View File

@ -1,6 +1,5 @@
# RUN: llvm-ifs --help | FileCheck %s --check-prefix HELP --implicit-check-not='{{[Oo]}}ptions:' # RUN: llvm-ifs --help | FileCheck %s --check-prefix HELP --implicit-check-not='{{[Oo]}}ptions:'
# HELP: USAGE # HELP: OVERVIEW:
# HELP: Color Options # HELP: USAGE:
# HELP: Generic Options # HELP: OPTIONS:
# HELP: Ifs Options

View File

@ -5,9 +5,17 @@ set(LLVM_LINK_COMPONENTS
Support Support
TextAPI TextAPI
ObjectYAML ObjectYAML
Option
) )
set(LLVM_TARGET_DEFINITIONS Opts.td)
tablegen(LLVM Opts.inc -gen-opt-parser-defs)
add_public_tablegen_target(IFSOptsTableGen)
add_llvm_tool(llvm-ifs add_llvm_tool(llvm-ifs
ErrorCollector.cpp ErrorCollector.cpp
llvm-ifs.cpp llvm-ifs.cpp
DEPENDS
IFSOptsTableGen
) )

View File

@ -0,0 +1,37 @@
include "llvm/Option/OptParser.td"
class F<string letter, string help> : Flag<["-"], letter>, HelpText<help>;
class FF<string name, string help> : Flag<["--"], name>, HelpText<help>;
multiclass Eq<string name, string help> {
def NAME #_EQ : Joined<["--"], name #"=">, HelpText<help>;
def : Separate<["--"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
}
defm arch : Eq<"arch", "Specify the architecture, e.g. x86_64">;
defm bitwidth : Eq<"bitwidth", "Specify the bit width">;
defm endianness : Eq<"endianness", "Specify the endianness">;
defm exclude : Eq<"exclude", "Remove symbols which match the pattern. Can be specified multiple times">;
def help : FF<"help", "Display this help">;
def : F<"h", "Alias for --help">, Alias<help>;
defm hint_ifs_target : Eq<"hint-ifs-target", "When --output-format is 'IFS', this flag will hint the expected target triple for IFS output">;
defm input : Eq<"input", "input">;
defm input_format : Eq<"input-format", "Specify the input file format">;
defm output : Eq<"output", "Output file **DEPRECATED**">;
def : Separate<["-"], "o">, HelpText<"Alias for --output">, Alias<output_EQ>;
defm output_elf : Eq<"output-elf", "Output path for ELF file">;
defm output_format : Eq<"output-format", "Specify the output file format **DEPRECATED**">;
defm output_ifs : Eq<"output-ifs", "Output path for IFS file">;
defm output_tbd : Eq<"output-tbd", "Output path for TBD file">;
defm soname : Eq<"soname", "name">;
def strip_ifs_arch : FF<"strip-ifs-arch", "Strip target architecture information away from IFS output">;
def strip_ifs_bitwidth : FF<"strip-ifs-bitwidth", "Strip target bit width information away from IFS output">;
def strip_ifs_endianness : FF<"strip-ifs-endianness", "Strip target endianness information away from IFS output">;
def strip_ifs_target : FF<"strip-ifs-target", "Strip all target information away from IFS output">;
def strip_needed : FF<"strip-needed", "Strip needed libs from output">;
def strip_size : FF<"strip-size", "Remove object size from the output">;
def strip_undefined : FF<"strip-undefined", "Strip undefined symbols from IFS output">;
defm target : Eq<"target", "Specify the target triple, e.g. x86_64-linux-gnu">;
def version : FF<"version", "Display the version">;
def : F<"V", "Alias for --version">, Alias<version>;
def write_if_changed : FF<"write-if-changed", "Write the output file only if it is new or has changed">;

View File

@ -15,6 +15,9 @@
#include "llvm/InterfaceStub/IFSHandler.h" #include "llvm/InterfaceStub/IFSHandler.h"
#include "llvm/InterfaceStub/IFSStub.h" #include "llvm/InterfaceStub/IFSStub.h"
#include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h" #include "llvm/Support/Errc.h"
@ -46,100 +49,68 @@ const VersionTuple IfsVersionCurrent(3, 0);
enum class FileFormat { IFS, ELF, TBD }; enum class FileFormat { IFS, ELF, TBD };
} // end anonymous namespace } // end anonymous namespace
cl::OptionCategory IfsCategory("Ifs Options"); using namespace llvm::opt;
enum ID {
OPT_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
OPT_##ID,
#include "Opts.inc"
#undef OPTION
};
// TODO: Use OptTable for option parsing in the future. #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
// Command line flags: #include "Opts.inc"
cl::list<std::string> InputFilePaths(cl::Positional, cl::desc("input"), #undef PREFIX
cl::ZeroOrMore, cl::cat(IfsCategory));
cl::opt<FileFormat> InputFormat(
"input-format", cl::desc("Specify the input file format"),
cl::values(clEnumValN(FileFormat::IFS, "IFS", "Text based ELF stub file"),
clEnumValN(FileFormat::ELF, "ELF", "ELF object file")),
cl::cat(IfsCategory));
cl::opt<FileFormat> OutputFormat(
"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::cat(IfsCategory));
cl::opt<std::string> OptArch("arch",
cl::desc("Specify the architecture, e.g. x86_64"),
cl::cat(IfsCategory));
cl::opt<IFSBitWidthType>
OptBitWidth("bitwidth", cl::desc("Specify the bit width"),
cl::values(clEnumValN(IFSBitWidthType::IFS32, "32", "32 bits"),
clEnumValN(IFSBitWidthType::IFS64, "64", "64 bits")),
cl::cat(IfsCategory));
cl::opt<IFSEndiannessType> OptEndianness(
"endianness", cl::desc("Specify the endianness"),
cl::values(clEnumValN(IFSEndiannessType::Little, "little", "Little Endian"),
clEnumValN(IFSEndiannessType::Big, "big", "Big Endian")),
cl::cat(IfsCategory));
cl::opt<std::string> OptTargetTriple(
"target", cl::desc("Specify the target triple, e.g. x86_64-linux-gnu"),
cl::cat(IfsCategory));
cl::opt<std::string> OptTargetTripleHint(
"hint-ifs-target",
cl::desc("When --output-format is 'IFS', this flag will hint the expected "
"target triple for IFS output"),
cl::cat(IfsCategory));
cl::opt<bool> StripIFSArch(
"strip-ifs-arch",
cl::desc("Strip target architecture information away from IFS output"),
cl::cat(IfsCategory));
cl::opt<bool> StripIFSBitWidth(
"strip-ifs-bitwidth",
cl::desc("Strip target bit width information away from IFS output"),
cl::cat(IfsCategory));
cl::opt<bool> StripIFSEndiannessWidth(
"strip-ifs-endianness",
cl::desc("Strip target endianness information away from IFS output"),
cl::cat(IfsCategory));
cl::opt<bool> StripIFSTarget(
"strip-ifs-target",
cl::desc("Strip all target information away from IFS output"),
cl::cat(IfsCategory));
cl::opt<bool>
StripUndefined("strip-undefined",
cl::desc("Strip undefined symbols from IFS output"),
cl::cat(IfsCategory));
cl::opt<bool> StripNeededLibs("strip-needed",
cl::desc("Strip needed libs from output"),
cl::cat(IfsCategory));
cl::opt<bool> StripSize("strip-size",
cl::desc("Remove object size from the output"),
cl::cat(IfsCategory));
cl::list<std::string> const opt::OptTable::Info InfoTable[] = {
ExcludeSyms("exclude", #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
cl::desc("Remove symbols which match the pattern. Can be " HELPTEXT, METAVAR, VALUES) \
"specified multiple times"), { \
cl::cat(IfsCategory)); PREFIX, NAME, HELPTEXT, \
METAVAR, OPT_##ID, opt::Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, \
OPT_##ALIAS, ALIASARGS, VALUES},
#include "Opts.inc"
#undef OPTION
};
cl::opt<std::string> class IFSOptTable : public opt::OptTable {
SoName("soname", public:
cl::desc("Manually set the DT_SONAME entry of any emitted files"), IFSOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
cl::value_desc("name"), cl::cat(IfsCategory)); };
cl::opt<std::string> 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<std::string> OutputELFFilePath("output-elf",
cl::desc("Output path for ELF file"),
cl::cat(IfsCategory));
cl::opt<std::string> OutputIFSFilePath("output-ifs",
cl::desc("Output path for IFS file"),
cl::cat(IfsCategory));
cl::opt<std::string> OutputTBDFilePath("output-tbd",
cl::desc("Output path for TBD file"),
cl::cat(IfsCategory));
cl::opt<bool> WriteIfChanged( struct DriverConfig {
"write-if-changed", std::vector<std::string> InputFilePaths;
cl::desc("Write the output file only if it is new or has changed."),
cl::cat(IfsCategory)); Optional<FileFormat> InputFormat;
Optional<FileFormat> OutputFormat;
Optional<std::string> HintIfsTarget;
Optional<std::string> OptTargetTriple;
Optional<IFSArch> OverrideArch;
Optional<IFSBitWidthType> OverrideBitWidth;
Optional<IFSEndiannessType> OverrideEndianness;
bool StripIfsArch = false;
bool StripIfsBitwidth = false;
bool StripIfsEndianness = false;
bool StripIfsTarget = false;
bool StripNeeded = false;
bool StripSize = false;
bool StripUndefined = false;
std::vector<std::string> Exclude;
Optional<std::string> SoName;
Optional<std::string> Output;
Optional<std::string> OutputElf;
Optional<std::string> OutputIfs;
Optional<std::string> OutputTbd;
bool WriteIfChanged = false;
};
static std::string getTypeName(IFSSymbolType Type) { static std::string getTypeName(IFSSymbolType Type) {
switch (Type) { switch (Type) {
@ -157,7 +128,8 @@ static std::string getTypeName(IFSSymbolType Type) {
llvm_unreachable("Unexpected ifs symbol type."); llvm_unreachable("Unexpected ifs symbol type.");
} }
static Expected<std::unique_ptr<IFSStub>> readInputFile(StringRef FilePath) { static Expected<std::unique_ptr<IFSStub>>
readInputFile(Optional<FileFormat> &InputFormat, StringRef FilePath) {
// Read in file. // Read in file.
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError = ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
MemoryBuffer::getFileOrSTDIN(FilePath, /*IsText=*/true); MemoryBuffer::getFileOrSTDIN(FilePath, /*IsText=*/true);
@ -169,10 +141,11 @@ static Expected<std::unique_ptr<IFSStub>> readInputFile(StringRef FilePath) {
ErrorCollector EC(/*UseFatalErrors=*/false); ErrorCollector EC(/*UseFatalErrors=*/false);
// First try to read as a binary (fails fast if not binary). // First try to read as a binary (fails fast if not binary).
if (InputFormat.getNumOccurrences() == 0 || InputFormat == FileFormat::ELF) { if (!InputFormat || *InputFormat == FileFormat::ELF) {
Expected<std::unique_ptr<IFSStub>> StubFromELF = Expected<std::unique_ptr<IFSStub>> StubFromELF =
readELFFile(FileReadBuffer->getMemBufferRef()); readELFFile(FileReadBuffer->getMemBufferRef());
if (StubFromELF) { if (StubFromELF) {
InputFormat = FileFormat::ELF;
(*StubFromELF)->IfsVersion = IfsVersionCurrent; (*StubFromELF)->IfsVersion = IfsVersionCurrent;
return std::move(*StubFromELF); return std::move(*StubFromELF);
} }
@ -180,10 +153,11 @@ static Expected<std::unique_ptr<IFSStub>> readInputFile(StringRef FilePath) {
} }
// Fall back to reading as a ifs. // Fall back to reading as a ifs.
if (InputFormat.getNumOccurrences() == 0 || InputFormat == FileFormat::IFS) { if (!InputFormat || *InputFormat == FileFormat::IFS) {
Expected<std::unique_ptr<IFSStub>> StubFromIFS = Expected<std::unique_ptr<IFSStub>> StubFromIFS =
readIFSFromBuffer(FileReadBuffer->getBuffer()); readIFSFromBuffer(FileReadBuffer->getBuffer());
if (StubFromIFS) { if (StubFromIFS) {
InputFormat = FileFormat::IFS;
if ((*StubFromIFS)->IfsVersion > IfsVersionCurrent) if ((*StubFromIFS)->IfsVersion > IfsVersionCurrent)
EC.addError( EC.addError(
createStringError(errc::not_supported, createStringError(errc::not_supported,
@ -271,9 +245,14 @@ static void fatalError(Error Err) {
exit(1); exit(1);
} }
static void fatalError(Twine T) {
WithColor::error() << T.str() << '\n';
exit(1);
}
/// writeIFS() writes a Text-Based ELF stub to a file using the latest version /// writeIFS() writes a Text-Based ELF stub to a file using the latest version
/// of the YAML parser. /// of the YAML parser.
static Error writeIFS(StringRef FilePath, IFSStub &Stub) { static Error writeIFS(StringRef FilePath, IFSStub &Stub, bool WriteIfChanged) {
// Write IFS to memory first. // Write IFS to memory first.
std::string IFSStr; std::string IFSStr;
raw_string_ostream OutStr(IFSStr); raw_string_ostream OutStr(IFSStr);
@ -285,7 +264,8 @@ static Error writeIFS(StringRef FilePath, IFSStub &Stub) {
if (WriteIfChanged) { if (WriteIfChanged) {
if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError = if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
MemoryBuffer::getFile(FilePath)) { MemoryBuffer::getFile(FilePath)) {
// Compare IFS output with the existing IFS file. If unchanged, avoid changing the file. // Compare IFS output with the existing IFS file. If unchanged, avoid
// changing the file.
if ((*BufOrError)->getBuffer() == IFSStr) if ((*BufOrError)->getBuffer() == IFSStr)
return Error::success(); return Error::success();
} }
@ -300,24 +280,119 @@ static Error writeIFS(StringRef FilePath, IFSStub &Stub) {
return Error::success(); return Error::success();
} }
int main(int argc, char *argv[]) { static DriverConfig parseArgs(int argc, char *const *argv) {
// Parse arguments. BumpPtrAllocator A;
cl::HideUnrelatedOptions({&IfsCategory, &getColorCategory()}); StringSaver Saver(A);
cl::ParseCommandLineOptions(argc, argv); IFSOptTable Tbl;
StringRef ToolName = argv[0];
llvm::opt::InputArgList Args = Tbl.parseArgs(
argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { fatalError(Msg); });
if (Args.hasArg(OPT_help)) {
Tbl.printHelp(llvm::outs(),
(Twine(ToolName) + " <input_file> <output_file> [options]")
.str()
.c_str(),
"shared object stubbing tool");
std::exit(0);
}
if (Args.hasArg(OPT_version)) {
llvm::outs() << ToolName << '\n';
cl::PrintVersionMessage();
std::exit(0);
}
if (InputFilePaths.empty()) DriverConfig Config;
InputFilePaths.push_back("-"); for (const opt::Arg *A : Args.filtered(OPT_INPUT))
Config.InputFilePaths.push_back(A->getValue());
if (const opt::Arg *A = Args.getLastArg(OPT_input_format_EQ)) {
Config.InputFormat = StringSwitch<Optional<FileFormat>>(A->getValue())
.Case("IFS", FileFormat::IFS)
.Case("ELF", FileFormat::ELF)
.Default(None);
if (!Config.InputFormat)
fatalError(Twine("invalid argument '") + A->getValue());
}
auto OptionNotFound = [ToolName](StringRef FlagName, StringRef OptionName) {
fatalError(Twine(ToolName) + ": for the " + FlagName +
" option: Cannot find option named '" + OptionName + "'!");
};
if (const opt::Arg *A = Args.getLastArg(OPT_output_format_EQ)) {
Config.OutputFormat = StringSwitch<Optional<FileFormat>>(A->getValue())
.Case("IFS", FileFormat::IFS)
.Case("ELF", FileFormat::ELF)
.Case("TBD", FileFormat::TBD)
.Default(None);
if (!Config.OutputFormat)
OptionNotFound("--output-format", A->getValue());
}
if (const opt::Arg *A = Args.getLastArg(OPT_arch_EQ))
Config.OverrideArch = ELF::convertArchNameToEMachine(A->getValue());
if (const opt::Arg *A = Args.getLastArg(OPT_bitwidth_EQ)) {
size_t Width;
llvm::StringRef S(A->getValue());
if (!S.getAsInteger<size_t>(10, Width) || Width == 64 || Width == 32)
Config.OverrideBitWidth =
Width == 64 ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;
else
OptionNotFound("--bitwidth", A->getValue());
}
if (const opt::Arg *A = Args.getLastArg(OPT_endianness_EQ)) {
Config.OverrideEndianness =
StringSwitch<Optional<IFSEndiannessType>>(A->getValue())
.Case("little", IFSEndiannessType::Little)
.Case("big", IFSEndiannessType::Big)
.Default(None);
if (!Config.OverrideEndianness)
OptionNotFound("--endianness", A->getValue());
}
if (const opt::Arg *A = Args.getLastArg(OPT_target_EQ))
Config.OptTargetTriple = A->getValue();
if (const opt::Arg *A = Args.getLastArg(OPT_hint_ifs_target_EQ))
Config.HintIfsTarget = A->getValue();
Config.StripIfsArch = Args.hasArg(OPT_strip_ifs_arch);
Config.StripIfsBitwidth = Args.hasArg(OPT_strip_ifs_bitwidth);
Config.StripIfsEndianness = Args.hasArg(OPT_strip_ifs_endianness);
Config.StripIfsTarget = Args.hasArg(OPT_strip_ifs_target);
Config.StripUndefined = Args.hasArg(OPT_strip_undefined);
Config.StripNeeded = Args.hasArg(OPT_strip_needed);
Config.StripSize = Args.hasArg(OPT_strip_size);
for (const opt::Arg *A : Args.filtered(OPT_exclude_EQ))
Config.Exclude.push_back(A->getValue());
if (const opt::Arg *A = Args.getLastArg(OPT_soname_EQ))
Config.SoName = A->getValue();
if (const opt::Arg *A = Args.getLastArg(OPT_output_EQ))
Config.Output = A->getValue();
if (const opt::Arg *A = Args.getLastArg(OPT_output_elf_EQ))
Config.OutputElf = A->getValue();
if (const opt::Arg *A = Args.getLastArg(OPT_output_ifs_EQ))
Config.OutputIfs = A->getValue();
if (const opt::Arg *A = Args.getLastArg(OPT_output_tbd_EQ))
Config.OutputTbd = A->getValue();
Config.WriteIfChanged = Args.hasArg(OPT_write_if_changed);
return Config;
}
int main(int argc, char *argv[]) {
DriverConfig Config = parseArgs(argc, argv);
if (Config.InputFilePaths.empty())
Config.InputFilePaths.push_back("-");
// If input files are more than one, they can only be IFS files. // If input files are more than one, they can only be IFS files.
if (InputFilePaths.size() > 1) if (Config.InputFilePaths.size() > 1)
InputFormat.setValue(FileFormat::IFS); Config.InputFormat = FileFormat::IFS;
// Attempt to merge input. // Attempt to merge input.
IFSStub Stub; IFSStub Stub;
std::map<std::string, IFSSymbol> SymbolMap; std::map<std::string, IFSSymbol> SymbolMap;
std::string PreviousInputFilePath; std::string PreviousInputFilePath;
for (const std::string &InputFilePath : InputFilePaths) { for (const std::string &InputFilePath : Config.InputFilePaths) {
Expected<std::unique_ptr<IFSStub>> StubOrErr = readInputFile(InputFilePath); Expected<std::unique_ptr<IFSStub>> StubOrErr =
readInputFile(Config.InputFormat, InputFilePath);
if (!StubOrErr) if (!StubOrErr)
fatalError(StubOrErr.takeError()); fatalError(StubOrErr.takeError());
@ -411,57 +486,45 @@ int main(int argc, char *argv[]) {
Stub.Symbols.push_back(Entry.second); Stub.Symbols.push_back(Entry.second);
// Change SoName before emitting stubs. // Change SoName before emitting stubs.
if (SoName.getNumOccurrences() == 1) if (Config.SoName)
Stub.SoName = SoName; Stub.SoName = *Config.SoName;
Optional<IFSArch> OverrideArch;
Optional<IFSEndiannessType> OverrideEndianness; Error OverrideError =
Optional<IFSBitWidthType> OverrideBitWidth; overrideIFSTarget(Stub, Config.OverrideArch, Config.OverrideEndianness,
Optional<std::string> OverrideTriple; Config.OverrideBitWidth, Config.OptTargetTriple);
if (OptArch.getNumOccurrences() == 1)
OverrideArch = ELF::convertArchNameToEMachine(OptArch.getValue());
if (OptEndianness.getNumOccurrences() == 1)
OverrideEndianness = OptEndianness.getValue();
if (OptBitWidth.getNumOccurrences() == 1)
OverrideBitWidth = OptBitWidth.getValue();
if (OptTargetTriple.getNumOccurrences() == 1)
OverrideTriple = OptTargetTriple.getValue();
Error OverrideError = overrideIFSTarget(
Stub, OverrideArch, OverrideEndianness, OverrideBitWidth, OverrideTriple);
if (OverrideError) if (OverrideError)
fatalError(std::move(OverrideError)); fatalError(std::move(OverrideError));
if (StripNeededLibs) if (Config.StripNeeded)
Stub.NeededLibs.clear(); Stub.NeededLibs.clear();
if (Error E = filterIFSSyms(Stub, StripUndefined, ExcludeSyms)) if (Error E = filterIFSSyms(Stub, Config.StripUndefined, Config.Exclude))
fatalError(std::move(E)); fatalError(std::move(E));
if (StripSize) if (Config.StripSize)
for (IFSSymbol &Sym : Stub.Symbols) for (IFSSymbol &Sym : Stub.Symbols)
Sym.Size.reset(); Sym.Size.reset();
if (OutputELFFilePath.getNumOccurrences() == 0 && if (!Config.OutputElf && !Config.OutputIfs && !Config.OutputTbd) {
OutputIFSFilePath.getNumOccurrences() == 0 && if (!Config.OutputFormat) {
OutputTBDFilePath.getNumOccurrences() == 0) {
if (OutputFormat.getNumOccurrences() == 0) {
WithColor::error() << "at least one output should be specified."; WithColor::error() << "at least one output should be specified.";
return -1; return -1;
} }
} else if (OutputFormat.getNumOccurrences() == 1) { } else if (Config.OutputFormat) {
WithColor::error() << "'--output-format' cannot be used with " WithColor::error() << "'--output-format' cannot be used with "
"'--output-{FILE_FORMAT}' options at the same time"; "'--output-{FILE_FORMAT}' options at the same time";
return -1; return -1;
} }
if (OutputFormat.getNumOccurrences() == 1) { if (Config.OutputFormat) {
// TODO: Remove OutputFormat flag in the next revision. // TODO: Remove OutputFormat flag in the next revision.
WithColor::warning() << "--output-format option is deprecated, please use " WithColor::warning() << "--output-format option is deprecated, please use "
"--output-{FILE_FORMAT} options instead\n"; "--output-{FILE_FORMAT} options instead\n";
switch (OutputFormat.getValue()) { switch (Config.OutputFormat.getValue()) {
case FileFormat::TBD: { case FileFormat::TBD: {
std::error_code SysErr; std::error_code SysErr;
raw_fd_ostream Out(OutputFilePath, SysErr); raw_fd_ostream Out(*Config.Output, SysErr);
if (SysErr) { if (SysErr) {
WithColor::error() << "Couldn't open " << OutputFilePath WithColor::error() << "Couldn't open " << *Config.Output
<< " for writing.\n"; << " for writing.\n";
return -1; return -1;
} }
@ -475,10 +538,10 @@ int main(int argc, char *argv[]) {
} }
case FileFormat::IFS: { case FileFormat::IFS: {
Stub.IfsVersion = IfsVersionCurrent; Stub.IfsVersion = IfsVersionCurrent;
if (InputFormat.getValue() == FileFormat::ELF && if (Config.InputFormat.getValue() == FileFormat::ELF &&
OptTargetTripleHint.getNumOccurrences() == 1) { Config.HintIfsTarget) {
std::error_code HintEC(1, std::generic_category()); std::error_code HintEC(1, std::generic_category());
IFSTarget HintTarget = parseTriple(OptTargetTripleHint); IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget);
if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue()) if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue())
fatalError(make_error<StringError>( fatalError(make_error<StringError>(
"Triple hint does not match the actual architecture", HintEC)); "Triple hint does not match the actual architecture", HintEC));
@ -491,12 +554,13 @@ int main(int argc, char *argv[]) {
"Triple hint does not match the actual bit width", HintEC)); "Triple hint does not match the actual bit width", HintEC));
stripIFSTarget(Stub, true, false, false, false); stripIFSTarget(Stub, true, false, false, false);
Stub.Target.Triple = OptTargetTripleHint.getValue(); Stub.Target.Triple = Config.HintIfsTarget.getValue();
} else { } else {
stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch,
StripIFSEndiannessWidth, StripIFSBitWidth); Config.StripIfsEndianness, Config.StripIfsBitwidth);
} }
Error IFSWriteError = writeIFS(OutputFilePath.getValue(), Stub); Error IFSWriteError =
writeIFS(Config.Output.getValue(), Stub, Config.WriteIfChanged);
if (IFSWriteError) if (IFSWriteError)
fatalError(std::move(IFSWriteError)); fatalError(std::move(IFSWriteError));
break; break;
@ -506,7 +570,7 @@ int main(int argc, char *argv[]) {
if (TargetError) if (TargetError)
fatalError(std::move(TargetError)); fatalError(std::move(TargetError));
Error BinaryWriteError = Error BinaryWriteError =
writeBinaryStub(OutputFilePath, Stub, WriteIfChanged); writeBinaryStub(*Config.Output, Stub, Config.WriteIfChanged);
if (BinaryWriteError) if (BinaryWriteError)
fatalError(std::move(BinaryWriteError)); fatalError(std::move(BinaryWriteError));
break; break;
@ -514,21 +578,21 @@ int main(int argc, char *argv[]) {
} }
} else { } else {
// Check if output path for individual format. // Check if output path for individual format.
if (OutputELFFilePath.getNumOccurrences() == 1) { if (Config.OutputElf) {
Error TargetError = validateIFSTarget(Stub, true); Error TargetError = validateIFSTarget(Stub, true);
if (TargetError) if (TargetError)
fatalError(std::move(TargetError)); fatalError(std::move(TargetError));
Error BinaryWriteError = Error BinaryWriteError =
writeBinaryStub(OutputELFFilePath, Stub, WriteIfChanged); writeBinaryStub(*Config.OutputElf, Stub, Config.WriteIfChanged);
if (BinaryWriteError) if (BinaryWriteError)
fatalError(std::move(BinaryWriteError)); fatalError(std::move(BinaryWriteError));
} }
if (OutputIFSFilePath.getNumOccurrences() == 1) { if (Config.OutputIfs) {
Stub.IfsVersion = IfsVersionCurrent; Stub.IfsVersion = IfsVersionCurrent;
if (InputFormat.getValue() == FileFormat::ELF && if (Config.InputFormat.getValue() == FileFormat::ELF &&
OptTargetTripleHint.getNumOccurrences() == 1) { Config.HintIfsTarget) {
std::error_code HintEC(1, std::generic_category()); std::error_code HintEC(1, std::generic_category());
IFSTarget HintTarget = parseTriple(OptTargetTripleHint); IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget);
if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue()) if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue())
fatalError(make_error<StringError>( fatalError(make_error<StringError>(
"Triple hint does not match the actual architecture", HintEC)); "Triple hint does not match the actual architecture", HintEC));
@ -541,20 +605,21 @@ int main(int argc, char *argv[]) {
"Triple hint does not match the actual bit width", HintEC)); "Triple hint does not match the actual bit width", HintEC));
stripIFSTarget(Stub, true, false, false, false); stripIFSTarget(Stub, true, false, false, false);
Stub.Target.Triple = OptTargetTripleHint.getValue(); Stub.Target.Triple = Config.HintIfsTarget.getValue();
} else { } else {
stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch,
StripIFSEndiannessWidth, StripIFSBitWidth); Config.StripIfsEndianness, Config.StripIfsBitwidth);
} }
Error IFSWriteError = writeIFS(OutputIFSFilePath.getValue(), Stub); Error IFSWriteError =
writeIFS(Config.OutputIfs.getValue(), Stub, Config.WriteIfChanged);
if (IFSWriteError) if (IFSWriteError)
fatalError(std::move(IFSWriteError)); fatalError(std::move(IFSWriteError));
} }
if (OutputTBDFilePath.getNumOccurrences() == 1) { if (Config.OutputTbd) {
std::error_code SysErr; std::error_code SysErr;
raw_fd_ostream Out(OutputTBDFilePath, SysErr); raw_fd_ostream Out(*Config.OutputTbd, SysErr);
if (SysErr) { if (SysErr) {
WithColor::error() << "Couldn't open " << OutputTBDFilePath WithColor::error() << "Couldn't open " << *Config.OutputTbd
<< " for writing.\n"; << " for writing.\n";
return -1; return -1;
} }