diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CopyConfig.h @@ -15,6 +15,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Regex.h" // Necessary for llvm::DebugCompressionType::None #include "llvm/Target/TargetOptions.h" @@ -131,12 +132,12 @@ // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. -DriverConfig parseObjcopyOptions(ArrayRef ArgsArr); +Expected parseObjcopyOptions(ArrayRef ArgsArr); // ParseStripOptions returns the config and sets the input arguments. If a // help flag is set then ParseStripOptions will print the help messege and // exit. -DriverConfig parseStripOptions(ArrayRef ArgsArr); +Expected parseStripOptions(ArrayRef ArgsArr); } // namespace objcopy } // namespace llvm diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -129,15 +129,18 @@ .Default(SectionFlag::SecNone); } -static uint64_t parseSectionFlagSet(ArrayRef SectionFlags) { +static Expected +parseSectionFlagSet(ArrayRef SectionFlags) { SectionFlag ParsedFlags = SectionFlag::SecNone; for (StringRef Flag : SectionFlags) { SectionFlag ParsedFlag = parseSectionRenameFlag(Flag); if (ParsedFlag == SectionFlag::SecNone) - error("Unrecognized section flag '" + Flag + - "'. Flags supported for GNU compatibility: alloc, load, noload, " - "readonly, debug, code, data, rom, share, contents, merge, " - "strings."); + return createStringError( + errc::invalid_argument, + "Unrecognized section flag '%s'. Flags supported for GNU " + "compatibility: alloc, load, noload, readonly, debug, code, data, " + "rom, share, contents, merge, strings.", + Flag.str().c_str()); ParsedFlags |= ParsedFlag; } @@ -155,9 +158,10 @@ return NewFlags; } -static SectionRename parseRenameSectionValue(StringRef FlagValue) { +static Expected parseRenameSectionValue(StringRef FlagValue) { if (!FlagValue.contains('=')) - error("Bad format for --rename-section: missing '='"); + return createStringError(errc::invalid_argument, + "Bad format for --rename-section: missing '='"); // Initial split: ".foo" = ".bar,f1,f2,..." auto Old2New = FlagValue.split('='); @@ -169,15 +173,22 @@ Old2New.second.split(NameAndFlags, ','); SR.NewName = NameAndFlags[0]; - if (NameAndFlags.size() > 1) - SR.NewFlags = parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front()); + if (NameAndFlags.size() > 1) { + Expected ParsedFlagSet = + parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front()); + if (!ParsedFlagSet) + return ParsedFlagSet.takeError(); + SR.NewFlags = *ParsedFlagSet; + } return SR; } -static SectionFlagsUpdate parseSetSectionFlagValue(StringRef FlagValue) { +static Expected +parseSetSectionFlagValue(StringRef FlagValue) { if (!StringRef(FlagValue).contains('=')) - error("Bad format for --set-section-flags: missing '='"); + return createStringError(errc::invalid_argument, + "Bad format for --set-section-flags: missing '='"); // Initial split: ".foo" = "f1,f2,..." auto Section2Flags = StringRef(FlagValue).split('='); @@ -187,7 +198,10 @@ // Flags split: "f1" "f2" ... SmallVector SectionFlags; Section2Flags.second.split(SectionFlags, ','); - SFU.NewFlags = parseSectionFlagSet(SectionFlags); + Expected ParsedFlagSet = parseSectionFlagSet(SectionFlags); + if (!ParsedFlagSet) + return ParsedFlagSet.takeError(); + SFU.NewFlags = *ParsedFlagSet; return SFU; } @@ -203,10 +217,11 @@ {"x86-64", {ELF::EM_X86_64, true, true}}, }; -static const MachineInfo &getMachineInfo(StringRef Arch) { +static Expected getMachineInfo(StringRef Arch) { auto Iter = ArchMap.find(Arch); if (Iter == std::end(ArchMap)) - error("Invalid architecture: '" + Arch + "'"); + return createStringError(errc::invalid_argument, + "Invalid architecture: '%s'.", Arch.str().c_str()); return Iter->getValue(); } @@ -219,21 +234,24 @@ {"elf64-x86-64", {ELF::EM_X86_64, true, true}}, }; -static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) { +static Expected +getOutputFormatMachineInfo(StringRef Format) { auto Iter = OutputFormatMap.find(Format); if (Iter == std::end(OutputFormatMap)) - error("Invalid output format: '" + Format + "'"); + return createStringError(errc::invalid_argument, + "Invalid output format: '%s'.", + Format.str().c_str()); return Iter->getValue(); } -static void addSymbolsFromFile(std::vector &Symbols, - BumpPtrAllocator &Alloc, StringRef Filename, - bool UseRegex) { +static Error addSymbolsFromFile(std::vector &Symbols, + BumpPtrAllocator &Alloc, StringRef Filename, + bool UseRegex) { StringSaver Saver(Alloc); SmallVector Lines; auto BufOrErr = MemoryBuffer::getFile(Filename); if (!BufOrErr) - reportError(Filename, BufOrErr.getError()); + return createFileError(Filename, BufOrErr.getError()); BufOrErr.get()->getBuffer().split(Lines, '\n'); for (StringRef Line : Lines) { @@ -243,6 +261,8 @@ if (!TrimmedLine.empty()) Symbols.emplace_back(Saver.save(TrimmedLine), UseRegex); } + + return Error::success(); } NameOrRegex::NameOrRegex(StringRef Pattern, bool IsRegex) { @@ -285,7 +305,7 @@ // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. -DriverConfig parseObjcopyOptions(ArrayRef ArgsArr) { +Expected parseObjcopyOptions(ArrayRef ArgsArr) { DriverConfig DC; ObjcopyOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; @@ -311,16 +331,18 @@ SmallVector Positional; for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) - error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); + return createStringError(errc::invalid_argument, "unknown argument '%s'", + Arg->getAsString(InputArgs).c_str()); for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) Positional.push_back(Arg->getValue()); if (Positional.empty()) - error("No input file specified"); + return createStringError(errc::invalid_argument, "No input file specified"); if (Positional.size() > 2) - error("Too many positional arguments"); + return createStringError(errc::invalid_argument, + "Too many positional arguments"); CopyConfig Config; Config.InputFilename = Positional[0]; @@ -328,7 +350,9 @@ if (InputArgs.hasArg(OBJCOPY_target) && (InputArgs.hasArg(OBJCOPY_input_target) || InputArgs.hasArg(OBJCOPY_output_target))) - error("--target cannot be used with --input-target or --output-target"); + return createStringError( + errc::invalid_argument, + "--target cannot be used with --input-target or --output-target."); bool UseRegex = InputArgs.hasArg(OBJCOPY_regex); if (InputArgs.hasArg(OBJCOPY_target)) { @@ -341,11 +365,21 @@ if (Config.InputFormat == "binary") { auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); if (BinaryArch.empty()) - error("Specified binary input without specifiying an architecture"); - Config.BinaryArch = getMachineInfo(BinaryArch); + return createStringError( + errc::invalid_argument, + "Specified binary input without specifiying an architecture."); + Expected MI = getMachineInfo(BinaryArch); + if (!MI) + return MI.takeError(); + Config.BinaryArch = *MI; + } + if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary") { + Expected MI = + getOutputFormatMachineInfo(Config.OutputFormat); + if (!MI) + return MI.takeError(); + Config.OutputArch = *MI; } - if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary") - Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat); if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, OBJCOPY_compress_debug_sections_eq)) { @@ -359,10 +393,16 @@ .Case("zlib", DebugCompressionType::Z) .Default(DebugCompressionType::None); if (Config.CompressionType == DebugCompressionType::None) - error("Invalid or unsupported --compress-debug-sections format: " + - InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)); + return createStringError( + errc::invalid_argument, + "Invalid or unsupported --compress-debug-sections format: %s.", + InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq) + .str() + .c_str()); if (!zlib::isAvailable()) - error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress."); + return createStringError( + errc::invalid_argument, + "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress."); } } @@ -379,39 +419,57 @@ for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { if (!StringRef(Arg->getValue()).contains('=')) - error("Bad format for --redefine-sym"); + return createStringError(errc::invalid_argument, + "Bad format for --redefine-sym"); auto Old2New = StringRef(Arg->getValue()).split('='); if (!Config.SymbolsToRename.insert(Old2New).second) - error("Multiple redefinition of symbol " + Old2New.first); + return createStringError(errc::invalid_argument, + "Multiple redefinition of symbol %s", + Old2New.first.str().c_str()); } for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols)) if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc, Arg->getValue())) - error(std::move(E)); + return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) { - SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue())); - if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second) - error("Multiple renames of section " + SR.OriginalName); + Expected SR = + parseRenameSectionValue(StringRef(Arg->getValue())); + if (!SR) + return SR.takeError(); + if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second) + return createStringError(errc::invalid_argument, + "Multiple renames of section %s", + SR->OriginalName.str().c_str()); } for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) { - SectionFlagsUpdate SFU = parseSetSectionFlagValue(Arg->getValue()); - if (!Config.SetSectionFlags.try_emplace(SFU.Name, SFU).second) - error("--set-section-flags set multiple times for section " + SFU.Name); + Expected SFU = + parseSetSectionFlagValue(Arg->getValue()); + if (!SFU) + return SFU.takeError(); + if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second) + return createStringError( + errc::invalid_argument, + "--set-section-flags set multiple times for section %s", + SFU->Name.str().c_str()); } // Prohibit combinations of --set-section-flags when the section name is used // by --rename-section, either as a source or a destination. for (const auto &E : Config.SectionsToRename) { const SectionRename &SR = E.second; if (Config.SetSectionFlags.count(SR.OriginalName)) - error("--set-section-flags=" + SR.OriginalName + - " conflicts with --rename-section=" + SR.OriginalName + "=" + - SR.NewName); + return createStringError( + errc::invalid_argument, + "--set-section-flags=%s conflicts with --rename-section=%s=%s.", + SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(), + SR.NewName.str().c_str()); if (Config.SetSectionFlags.count(SR.NewName)) - error("--set-section-flags=" + SR.NewName + - " conflicts with --rename-section=" + SR.OriginalName + "=" + - SR.NewName); + return createStringError( + errc::invalid_argument, + "--set-section-flags=%s conflicts with --rename-section=%s=%s.", + SR.NewName.str().c_str(), SR.OriginalName.str().c_str(), + SR.NewName.str().c_str()); } for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) @@ -446,33 +504,39 @@ for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) Config.SymbolsToLocalize.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols)) - addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, Arg->getValue(), - UseRegex); + if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, + Arg->getValue(), UseRegex)) + return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) Config.SymbolsToKeepGlobal.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) - addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, Arg->getValue(), - UseRegex); + if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, + Arg->getValue(), UseRegex)) + return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) Config.SymbolsToGlobalize.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols)) - addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, Arg->getValue(), - UseRegex); + if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, + Arg->getValue(), UseRegex)) + return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) Config.SymbolsToWeaken.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols)) - addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, Arg->getValue(), - UseRegex); + if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, + Arg->getValue(), UseRegex)) + return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols)) - addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc, Arg->getValue(), - UseRegex); + if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc, + Arg->getValue(), UseRegex)) + return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol)) Config.UnneededSymbolsToRemove.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols)) - addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc, - Arg->getValue(), UseRegex); + if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc, + Arg->getValue(), UseRegex)) + return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegex); @@ -484,12 +548,16 @@ if (Config.DecompressDebugSections && Config.CompressionType != DebugCompressionType::None) { - error("Cannot specify --compress-debug-sections at the same time as " - "--decompress-debug-sections at the same time"); + return createStringError( + errc::invalid_argument, + "Cannot specify --compress-debug-sections at the same time as " + "--decompress-debug-sections at the same time."); } if (Config.DecompressDebugSections && !zlib::isAvailable()) - error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress."); + return createStringError( + errc::invalid_argument, + "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress."); DC.CopyConfigs.push_back(std::move(Config)); return DC; @@ -498,7 +566,7 @@ // ParseStripOptions returns the config and sets the input arguments. If a // help flag is set then ParseStripOptions will print the help messege and // exit. -DriverConfig parseStripOptions(ArrayRef ArgsArr) { +Expected parseStripOptions(ArrayRef ArgsArr) { StripOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; llvm::opt::InputArgList InputArgs = @@ -522,15 +590,18 @@ SmallVector Positional; for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN)) - error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); + return createStringError(errc::invalid_argument, "unknown argument '%s'", + Arg->getAsString(InputArgs).c_str()); for (auto Arg : InputArgs.filtered(STRIP_INPUT)) Positional.push_back(Arg->getValue()); if (Positional.empty()) - error("No input file specified"); + return createStringError(errc::invalid_argument, "No input file specified"); if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output)) - error("Multiple input files cannot be used in combination with -o"); + return createStringError( + errc::invalid_argument, + "Multiple input files cannot be used in combination with -o."); CopyConfig Config; bool UseRegexp = InputArgs.hasArg(STRIP_regex); diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -183,70 +183,86 @@ Config.DeterministicArchives, Ar.isThin()); } -static void restoreDateOnFile(StringRef Filename, - const sys::fs::file_status &Stat) { +static Error restoreDateOnFile(StringRef Filename, + const sys::fs::file_status &Stat) { int FD; if (auto EC = sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) - reportError(Filename, EC); + return createFileError(Filename, EC); if (auto EC = sys::fs::setLastAccessAndModificationTime( FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) - reportError(Filename, EC); + return createFileError(Filename, EC); if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) - reportError(Filename, EC); + return createFileError(Filename, EC); + + return Error::success(); } /// The function executeObjcopy does the higher level dispatch based on the type /// of input (raw binary, archive or single object file) and takes care of the /// format-agnostic modifications, i.e. preserving dates. -static void executeObjcopy(const CopyConfig &Config) { +static Error executeObjcopy(const CopyConfig &Config) { sys::fs::file_status Stat; if (Config.PreserveDates) if (auto EC = sys::fs::status(Config.InputFilename, Stat)) - reportError(Config.InputFilename, EC); + return createFileError(Config.InputFilename, EC); if (Config.InputFormat == "binary") { auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); if (!BufOrErr) - reportError(Config.InputFilename, BufOrErr.getError()); + return createFileError(Config.InputFilename, BufOrErr.getError()); FileBuffer FB(Config.OutputFilename); if (Error E = executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB)) - error(std::move(E)); + return E; } else { Expected> BinaryOrErr = createBinary(Config.InputFilename); if (!BinaryOrErr) - reportError(Config.InputFilename, BinaryOrErr.takeError()); + return createFileError(Config.InputFilename, BinaryOrErr.takeError()); if (Archive *Ar = dyn_cast(BinaryOrErr.get().getBinary())) { if (Error E = executeObjcopyOnArchive(Config, *Ar)) - error(std::move(E)); + return E; } else { FileBuffer FB(Config.OutputFilename); if (Error E = executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB)) - error(std::move(E)); + return E; } } if (Config.PreserveDates) { - restoreDateOnFile(Config.OutputFilename, Stat); + if (Error E = restoreDateOnFile(Config.OutputFilename, Stat)) + return E; if (!Config.SplitDWO.empty()) - restoreDateOnFile(Config.SplitDWO, Stat); + if (Error E = restoreDateOnFile(Config.SplitDWO, Stat)) + return E; } + + return Error::success(); } int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - DriverConfig DriverConfig; - if (sys::path::stem(ToolName).contains("strip")) - DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc)); - else - DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc)); - for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs) - executeObjcopy(CopyConfig); + bool IsStrip = sys::path::stem(ToolName).contains("strip"); + Expected DriverConfig = + IsStrip ? parseStripOptions(makeArrayRef(argv + 1, argc)) + : parseObjcopyOptions(makeArrayRef(argv + 1, argc)); + if (!DriverConfig) { + logAllUnhandledErrors(DriverConfig.takeError(), + WithColor::error(errs(), ToolName)); + return 1; + } + for (const CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { + if (Error E = executeObjcopy(CopyConfig)) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); + return 1; + } + } + + return 0; }