forked from OSchip/llvm-project
[ifs] Switch to using OptTable
Differential revision: https://reviews.llvm.org/D125658
This commit is contained in:
parent
aed49eac87
commit
480dcdc897
|
@ -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
|
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
@ -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">;
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue