diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt --- a/llvm/tools/llvm-objcopy/CMakeLists.txt +++ b/llvm/tools/llvm-objcopy/CMakeLists.txt @@ -22,13 +22,12 @@ add_public_tablegen_target(StripOptsTableGen) add_llvm_tool(llvm-objcopy - CopyConfig.cpp + ConfigManager.cpp llvm-objcopy.cpp COFF/COFFObjcopy.cpp COFF/Object.cpp COFF/Reader.cpp COFF/Writer.cpp - ELF/ELFConfig.cpp ELF/ELFObjcopy.cpp ELF/Object.cpp MachO/MachOObjcopy.cpp diff --git a/llvm/tools/llvm-objcopy/COFF/COFFConfig.h b/llvm/tools/llvm-objcopy/COFF/COFFConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/COFF/COFFConfig.h @@ -0,0 +1,21 @@ +//===- COFFConfig.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COFFCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_COFFCONFIG_H + +namespace llvm { +namespace objcopy { + +// Coff specific configuration for copying/stripping a single file. +struct COFFConfig {}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_COFFCONFIG_H diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h +++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h @@ -18,10 +18,12 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CommonConfig; +struct COFFConfig; namespace coff { -Error executeObjcopyOnBinary(const CopyConfig &Config, + +Error executeObjcopyOnBinary(const CommonConfig &Config, const COFFConfig &, object::COFFObjectFile &In, raw_ostream &Out); } // end namespace coff diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -7,7 +7,8 @@ //===----------------------------------------------------------------------===// #include "COFFObjcopy.h" -#include "CopyConfig.h" +#include "COFFConfig.h" +#include "CommonConfig.h" #include "Object.h" #include "Reader.h" #include "Writer.h" @@ -130,7 +131,7 @@ Sec.Header.Characteristics = NewCharacteristics; } -static Error handleArgs(const CopyConfig &Config, Object &Obj) { +static Error handleArgs(const CommonConfig &Config, Object &Obj) { // Perform the actual section removals. Obj.removeSections([&Config](const Section &Sec) { // Contrary to --only-keep-debug, --only-section fully removes sections that @@ -248,28 +249,11 @@ if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink)) return E; - if (Config.AllowBrokenLinks || !Config.SplitDWO.empty() || - !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() || - !Config.DumpSection.empty() || !Config.KeepSection.empty() || - Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() || - !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || - !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || - !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() || - Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates || - Config.StripDWO || Config.StripNonAlloc || Config.StripSections || - Config.StripSwiftSymbols || Config.KeepUndefined || Config.Weaken || - Config.DecompressDebugSections || - Config.DiscardMode == DiscardType::Locals || - !Config.SymbolsToAdd.empty() || Config.EntryExpr) { - return createStringError(llvm::errc::invalid_argument, - "option not supported by llvm-objcopy for COFF"); - } - return Error::success(); } -Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In, - raw_ostream &Out) { +Error executeObjcopyOnBinary(const CommonConfig &Config, const COFFConfig &, + COFFObjectFile &In, raw_ostream &Out) { COFFReader Reader(In); Expected> ObjOrErr = Reader.create(); if (!ObjOrErr) diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CommonConfig.h rename from llvm/tools/llvm-objcopy/CopyConfig.h rename to llvm/tools/llvm-objcopy/CommonConfig.h --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CommonConfig.h @@ -1,4 +1,4 @@ -//===- CopyConfig.h -------------------------------------------------------===// +//===- CommonConfig.h -------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,20 +6,16 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H -#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COMMONCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_COMMONCONFIG_H -#include "ELF/ELFConfig.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELFTypes.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Error.h" #include "llvm/Support/GlobPattern.h" #include "llvm/Support/Regex.h" // Necessary for llvm::DebugCompressionType::None @@ -99,7 +95,7 @@ class NameOrPattern { StringRef Name; - // Regex is shared between multiple CopyConfig instances. + // Regex is shared between multiple CommonConfig instances. std::shared_ptr R; std::shared_ptr G; bool IsPositiveMatch = true; @@ -146,10 +142,7 @@ }; // Configuration for copying/stripping a single file. -struct CopyConfig { - // Format-specific options to be initialized lazily when needed. - Optional ELF; - +struct CommonConfig { // Main input/output options StringRef InputFilename; FileFormat InputFormat = FileFormat::Unspecified; @@ -168,12 +161,10 @@ StringRef SymbolsPrefix; StringRef AllocSectionsPrefix; DiscardType DiscardMode = DiscardType::None; - Optional NewSymbolVisibility; // Repeated options std::vector AddSection; std::vector DumpSection; - std::vector SymbolsToAdd; std::vector RPathToAdd; std::vector RPathToPrepend; DenseMap RPathsToUpdate; @@ -233,55 +224,9 @@ bool RemoveAllRpaths = false; DebugCompressionType CompressionType = DebugCompressionType::None; - - // parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on - // success or returns an Error otherwise. - Error parseELFConfig() { - if (!ELF) { - Expected ELFConfig = elf::parseConfig(*this); - if (!ELFConfig) - return ELFConfig.takeError(); - ELF = *ELFConfig; - } - return Error::success(); - } }; -// Configuration for the overall invocation of this tool. When invoked as -// objcopy, will always contain exactly one CopyConfig. When invoked as strip, -// will contain one or more CopyConfigs. -struct DriverConfig { - SmallVector CopyConfigs; - BumpPtrAllocator Alloc; -}; - -// ParseObjcopyOptions returns the config and sets the input arguments. If a -// help flag is set then ParseObjcopyOptions will print the help messege and -// exit. ErrorCallback is used to handle recoverable errors. An Error returned -// by the callback aborts the parsing and is then returned by this function. -Expected -parseObjcopyOptions(ArrayRef ArgsArr, - llvm::function_ref ErrorCallback); - -// ParseInstallNameToolOptions returns the config and sets the input arguments. -// If a help flag is set then ParseInstallNameToolOptions will print the help -// messege and exit. -Expected -parseInstallNameToolOptions(ArrayRef ArgsArr); - -// ParseBitcodeStripOptions returns the config and sets the input arguments. -// If a help flag is set then ParseBitcodeStripOptions will print the help -// messege and exit. -Expected parseBitcodeStripOptions(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. ErrorCallback is used to handle recoverable errors. An Error returned -// by the callback aborts the parsing and is then returned by this function. -Expected -parseStripOptions(ArrayRef ArgsArr, - llvm::function_ref ErrorCallback); } // namespace objcopy } // namespace llvm -#endif +#endif // LLVM_TOOLS_LLVM_OBJCOPY_COMMONCONFIG_H diff --git a/llvm/tools/llvm-objcopy/ConfigManager.h b/llvm/tools/llvm-objcopy/ConfigManager.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/ConfigManager.h @@ -0,0 +1,84 @@ +//===- ConfigManager.h ----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_CONFIGMANAGER_H +#define LLVM_TOOLS_LLVM_OBJCOPY_CONFIGMANAGER_H + +#include "COFF/COFFConfig.h" +#include "CommonConfig.h" +#include "ELF/ELFConfig.h" +#include "MachO/MachOConfig.h" +#include "MultiFormatConfig.h" +#include "wasm/WasmConfig.h" +#include "llvm/Support/Allocator.h" +#include + +namespace llvm { +namespace objcopy { + +// ConfigManager keeps all configurations and prepare +// format-specific options. +struct ConfigManager : public MultiFormatConfig { + virtual ~ConfigManager() {} + + const CommonConfig &getCommonConfig() const override { return Common; } + Expected getELFConfig() const override; + Expected getCOFFConfig() const override; + Expected getMachOConfig() const override; + Expected getWasmConfig() const override; + + // String representation for lazy Elf options. + std::vector SymbolsToAdd; + Optional NewSymbolVisibility; + + // All configs. + CommonConfig Common; + mutable Optional ELF; + COFFConfig COFF; + MachOConfig MachO; + WasmConfig Wasm; +}; + +// Configuration for the overall invocation of this tool. When invoked as +// objcopy, will always contain exactly one CopyConfig. When invoked as strip, +// will contain one or more CopyConfigs. +struct DriverConfig { + SmallVector CopyConfigs; + BumpPtrAllocator Alloc; +}; + +// ParseObjcopyOptions returns the config and sets the input arguments. If a +// help flag is set then ParseObjcopyOptions will print the help messege and +// exit. ErrorCallback is used to handle recoverable errors. An Error returned +// by the callback aborts the parsing and is then returned by this function. +Expected +parseObjcopyOptions(ArrayRef ArgsArr, + llvm::function_ref ErrorCallback); + +// ParseInstallNameToolOptions returns the config and sets the input arguments. +// If a help flag is set then ParseInstallNameToolOptions will print the help +// messege and exit. +Expected +parseInstallNameToolOptions(ArrayRef ArgsArr); + +// ParseBitcodeStripOptions returns the config and sets the input arguments. +// If a help flag is set then ParseBitcodeStripOptions will print the help +// messege and exit. +Expected parseBitcodeStripOptions(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. ErrorCallback is used to handle recoverable errors. An Error returned +// by the callback aborts the parsing and is then returned by this function. +Expected +parseStripOptions(ArrayRef ArgsArr, + llvm::function_ref ErrorCallback); +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_CONFIGMANAGER_H diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/ConfigManager.cpp rename from llvm/tools/llvm-objcopy/CopyConfig.cpp rename to llvm/tools/llvm-objcopy/ConfigManager.cpp --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/ConfigManager.cpp @@ -1,4 +1,4 @@ -//===- CopyConfig.cpp -----------------------------------------------------===// +//===- ConfigManager.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "CopyConfig.h" - +#include "ConfigManager.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -18,6 +17,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/StringSaver.h" #include @@ -466,6 +466,190 @@ OS << "\nPass @FILE as argument to read options from FILE.\n"; } +static Expected parseNewSymbolInfo(StringRef FlagValue, + uint8_t DefaultVisibility) { + // Parse value given with --add-symbol option and create the + // new symbol if possible. The value format for --add-symbol is: + // + // =[
:][,] + // + // where: + // - symbol name, can be empty string + //
- optional section name. If not given ABS symbol is created + // - symbol value, can be decimal or hexadecimal number prefixed + // with 0x. + // - optional flags affecting symbol type, binding or visibility: + // The following are currently supported: + // + // global, local, weak, default, hidden, file, section, object, + // indirect-function. + // + // The following flags are ignored and provided for GNU + // compatibility only: + // + // warning, debug, constructor, indirect, synthetic, + // unique-object, before=. + NewSymbolInfo SI; + StringRef Value; + std::tie(SI.SymbolName, Value) = FlagValue.split('='); + if (Value.empty()) + return createStringError( + errc::invalid_argument, + "bad format for --add-symbol, missing '=' after '%s'", + SI.SymbolName.str().c_str()); + + if (Value.contains(':')) { + std::tie(SI.SectionName, Value) = Value.split(':'); + if (SI.SectionName.empty() || Value.empty()) + return createStringError( + errc::invalid_argument, + "bad format for --add-symbol, missing section name or symbol value"); + } + + SmallVector Flags; + Value.split(Flags, ','); + if (Flags[0].getAsInteger(0, SI.Value)) + return createStringError(errc::invalid_argument, "bad symbol value: '%s'", + Flags[0].str().c_str()); + + SI.Visibility = DefaultVisibility; + using Functor = std::function; + SmallVector UnsupportedFlags; + for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) + static_cast( + StringSwitch(Flags[I]) + .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; }) + .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; }) + .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; }) + .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; }) + .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; }) + .CaseLower("protected", + [&SI] { SI.Visibility = ELF::STV_PROTECTED; }) + .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; }) + .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; }) + .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; }) + .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; }) + .CaseLower("indirect-function", + [&SI] { SI.Type = ELF::STT_GNU_IFUNC; }) + .CaseLower("debug", [] {}) + .CaseLower("constructor", [] {}) + .CaseLower("warning", [] {}) + .CaseLower("indirect", [] {}) + .CaseLower("synthetic", [] {}) + .CaseLower("unique-object", [] {}) + .StartsWithLower("before", [] {}) + .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); + if (!UnsupportedFlags.empty()) + return createStringError(errc::invalid_argument, + "unsupported flag%s for --add-symbol: '%s'", + UnsupportedFlags.size() > 1 ? "s" : "", + join(UnsupportedFlags, "', '").c_str()); + return SI; +} + +Expected ConfigManager::getELFConfig() const { + if (!ELF) { + if (Common.StripSwiftSymbols || Common.KeepUndefined) + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for ELF"); + + // Parse lazy options. + ELFConfig ResConfig; + + if (NewSymbolVisibility) { + const uint8_t Invalid = 0xff; + ResConfig.NewSymbolVisibility = + StringSwitch(*NewSymbolVisibility) + .Case("default", ELF::STV_DEFAULT) + .Case("hidden", ELF::STV_HIDDEN) + .Case("internal", ELF::STV_INTERNAL) + .Case("protected", ELF::STV_PROTECTED) + .Default(Invalid); + + if (ResConfig.NewSymbolVisibility == Invalid) + return createStringError(errc::invalid_argument, + "'%s' is not a valid symbol visibility", + NewSymbolVisibility->str().c_str()); + } + + for (StringRef Arg : SymbolsToAdd) { + Expected NSI = parseNewSymbolInfo( + Arg, + ResConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); + if (!NSI) + return NSI.takeError(); + ResConfig.SymbolsToAdd.push_back(*NSI); + } + + ELF = std::move(ResConfig); + } + + return *ELF; +} + +Expected ConfigManager::getCOFFConfig() const { + if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() || + !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() || + !Common.DumpSection.empty() || !Common.KeepSection.empty() || + NewSymbolVisibility || !Common.SymbolsToGlobalize.empty() || + !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() || + !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() || + !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() || + Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates || + Common.StripDWO || Common.StripNonAlloc || Common.StripSections || + Common.StripSwiftSymbols || Common.KeepUndefined || Common.Weaken || + Common.DecompressDebugSections || + Common.DiscardMode == DiscardType::Locals || !SymbolsToAdd.empty() || + Common.EntryExpr) { + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for COFF"); + } + + return COFF; +} + +Expected ConfigManager::getMachOConfig() const { + if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() || + !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() || + !Common.KeepSection.empty() || NewSymbolVisibility || + !Common.SymbolsToGlobalize.empty() || !Common.SymbolsToKeep.empty() || + !Common.SymbolsToLocalize.empty() || !Common.SymbolsToWeaken.empty() || + !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() || + !Common.UnneededSymbolsToRemove.empty() || + !Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() || + Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates || + Common.StripAllGNU || Common.StripDWO || Common.StripNonAlloc || + Common.StripSections || Common.Weaken || Common.DecompressDebugSections || + Common.StripUnneeded || Common.DiscardMode == DiscardType::Locals || + !SymbolsToAdd.empty() || Common.EntryExpr) { + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for MachO"); + } + + return MachO; +} + +Expected ConfigManager::getWasmConfig() const { + if (!Common.AddGnuDebugLink.empty() || Common.ExtractPartition || + !Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() || + !Common.AllocSectionsPrefix.empty() || + Common.DiscardMode != DiscardType::None || NewSymbolVisibility || + !SymbolsToAdd.empty() || !Common.RPathToAdd.empty() || + !Common.OnlySection.empty() || !Common.SymbolsToGlobalize.empty() || + !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() || + !Common.SymbolsToRemove.empty() || + !Common.UnneededSymbolsToRemove.empty() || + !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() || + !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() || + !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty()) { + return createStringError( + llvm::errc::invalid_argument, + "only add-section, dump-section, and remove-section are supported"); + } + + return Wasm; +} + // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. @@ -510,7 +694,8 @@ return createStringError(errc::invalid_argument, "too many positional arguments"); - CopyConfig Config; + ConfigManager ConfigMgr; + CommonConfig &Config = ConfigMgr.Common; Config.InputFilename = Positional[0]; Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; if (InputArgs.hasArg(OBJCOPY_target) && @@ -550,7 +735,7 @@ .Default(FileFormat::Unspecified); if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) - Config.NewSymbolVisibility = + ConfigMgr.NewSymbolVisibility = InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility); Config.OutputFormat = StringSwitch(OutputFormat) @@ -799,7 +984,7 @@ SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) - Config.SymbolsToAdd.push_back(Arg->getValue()); + ConfigMgr.SymbolsToAdd.push_back(Arg->getValue()); Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); @@ -853,7 +1038,7 @@ "cannot specify --extract-partition together with " "--extract-main-partition"); - DC.CopyConfigs.push_back(std::move(Config)); + DC.CopyConfigs.push_back(std::move(ConfigMgr)); return std::move(DC); } @@ -863,7 +1048,8 @@ Expected parseInstallNameToolOptions(ArrayRef ArgsArr) { DriverConfig DC; - CopyConfig Config; + ConfigManager ConfigMgr; + CommonConfig &Config = ConfigMgr.Common; InstallNameToolOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; llvm::opt::InputArgList InputArgs = @@ -987,14 +1173,15 @@ Config.InputFilename = Positional[0]; Config.OutputFilename = Positional[0]; - DC.CopyConfigs.push_back(std::move(Config)); + DC.CopyConfigs.push_back(std::move(ConfigMgr)); return std::move(DC); } Expected parseBitcodeStripOptions(ArrayRef ArgsArr) { DriverConfig DC; - CopyConfig Config; + ConfigManager ConfigMgr; + CommonConfig &Config = ConfigMgr.Common; BitcodeStripOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; opt::InputArgList InputArgs = @@ -1031,7 +1218,7 @@ Config.InputFilename = Positional[0]; Config.OutputFilename = Positional[0]; - DC.CopyConfigs.push_back(std::move(Config)); + DC.CopyConfigs.push_back(std::move(ConfigMgr)); return std::move(DC); } @@ -1077,7 +1264,8 @@ errc::invalid_argument, "multiple input files cannot be used in combination with -o"); - CopyConfig Config; + ConfigManager ConfigMgr; + CommonConfig &Config = ConfigMgr.Common; if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard)) return createStringError(errc::invalid_argument, @@ -1150,7 +1338,7 @@ Config.InputFilename = Positional[0]; Config.OutputFilename = InputArgs.getLastArgValue(STRIP_output, Positional[0]); - DC.CopyConfigs.push_back(std::move(Config)); + DC.CopyConfigs.push_back(std::move(ConfigMgr)); } else { StringMap InputFiles; for (StringRef Filename : Positional) { @@ -1166,7 +1354,7 @@ } Config.InputFilename = Filename; Config.OutputFilename = Filename; - DC.CopyConfigs.push_back(Config); + DC.CopyConfigs.push_back(ConfigMgr); } } diff --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h --- a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h +++ b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h @@ -1,4 +1,4 @@ -//===- ELFConfig.h ----------------------------------------------*- C++ -*-===// +//===- ElfConfig.h ----------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,20 +6,16 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_OBJCOPY_ELFCONFIG_H -#define LLVM_TOOLS_OBJCOPY_ELFCONFIG_H +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELFTypes.h" -#include "llvm/Support/Error.h" #include namespace llvm { namespace objcopy { -struct CopyConfig; - -namespace elf { struct NewSymbolInfo { StringRef SymbolName; @@ -30,15 +26,13 @@ uint8_t Visibility = ELF::STV_DEFAULT; }; -struct ELFCopyConfig { +// ELF specific configuration for copying/stripping a single file. +struct ELFConfig { Optional NewSymbolVisibility; std::vector SymbolsToAdd; }; -Expected parseConfig(const CopyConfig &Config); - -} // namespace elf } // namespace objcopy } // namespace llvm -#endif +#endif // LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H diff --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp b/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp deleted file mode 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp +++ /dev/null @@ -1,133 +0,0 @@ -//===- ELFConfig.cpp ------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "CopyConfig.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Error.h" - -namespace llvm { -namespace objcopy { -namespace elf { - -static Expected parseNewSymbolInfo(StringRef FlagValue, - uint8_t DefaultVisibility) { - // Parse value given with --add-symbol option and create the - // new symbol if possible. The value format for --add-symbol is: - // - // =[
:][,] - // - // where: - // - symbol name, can be empty string - //
- optional section name. If not given ABS symbol is created - // - symbol value, can be decimal or hexadecimal number prefixed - // with 0x. - // - optional flags affecting symbol type, binding or visibility: - // The following are currently supported: - // - // global, local, weak, default, hidden, file, section, object, - // indirect-function. - // - // The following flags are ignored and provided for GNU - // compatibility only: - // - // warning, debug, constructor, indirect, synthetic, - // unique-object, before=. - NewSymbolInfo SI; - StringRef Value; - std::tie(SI.SymbolName, Value) = FlagValue.split('='); - if (Value.empty()) - return createStringError( - errc::invalid_argument, - "bad format for --add-symbol, missing '=' after '%s'", - SI.SymbolName.str().c_str()); - - if (Value.contains(':')) { - std::tie(SI.SectionName, Value) = Value.split(':'); - if (SI.SectionName.empty() || Value.empty()) - return createStringError( - errc::invalid_argument, - "bad format for --add-symbol, missing section name or symbol value"); - } - - SmallVector Flags; - Value.split(Flags, ','); - if (Flags[0].getAsInteger(0, SI.Value)) - return createStringError(errc::invalid_argument, "bad symbol value: '%s'", - Flags[0].str().c_str()); - - SI.Visibility = DefaultVisibility; - - using Functor = std::function; - SmallVector UnsupportedFlags; - for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) - static_cast( - StringSwitch(Flags[I]) - .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; }) - .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; }) - .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; }) - .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; }) - .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; }) - .CaseLower("protected", - [&SI] { SI.Visibility = ELF::STV_PROTECTED; }) - .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; }) - .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; }) - .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; }) - .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; }) - .CaseLower("indirect-function", - [&SI] { SI.Type = ELF::STT_GNU_IFUNC; }) - .CaseLower("debug", [] {}) - .CaseLower("constructor", [] {}) - .CaseLower("warning", [] {}) - .CaseLower("indirect", [] {}) - .CaseLower("synthetic", [] {}) - .CaseLower("unique-object", [] {}) - .StartsWithLower("before", [] {}) - .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); - if (!UnsupportedFlags.empty()) - return createStringError(errc::invalid_argument, - "unsupported flag%s for --add-symbol: '%s'", - UnsupportedFlags.size() > 1 ? "s" : "", - join(UnsupportedFlags, "', '").c_str()); - return SI; -} - -Expected parseConfig(const CopyConfig &Config) { - ELFCopyConfig ELFConfig; - if (Config.NewSymbolVisibility) { - const uint8_t Invalid = 0xff; - ELFConfig.NewSymbolVisibility = - StringSwitch(*Config.NewSymbolVisibility) - .Case("default", ELF::STV_DEFAULT) - .Case("hidden", ELF::STV_HIDDEN) - .Case("internal", ELF::STV_INTERNAL) - .Case("protected", ELF::STV_PROTECTED) - .Default(Invalid); - - if (ELFConfig.NewSymbolVisibility == Invalid) - return createStringError(errc::invalid_argument, - "'%s' is not a valid symbol visibility", - Config.NewSymbolVisibility->str().c_str()); - } - - for (StringRef Arg : Config.SymbolsToAdd) { - Expected NSI = parseNewSymbolInfo( - Arg, - ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); - if (!NSI) - return NSI.takeError(); - ELFConfig.SymbolsToAdd.push_back(*NSI); - } - - return ELFConfig; -} - -} // end namespace elf -} // end namespace objcopy -} // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h @@ -19,14 +19,18 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CommonConfig; +struct ELFConfig; namespace elf { -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CommonConfig &Config, + const ELFConfig &ELFConfig, MemoryBuffer &In, raw_ostream &Out); -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnRawBinary(const CommonConfig &Config, + const ELFConfig &ELFConfig, MemoryBuffer &In, raw_ostream &Out); -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &Config, + const ELFConfig &ELFConfig, object::ELFObjectFileBase &In, raw_ostream &Out); } // end namespace elf diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -7,7 +7,8 @@ //===----------------------------------------------------------------------===// #include "ELFObjcopy.h" -#include "CopyConfig.h" +#include "CommonConfig.h" +#include "ELFConfig.h" #include "Object.h" #include "llvm-objcopy.h" #include "llvm/ADT/BitmaskEnum.h" @@ -132,7 +133,7 @@ return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; } -static std::unique_ptr createELFWriter(const CopyConfig &Config, +static std::unique_ptr createELFWriter(const CommonConfig &Config, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { // Depending on the initial ELFT and OutputFormat we need a different Writer. @@ -153,7 +154,7 @@ llvm_unreachable("Invalid output format"); } -static std::unique_ptr createWriter(const CopyConfig &Config, +static std::unique_ptr createWriter(const CommonConfig &Config, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { switch (Config.OutputFormat) { @@ -243,7 +244,7 @@ Sym.Type != STT_SECTION; } -static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { +static Error updateAndRemoveSymbols(const CommonConfig &Config, Object &Obj) { // TODO: update or remove symbols only if there is an option that affects // them. if (!Obj.SymbolTable) @@ -338,7 +339,7 @@ return Obj.removeSymbols(RemoveSymbolsPred); } -static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { +static Error replaceAndRemoveSections(const CommonConfig &Config, Object &Obj) { SectionPred RemovePred = [](const SectionBase &) { return false; }; // Removes: @@ -506,11 +507,8 @@ // any previous removals. Lastly whether or not something is removed shouldn't // depend a) on the order the options occur in or b) on some opaque priority // system. The only priority is that keeps/copies overrule removes. -static Error handleArgs(const CopyConfig &Config, Object &Obj) { - if (Config.StripSwiftSymbols || Config.KeepUndefined) - return createStringError(llvm::errc::invalid_argument, - "option not supported by llvm-objcopy for ELF"); - +static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, + Object &Obj) { if (Config.OutputArch) { Obj.Machine = Config.OutputArch.getValue().EMachine; Obj.OSABI = Config.OutputArch.getValue().OSABI; @@ -635,11 +633,11 @@ // If the symbol table was previously removed, we need to create a new one // before adding new symbols. - if (!Obj.SymbolTable && !Config.ELF->SymbolsToAdd.empty()) + if (!Obj.SymbolTable && !ELFConfig.SymbolsToAdd.empty()) if (Error E = Obj.addNewSymbolTable()) return E; - for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) { + for (const NewSymbolInfo &SI : ELFConfig.SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; Obj.SymbolTable->addSymbol( @@ -663,7 +661,7 @@ return Error::success(); } -static Error writeOutput(const CopyConfig &Config, Object &Obj, +static Error writeOutput(const CommonConfig &Config, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { std::unique_ptr Writer = createWriter(Config, Obj, Out, OutputElfType); @@ -672,7 +670,8 @@ return Writer->write(); } -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CommonConfig &Config, + const ELFConfig &ELFConfig, MemoryBuffer &In, raw_ostream &Out) { IHexReader Reader(&In); Expected> Obj = Reader.create(true); @@ -681,15 +680,16 @@ const ElfType OutputElfType = getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); - if (Error E = handleArgs(Config, **Obj)) + if (Error E = handleArgs(Config, ELFConfig, **Obj)) return E; return writeOutput(Config, **Obj, Out, OutputElfType); } -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnRawBinary(const CommonConfig &Config, + const ELFConfig &ELFConfig, MemoryBuffer &In, raw_ostream &Out) { uint8_t NewSymbolVisibility = - Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); + ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); BinaryReader Reader(&In, NewSymbolVisibility); Expected> Obj = Reader.create(true); if (!Obj) @@ -699,16 +699,17 @@ // (-B). const ElfType OutputElfType = getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); - if (Error E = handleArgs(Config, **Obj)) + if (Error E = handleArgs(Config, ELFConfig, **Obj)) return E; return writeOutput(Config, **Obj, Out, OutputElfType); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &Config, + const ELFConfig &ElfConfig, object::ELFObjectFileBase &In, raw_ostream &Out) { ELFReader Reader(&In, Config.ExtractPartition); Expected> Obj = - Reader.create(!Config.SymbolsToAdd.empty()); + Reader.create(!ElfConfig.SymbolsToAdd.empty()); if (!Obj) return Obj.takeError(); // Prefer OutputArch (-O) if set, otherwise infer it from the input. @@ -716,7 +717,7 @@ Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) : getOutputElfType(In); - if (Error E = handleArgs(Config, **Obj)) + if (Error E = handleArgs(Config, ElfConfig, **Obj)) return createFileError(Config.InputFilename, std::move(E)); if (Error E = writeOutput(Config, **Obj, Out, OutputElfType)) diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h --- a/llvm/tools/llvm-objcopy/ELF/Object.h +++ b/llvm/tools/llvm-objcopy/ELF/Object.h @@ -9,7 +9,7 @@ #ifndef LLVM_TOOLS_OBJCOPY_OBJECT_H #define LLVM_TOOLS_OBJCOPY_OBJECT_H -#include "CopyConfig.h" +#include "CommonConfig.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" diff --git a/llvm/tools/llvm-objcopy/MachO/MachOConfig.h b/llvm/tools/llvm-objcopy/MachO/MachOConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MachO/MachOConfig.h @@ -0,0 +1,21 @@ +//===- MachOConfig.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_MACHOCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_MACHOCONFIG_H + +namespace llvm { +namespace objcopy { + +// Mach-O specific configuration for copying/stripping a single file. +struct MachOConfig {}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_MACHOCONFIG_H diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h @@ -19,15 +19,16 @@ } // end namespace object namespace objcopy { -struct CopyConfig; -class Buffer; +struct CommonConfig; +struct MachOConfig; +class MultiFormatConfig; namespace macho { -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &, object::MachOObjectFile &In, raw_ostream &Out); Error executeObjcopyOnMachOUniversalBinary( - CopyConfig &Config, const object::MachOUniversalBinary &In, + const MultiFormatConfig &Config, const object::MachOUniversalBinary &In, raw_ostream &Out); } // end namespace macho diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -7,10 +7,11 @@ //===----------------------------------------------------------------------===// #include "MachOObjcopy.h" -#include "../CopyConfig.h" #include "../llvm-objcopy.h" +#include "CommonConfig.h" #include "MachOReader.h" #include "MachOWriter.h" +#include "MultiFormatConfig.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/MachOUniversal.h" @@ -48,7 +49,7 @@ .rtrim('\0'); } -static Error removeSections(const CopyConfig &Config, Object &Obj) { +static Error removeSections(const CommonConfig &Config, Object &Obj) { SectionPred RemovePred = [](const std::unique_ptr
&) { return false; }; @@ -79,14 +80,14 @@ return Obj.removeSections(RemovePred); } -static void markSymbols(const CopyConfig &Config, Object &Obj) { +static void markSymbols(const CommonConfig &, Object &Obj) { // Symbols referenced from the indirect symbol table must not be removed. for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols) if (ISE.Symbol) (*ISE.Symbol)->Referenced = true; } -static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { +static void updateAndRemoveSymbols(const CommonConfig &Config, Object &Obj) { for (SymbolEntry &Sym : Obj.SymTable) { auto I = Config.SymbolsToRename.find(Sym.Name); if (I != Config.SymbolsToRename.end()) @@ -136,7 +137,7 @@ return LC; } -static Error processLoadCommands(const CopyConfig &Config, Object &Obj) { +static Error processLoadCommands(const CommonConfig &Config, Object &Obj) { // Remove RPaths. DenseSet RPathsToRemove(Config.RPathsToRemove.begin(), Config.RPathsToRemove.end()); @@ -330,24 +331,7 @@ return Error::success(); } -static Error handleArgs(const CopyConfig &Config, Object &Obj) { - if (Config.AllowBrokenLinks || !Config.SplitDWO.empty() || - !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() || - !Config.KeepSection.empty() || Config.NewSymbolVisibility || - !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() || - !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || - !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || - !Config.UnneededSymbolsToRemove.empty() || - !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() || - Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates || - Config.StripAllGNU || Config.StripDWO || Config.StripNonAlloc || - Config.StripSections || Config.Weaken || Config.DecompressDebugSections || - Config.StripUnneeded || Config.DiscardMode == DiscardType::Locals || - !Config.SymbolsToAdd.empty() || Config.EntryExpr) { - return createStringError(llvm::errc::invalid_argument, - "option not supported by llvm-objcopy for MachO"); - } - +static Error handleArgs(const CommonConfig &Config, Object &Obj) { // Dump sections before add/remove for compatibility with GNU objcopy. for (StringRef Flag : Config.DumpSection) { StringRef SectionName; @@ -387,7 +371,7 @@ return Error::success(); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &, object::MachOObjectFile &In, raw_ostream &Out) { MachOReader Reader(In); Expected> O = Reader.create(); @@ -416,7 +400,7 @@ return Writer.write(); } -Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config, +Error executeObjcopyOnMachOUniversalBinary(const MultiFormatConfig &Config, const MachOUniversalBinary &In, raw_ostream &Out) { SmallVector, 2> Binaries; @@ -431,7 +415,7 @@ Expected> OutputBufferOrErr = writeArchiveToBuffer(*NewArchiveMembersOrErr, (*ArOrErr)->hasSymbolTable(), (*ArOrErr)->kind(), - Config.DeterministicArchives, + Config.getCommonConfig().DeterministicArchives, (*ArOrErr)->isThin()); if (!OutputBufferOrErr) return OutputBufferOrErr.takeError(); @@ -455,18 +439,24 @@ Expected> ObjOrErr = O.getAsObjectFile(); if (!ObjOrErr) { consumeError(ObjOrErr.takeError()); - return createStringError(std::errc::invalid_argument, - "slice for '%s' of the universal Mach-O binary " - "'%s' is not a Mach-O object or an archive", - O.getArchFlagName().c_str(), - Config.InputFilename.str().c_str()); + return createStringError( + std::errc::invalid_argument, + "slice for '%s' of the universal Mach-O binary " + "'%s' is not a Mach-O object or an archive", + O.getArchFlagName().c_str(), + Config.getCommonConfig().InputFilename.str().c_str()); } std::string ArchFlagName = O.getArchFlagName(); SmallVector Buffer; raw_svector_ostream MemStream(Buffer); - if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MemStream)) + Expected MachO = Config.getMachOConfig(); + if (!MachO) + return MachO.takeError(); + + if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, + **ObjOrErr, MemStream)) return E; std::unique_ptr MB = diff --git a/llvm/tools/llvm-objcopy/MultiFormatConfig.h b/llvm/tools/llvm-objcopy/MultiFormatConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MultiFormatConfig.h @@ -0,0 +1,37 @@ +//===- MultiFormatConfig.h ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace objcopy { + +struct CommonConfig; +struct ELFConfig; +struct COFFConfig; +struct MachOConfig; +struct WasmConfig; + +class MultiFormatConfig { +public: + virtual ~MultiFormatConfig() {} + + virtual const CommonConfig &getCommonConfig() const = 0; + virtual Expected getELFConfig() const = 0; + virtual Expected getCOFFConfig() const = 0; + virtual Expected getMachOConfig() const = 0; + virtual Expected getWasmConfig() const = 0; +}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.h b/llvm/tools/llvm-objcopy/llvm-objcopy.h --- a/llvm/tools/llvm-objcopy/llvm-objcopy.h +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.h @@ -23,9 +23,10 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +class MultiFormatConfig; Expected> -createNewArchiveMembers(CopyConfig &Config, const object::Archive &Ar); +createNewArchiveMembers(const MultiFormatConfig &Config, + const object::Archive &Ar); } // end namespace objcopy } // end namespace llvm 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 @@ -7,10 +7,15 @@ //===----------------------------------------------------------------------===// #include "llvm-objcopy.h" +#include "COFF/COFFConfig.h" #include "COFF/COFFObjcopy.h" -#include "CopyConfig.h" +#include "CommonConfig.h" +#include "ConfigManager.h" +#include "ELF/ELFConfig.h" #include "ELF/ELFObjcopy.h" +#include "MachO/MachOConfig.h" #include "MachO/MachOObjcopy.h" +#include "wasm/WasmConfig.h" #include "wasm/WasmObjcopy.h" #include "llvm/ADT/STLExtras.h" @@ -133,19 +138,22 @@ /// The function executeObjcopyOnIHex does the dispatch based on the format /// of the output specified by the command line options. -static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In, +static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In, raw_ostream &Out) { // TODO: support output formats other than ELF. - if (Error E = Config.parseELFConfig()) - return E; - return elf::executeObjcopyOnIHex(Config, In, Out); + Expected ELFConfig = ConfigMgr.getELFConfig(); + if (!ELFConfig) + return ELFConfig.takeError(); + + return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In, + Out); } /// The function executeObjcopyOnRawBinary does the dispatch based on the format /// of the output specified by the command line options. -static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In, - raw_ostream &Out) { - switch (Config.OutputFormat) { +static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr, + MemoryBuffer &In, raw_ostream &Out) { + switch (ConfigMgr.getCommonConfig().OutputFormat) { case FileFormat::ELF: // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the // output format is binary/ihex or it's not given. This behavior differs from @@ -153,9 +161,12 @@ case FileFormat::Binary: case FileFormat::IHex: case FileFormat::Unspecified: - if (Error E = Config.parseELFConfig()) - return E; - return elf::executeObjcopyOnRawBinary(Config, In, Out); + Expected ELFConfig = ConfigMgr.getELFConfig(); + if (!ELFConfig) + return ELFConfig.takeError(); + + return elf::executeObjcopyOnRawBinary(ConfigMgr.getCommonConfig(), + *ELFConfig, In, Out); } llvm_unreachable("unsupported output format"); @@ -163,23 +174,41 @@ /// The function executeObjcopyOnBinary does the dispatch based on the format /// of the input binary (ELF, MachO or COFF). -static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In, - raw_ostream &Out) { +static Error executeObjcopyOnBinary(const MultiFormatConfig &Config, + object::Binary &In, raw_ostream &Out) { if (auto *ELFBinary = dyn_cast(&In)) { - if (Error E = Config.parseELFConfig()) - return E; - return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); - } else if (auto *COFFBinary = dyn_cast(&In)) - return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out); - else if (auto *MachOBinary = dyn_cast(&In)) - return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out); - else if (auto *MachOUniversalBinary = - dyn_cast(&In)) + Expected ELFConfig = Config.getELFConfig(); + if (!ELFConfig) + return ELFConfig.takeError(); + + return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ELFConfig, + *ELFBinary, Out); + } else if (auto *COFFBinary = dyn_cast(&In)) { + Expected COFFConfig = Config.getCOFFConfig(); + if (!COFFConfig) + return COFFConfig.takeError(); + + return coff::executeObjcopyOnBinary(Config.getCommonConfig(), *COFFConfig, + *COFFBinary, Out); + } else if (auto *MachOBinary = dyn_cast(&In)) { + Expected MachOConfig = Config.getMachOConfig(); + if (!MachOConfig) + return MachOConfig.takeError(); + + return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOConfig, + *MachOBinary, Out); + } else if (auto *MachOUniversalBinary = + dyn_cast(&In)) { return macho::executeObjcopyOnMachOUniversalBinary( Config, *MachOUniversalBinary, Out); - else if (auto *WasmBinary = dyn_cast(&In)) - return objcopy::wasm::executeObjcopyOnBinary(Config, *WasmBinary, Out); - else + } else if (auto *WasmBinary = dyn_cast(&In)) { + Expected WasmConfig = Config.getWasmConfig(); + if (!WasmConfig) + return WasmConfig.takeError(); + + return objcopy::wasm::executeObjcopyOnBinary(Config.getCommonConfig(), + *WasmConfig, *WasmBinary, Out); + } else return createStringError(object_error::invalid_file_type, "unsupported object file format"); } @@ -188,7 +217,7 @@ namespace objcopy { Expected> -createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) { +createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { std::vector NewArchiveMembers; Error Err = Error::success(); for (const Archive::Child &Child : Ar.children(Err)) { @@ -207,8 +236,8 @@ if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) return std::move(E); - Expected Member = - NewArchiveMember::getOldMember(Child, Config.DeterministicArchives); + Expected Member = NewArchiveMember::getOldMember( + Child, Config.getCommonConfig().DeterministicArchives); if (!Member) return createFileError(Ar.getFileName(), Member.takeError()); @@ -218,27 +247,29 @@ NewArchiveMembers.push_back(std::move(*Member)); } if (Err) - return createFileError(Config.InputFilename, std::move(Err)); + return createFileError(Config.getCommonConfig().InputFilename, + std::move(Err)); return std::move(NewArchiveMembers); } } // end namespace objcopy } // end namespace llvm -static Error executeObjcopyOnArchive(CopyConfig &Config, +static Error executeObjcopyOnArchive(const ConfigManager &ConfigMgr, const object::Archive &Ar) { Expected> NewArchiveMembersOrErr = - createNewArchiveMembers(Config, Ar); + createNewArchiveMembers(ConfigMgr, Ar); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); - return deepWriteArchive(Config.OutputFilename, *NewArchiveMembersOrErr, - Ar.hasSymbolTable(), Ar.kind(), - Config.DeterministicArchives, Ar.isThin()); + return deepWriteArchive( + ConfigMgr.getCommonConfig().OutputFilename, *NewArchiveMembersOrErr, + Ar.hasSymbolTable(), Ar.kind(), + ConfigMgr.getCommonConfig().DeterministicArchives, Ar.isThin()); } static Error restoreStatOnFile(StringRef Filename, const sys::fs::file_status &Stat, - const CopyConfig &Config) { + const ConfigManager &ConfigMgr) { int FD; // Writing to stdout should not be treated as an error here, just @@ -250,7 +281,7 @@ sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) return createFileError(Filename, EC); - if (Config.PreserveDates) + if (ConfigMgr.getCommonConfig().PreserveDates) if (auto EC = sys::fs::setLastAccessAndModificationTime( FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) return createFileError(Filename, EC); @@ -261,12 +292,15 @@ if (OStat.type() == sys::fs::file_type::regular_file) { #ifndef _WIN32 // Keep ownership if llvm-objcopy is called under root. - if (Config.InputFilename == Config.OutputFilename && OStat.getUser() == 0) + if (ConfigMgr.getCommonConfig().InputFilename == + ConfigMgr.getCommonConfig().OutputFilename && + OStat.getUser() == 0) sys::fs::changeFileOwnership(FD, Stat.getUser(), Stat.getGroup()); #endif sys::fs::perms Perm = Stat.permissions(); - if (Config.InputFilename != Config.OutputFilename) + if (ConfigMgr.getCommonConfig().InputFilename != + ConfigMgr.getCommonConfig().OutputFilename) Perm = static_cast(Perm & ~sys::fs::getUmask() & ~06000); #ifdef _WIN32 if (auto EC = sys::fs::setPermissions(Filename, Perm)) @@ -285,11 +319,11 @@ /// 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 Error executeObjcopy(CopyConfig &Config) { +static Error executeObjcopy(ConfigManager &ConfigMgr) { sys::fs::file_status Stat; - if (Config.InputFilename != "-") { - if (auto EC = sys::fs::status(Config.InputFilename, Stat)) - return createFileError(Config.InputFilename, EC); + if (ConfigMgr.Common.InputFilename != "-") { + if (auto EC = sys::fs::status(ConfigMgr.Common.InputFilename, Stat)) + return createFileError(ConfigMgr.Common.InputFilename, EC); } else { Stat.permissions(static_cast(0777)); } @@ -299,73 +333,78 @@ OwningBinary BinaryHolder; std::unique_ptr MemoryBufferHolder; - if (Config.InputFormat == FileFormat::Binary || - Config.InputFormat == FileFormat::IHex) { + if (ConfigMgr.Common.InputFormat == FileFormat::Binary || + ConfigMgr.Common.InputFormat == FileFormat::IHex) { ErrorOr> BufOrErr = - MemoryBuffer::getFileOrSTDIN(Config.InputFilename); + MemoryBuffer::getFileOrSTDIN(ConfigMgr.Common.InputFilename); if (!BufOrErr) - return createFileError(Config.InputFilename, BufOrErr.getError()); + return createFileError(ConfigMgr.Common.InputFilename, + BufOrErr.getError()); MemoryBufferHolder = std::move(*BufOrErr); - if (Config.InputFormat == FileFormat::Binary) + if (ConfigMgr.Common.InputFormat == FileFormat::Binary) ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { // Handle FileFormat::Binary. - return executeObjcopyOnRawBinary(Config, *MemoryBufferHolder, OutFile); + return executeObjcopyOnRawBinary(ConfigMgr, *MemoryBufferHolder, + OutFile); }; else ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { // Handle FileFormat::IHex. - return executeObjcopyOnIHex(Config, *MemoryBufferHolder, OutFile); + return executeObjcopyOnIHex(ConfigMgr, *MemoryBufferHolder, OutFile); }; } else { Expected> BinaryOrErr = - createBinary(Config.InputFilename); + createBinary(ConfigMgr.Common.InputFilename); if (!BinaryOrErr) - return createFileError(Config.InputFilename, BinaryOrErr.takeError()); + return createFileError(ConfigMgr.Common.InputFilename, + BinaryOrErr.takeError()); BinaryHolder = std::move(*BinaryOrErr); if (Archive *Ar = dyn_cast(BinaryHolder.getBinary())) { // Handle Archive. - if (Error E = executeObjcopyOnArchive(Config, *Ar)) + if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar)) return E; } else { // Handle llvm::object::Binary. ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { - return executeObjcopyOnBinary(Config, *BinaryHolder.getBinary(), + return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(), OutFile); }; } } if (ObjcopyFunc) { - if (Config.SplitDWO.empty()) { + if (ConfigMgr.Common.SplitDWO.empty()) { // Apply transformations described by Config and store result into // Config.OutputFilename using specified ObjcopyFunc function. - if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) + if (Error E = writeToOutput(ConfigMgr.getCommonConfig().OutputFilename, + ObjcopyFunc)) return E; } else { - Config.ExtractDWO = true; - Config.StripDWO = false; + ConfigMgr.Common.ExtractDWO = true; + ConfigMgr.Common.StripDWO = false; // Copy .dwo tables from the Config.InputFilename into Config.SplitDWO // file using specified ObjcopyFunc function. - if (Error E = writeToOutput(Config.SplitDWO, ObjcopyFunc)) + if (Error E = writeToOutput(ConfigMgr.Common.SplitDWO, ObjcopyFunc)) return E; - Config.ExtractDWO = false; - Config.StripDWO = true; + ConfigMgr.Common.ExtractDWO = false; + ConfigMgr.Common.StripDWO = true; // Apply transformations described by Config, remove .dwo tables and // store result into Config.OutputFilename using specified ObjcopyFunc // function. - if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) + if (Error E = writeToOutput(ConfigMgr.Common.OutputFilename, ObjcopyFunc)) return E; } } - if (Error E = restoreStatOnFile(Config.OutputFilename, Stat, Config)) + if (Error E = + restoreStatOnFile(ConfigMgr.Common.OutputFilename, Stat, ConfigMgr)) return E; - if (!Config.SplitDWO.empty()) { + if (!ConfigMgr.Common.SplitDWO.empty()) { Stat.permissions(static_cast(0666)); - if (Error E = restoreStatOnFile(Config.SplitDWO, Stat, Config)) + if (Error E = restoreStatOnFile(ConfigMgr.Common.SplitDWO, Stat, ConfigMgr)) return E; } @@ -401,8 +440,8 @@ WithColor::error(errs(), ToolName)); return 1; } - for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { - if (Error E = executeObjcopy(CopyConfig)) { + for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) { + if (Error E = executeObjcopy(ConfigMgr)) { logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); return 1; } diff --git a/llvm/tools/llvm-objcopy/wasm/WasmConfig.h b/llvm/tools/llvm-objcopy/wasm/WasmConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/wasm/WasmConfig.h @@ -0,0 +1,21 @@ +//===- WasmConfig.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_WASMCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_WASMCONFIG_H + +namespace llvm { +namespace objcopy { + +// Wasm specific configuration for copying/stripping a single file. +struct WasmConfig {}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASMCONFIG_H diff --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h --- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h +++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h @@ -18,10 +18,11 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CommonConfig; +struct WasmConfig; namespace wasm { -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &Config, const WasmConfig &, object::WasmObjectFile &In, raw_ostream &Out); } // end namespace wasm diff --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp --- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "WasmObjcopy.h" -#include "CopyConfig.h" +#include "CommonConfig.h" #include "Object.h" #include "Reader.h" #include "Writer.h" @@ -39,7 +39,7 @@ return createStringError(errc::invalid_argument, "section '%s' not found", SecName.str().c_str()); } -static Error handleArgs(const CopyConfig &Config, Object &Obj) { +static Error handleArgs(const CommonConfig &Config, Object &Obj) { // Only support AddSection, DumpSection, RemoveSection for now. for (StringRef Flag : Config.DumpSection) { StringRef SecName; @@ -72,26 +72,10 @@ Obj.addSectionWithOwnedContents(Sec, std::move(Buf)); } - if (!Config.AddGnuDebugLink.empty() || Config.ExtractPartition || - !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || - !Config.AllocSectionsPrefix.empty() || - Config.DiscardMode != DiscardType::None || Config.NewSymbolVisibility || - !Config.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() || - !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() || - !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || - !Config.SymbolsToRemove.empty() || - !Config.UnneededSymbolsToRemove.empty() || - !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || - !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() || - !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty()) { - return createStringError( - llvm::errc::invalid_argument, - "only add-section, dump-section, and remove-section are supported"); - } return Error::success(); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &Config, const WasmConfig &, object::WasmObjectFile &In, raw_ostream &Out) { Reader TheReader(In); Expected> ObjOrErr = TheReader.create();