forked from OSchip/llvm-project
[llvm-objcopy][NFC] Refactor output target parsing v2
Summary:
Use an enum instead of string to hold the output file format in Config.InputFormat and Config.OutputFormat. It's essential to support other output file formats other than ELF.
This patch originally has been submitted as D63239. However, there was an use-of-uninitialized-value bug and reverted in r364379 (git commit 4ee933c
).
This patch includes the fix for the bug by setting Config.InputFormat/Config.OutputFormat in parseStripOptions.
Reviewers: espindola, alexshap, rupprecht, jhenderson
Reviewed By: jhenderson
Subscribers: emaste, arichardson, jakehehrlich, MaskRay, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64170
llvm-svn: 365173
This commit is contained in:
parent
3c47d38f61
commit
ecb60b7e5c
|
@ -277,8 +277,13 @@ static Expected<const MachineInfo &> getMachineInfo(StringRef Arch) {
|
||||||
return Iter->getValue();
|
return Iter->getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TargetInfo {
|
||||||
|
FileFormat Format;
|
||||||
|
MachineInfo Machine;
|
||||||
|
};
|
||||||
|
|
||||||
// FIXME: consolidate with the bfd parsing used by lld.
|
// FIXME: consolidate with the bfd parsing used by lld.
|
||||||
static const StringMap<MachineInfo> OutputFormatMap{
|
static const StringMap<MachineInfo> TargetMap{
|
||||||
// Name, {EMachine, 64bit, LittleEndian}
|
// Name, {EMachine, 64bit, LittleEndian}
|
||||||
// x86
|
// x86
|
||||||
{"elf32-i386", {ELF::EM_386, false, true}},
|
{"elf32-i386", {ELF::EM_386, false, true}},
|
||||||
|
@ -312,18 +317,28 @@ static const StringMap<MachineInfo> OutputFormatMap{
|
||||||
{"elf32-sparcel", {ELF::EM_SPARC, false, true}},
|
{"elf32-sparcel", {ELF::EM_SPARC, false, true}},
|
||||||
};
|
};
|
||||||
|
|
||||||
static Expected<MachineInfo> getOutputFormatMachineInfo(StringRef Format) {
|
static Expected<TargetInfo>
|
||||||
StringRef OriginalFormat = Format;
|
getOutputTargetInfoByTargetName(StringRef TargetName) {
|
||||||
bool IsFreeBSD = Format.consume_back("-freebsd");
|
StringRef OriginalTargetName = TargetName;
|
||||||
auto Iter = OutputFormatMap.find(Format);
|
bool IsFreeBSD = TargetName.consume_back("-freebsd");
|
||||||
if (Iter == std::end(OutputFormatMap))
|
auto Iter = TargetMap.find(TargetName);
|
||||||
|
if (Iter == std::end(TargetMap))
|
||||||
return createStringError(errc::invalid_argument,
|
return createStringError(errc::invalid_argument,
|
||||||
"invalid output format: '%s'",
|
"invalid output format: '%s'",
|
||||||
OriginalFormat.str().c_str());
|
OriginalTargetName.str().c_str());
|
||||||
MachineInfo MI = Iter->getValue();
|
MachineInfo MI = Iter->getValue();
|
||||||
if (IsFreeBSD)
|
if (IsFreeBSD)
|
||||||
MI.OSABI = ELF::ELFOSABI_FREEBSD;
|
MI.OSABI = ELF::ELFOSABI_FREEBSD;
|
||||||
return {MI};
|
|
||||||
|
FileFormat Format;
|
||||||
|
if (TargetName.startswith("elf"))
|
||||||
|
Format = FileFormat::ELF;
|
||||||
|
else
|
||||||
|
// This should never happen because `TargetName` is valid (it certainly
|
||||||
|
// exists in the TargetMap).
|
||||||
|
llvm_unreachable("unknown target prefix");
|
||||||
|
|
||||||
|
return {TargetInfo{Format, MI}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error addSymbolsFromFile(std::vector<NameOrRegex> &Symbols,
|
static Error addSymbolsFromFile(std::vector<NameOrRegex> &Symbols,
|
||||||
|
@ -445,14 +460,23 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
|
||||||
"--target cannot be used with --input-target or --output-target");
|
"--target cannot be used with --input-target or --output-target");
|
||||||
|
|
||||||
bool UseRegex = InputArgs.hasArg(OBJCOPY_regex);
|
bool UseRegex = InputArgs.hasArg(OBJCOPY_regex);
|
||||||
|
StringRef InputFormat, OutputFormat;
|
||||||
if (InputArgs.hasArg(OBJCOPY_target)) {
|
if (InputArgs.hasArg(OBJCOPY_target)) {
|
||||||
Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
|
InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
|
||||||
Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
|
OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
|
||||||
} else {
|
} else {
|
||||||
Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
|
InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
|
||||||
Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
|
OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
|
||||||
}
|
}
|
||||||
if (Config.InputFormat == "binary") {
|
|
||||||
|
// FIXME: Currently, we ignore the target for non-binary/ihex formats
|
||||||
|
// explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the
|
||||||
|
// format by llvm::object::createBinary regardless of the option value.
|
||||||
|
Config.InputFormat = StringSwitch<FileFormat>(InputFormat)
|
||||||
|
.Case("binary", FileFormat::Binary)
|
||||||
|
.Case("ihex", FileFormat::IHex)
|
||||||
|
.Default(FileFormat::Unspecified);
|
||||||
|
if (Config.InputFormat == FileFormat::Binary) {
|
||||||
auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
|
auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
|
||||||
if (BinaryArch.empty())
|
if (BinaryArch.empty())
|
||||||
return createStringError(
|
return createStringError(
|
||||||
|
@ -463,12 +487,17 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
|
||||||
return MI.takeError();
|
return MI.takeError();
|
||||||
Config.BinaryArch = *MI;
|
Config.BinaryArch = *MI;
|
||||||
}
|
}
|
||||||
if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary" &&
|
|
||||||
Config.OutputFormat != "ihex") {
|
Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
|
||||||
Expected<MachineInfo> MI = getOutputFormatMachineInfo(Config.OutputFormat);
|
.Case("binary", FileFormat::Binary)
|
||||||
if (!MI)
|
.Case("ihex", FileFormat::IHex)
|
||||||
return MI.takeError();
|
.Default(FileFormat::Unspecified);
|
||||||
Config.OutputArch = *MI;
|
if (Config.OutputFormat == FileFormat::Unspecified && !OutputFormat.empty()) {
|
||||||
|
Expected<TargetInfo> Target = getOutputTargetInfoByTargetName(OutputFormat);
|
||||||
|
if (!Target)
|
||||||
|
return Target.takeError();
|
||||||
|
Config.OutputFormat = Target->Format;
|
||||||
|
Config.OutputArch = Target->Machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
|
if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
|
||||||
|
@ -804,6 +833,8 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,
|
||||||
STRIP_disable_deterministic_archives, /*default=*/true);
|
STRIP_disable_deterministic_archives, /*default=*/true);
|
||||||
|
|
||||||
Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
|
Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
|
||||||
|
Config.InputFormat = FileFormat::Unspecified;
|
||||||
|
Config.OutputFormat = FileFormat::Unspecified;
|
||||||
|
|
||||||
DriverConfig DC;
|
DriverConfig DC;
|
||||||
if (Positional.size() == 1) {
|
if (Positional.size() == 1) {
|
||||||
|
|
|
@ -26,6 +26,13 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace objcopy {
|
namespace objcopy {
|
||||||
|
|
||||||
|
enum class FileFormat {
|
||||||
|
Unspecified,
|
||||||
|
ELF,
|
||||||
|
Binary,
|
||||||
|
IHex,
|
||||||
|
};
|
||||||
|
|
||||||
// This type keeps track of the machine info for various architectures. This
|
// This type keeps track of the machine info for various architectures. This
|
||||||
// lets us map architecture names to ELF types and the e_machine value of the
|
// lets us map architecture names to ELF types and the e_machine value of the
|
||||||
// ELF file.
|
// ELF file.
|
||||||
|
@ -104,9 +111,9 @@ struct NewSymbolInfo {
|
||||||
struct CopyConfig {
|
struct CopyConfig {
|
||||||
// Main input/output options
|
// Main input/output options
|
||||||
StringRef InputFilename;
|
StringRef InputFilename;
|
||||||
StringRef InputFormat;
|
FileFormat InputFormat;
|
||||||
StringRef OutputFilename;
|
StringRef OutputFilename;
|
||||||
StringRef OutputFormat;
|
FileFormat OutputFormat;
|
||||||
|
|
||||||
// Only applicable for --input-format=binary
|
// Only applicable for --input-format=binary
|
||||||
MachineInfo BinaryArch;
|
MachineInfo BinaryArch;
|
||||||
|
|
|
@ -154,12 +154,14 @@ static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
|
||||||
static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
|
static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
|
||||||
Object &Obj, Buffer &Buf,
|
Object &Obj, Buffer &Buf,
|
||||||
ElfType OutputElfType) {
|
ElfType OutputElfType) {
|
||||||
using Functor = std::function<std::unique_ptr<Writer>()>;
|
switch (Config.OutputFormat) {
|
||||||
return StringSwitch<Functor>(Config.OutputFormat)
|
case FileFormat::Binary:
|
||||||
.Case("binary", [&] { return llvm::make_unique<BinaryWriter>(Obj, Buf); })
|
return llvm::make_unique<BinaryWriter>(Obj, Buf);
|
||||||
.Case("ihex", [&] { return llvm::make_unique<IHexWriter>(Obj, Buf); })
|
case FileFormat::IHex:
|
||||||
.Default(
|
return llvm::make_unique<IHexWriter>(Obj, Buf);
|
||||||
[&] { return createELFWriter(Config, Obj, Buf, OutputElfType); })();
|
default:
|
||||||
|
return createELFWriter(Config, Obj, Buf, OutputElfType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
|
|
@ -140,11 +140,18 @@ static Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
|
||||||
/// of the output specified by the command line options.
|
/// of the output specified by the command line options.
|
||||||
static Error executeObjcopyOnRawBinary(const CopyConfig &Config,
|
static Error executeObjcopyOnRawBinary(const CopyConfig &Config,
|
||||||
MemoryBuffer &In, Buffer &Out) {
|
MemoryBuffer &In, Buffer &Out) {
|
||||||
// TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize
|
switch (Config.OutputFormat) {
|
||||||
// formats other than ELF / "binary" and invoke
|
case FileFormat::ELF:
|
||||||
// elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or
|
// FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the
|
||||||
// coff::executeObjcopyOnRawBinary accordingly.
|
// output format is binary/ihex or it's not given. This behavior differs from
|
||||||
return elf::executeObjcopyOnRawBinary(Config, In, Out);
|
// GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details.
|
||||||
|
case FileFormat::Binary:
|
||||||
|
case FileFormat::IHex:
|
||||||
|
case FileFormat::Unspecified:
|
||||||
|
return elf::executeObjcopyOnRawBinary(Config, In, Out);
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_unreachable("unsupported output format");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The function executeObjcopyOnBinary does the dispatch based on the format
|
/// The function executeObjcopyOnBinary does the dispatch based on the format
|
||||||
|
@ -238,10 +245,17 @@ static Error executeObjcopy(const CopyConfig &Config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &);
|
typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &);
|
||||||
auto ProcessRaw = StringSwitch<ProcessRawFn>(Config.InputFormat)
|
ProcessRawFn ProcessRaw;
|
||||||
.Case("binary", executeObjcopyOnRawBinary)
|
switch (Config.InputFormat) {
|
||||||
.Case("ihex", executeObjcopyOnIHex)
|
case FileFormat::Binary:
|
||||||
.Default(nullptr);
|
ProcessRaw = executeObjcopyOnRawBinary;
|
||||||
|
break;
|
||||||
|
case FileFormat::IHex:
|
||||||
|
ProcessRaw = executeObjcopyOnIHex;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ProcessRaw = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (ProcessRaw) {
|
if (ProcessRaw) {
|
||||||
auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
|
auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
|
||||||
|
|
Loading…
Reference in New Issue