[llvm] r344307 - [llvm-objcopy] Factor out CopyConfig
Alexander Shaposhnikov via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 11 15:33:51 PDT 2018
Author: alexshap
Date: Thu Oct 11 15:33:50 2018
New Revision: 344307
URL: http://llvm.org/viewvc/llvm-project?rev=344307&view=rev
Log:
[llvm-objcopy] Factor out CopyConfig
In this diff we move out CopyConfig from llvm-oobjcopy.cpp into a separate header CopyConfig.h
to enable us (in the future) reuse this class in the other implementations of objcopy (for coff, mach-o).
Additionally this enables us to unload the complexity from llvm-objcopy.cpp a little bit.
Test plan: make check-all
Differential revision: https://reviews.llvm.org/D53006
Added:
llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp
llvm/trunk/tools/llvm-objcopy/CopyConfig.h
Modified:
llvm/trunk/tools/llvm-objcopy/CMakeLists.txt
llvm/trunk/tools/llvm-objcopy/Object.h
llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
Modified: llvm/trunk/tools/llvm-objcopy/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CMakeLists.txt?rev=344307&r1=344306&r2=344307&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-objcopy/CMakeLists.txt Thu Oct 11 15:33:50 2018
@@ -14,6 +14,7 @@ tablegen(LLVM StripOpts.inc -gen-opt-par
add_public_tablegen_target(StripOptsTableGen)
add_llvm_tool(llvm-objcopy
+ CopyConfig.cpp
llvm-objcopy.cpp
Object.cpp
DEPENDS
Added: llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp?rev=344307&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp (added)
+++ llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp Thu Oct 11 15:33:50 2018
@@ -0,0 +1,424 @@
+//===- CopyConfig.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CopyConfig.h"
+#include "llvm-objcopy.h"
+
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+#include <string>
+
+namespace llvm {
+namespace objcopy {
+
+namespace {
+enum ObjcopyID {
+ OBJCOPY_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OBJCOPY_##ID,
+#include "ObjcopyOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
+#include "ObjcopyOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info ObjcopyInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {OBJCOPY_##PREFIX, \
+ NAME, \
+ HELPTEXT, \
+ METAVAR, \
+ OBJCOPY_##ID, \
+ opt::Option::KIND##Class, \
+ PARAM, \
+ FLAGS, \
+ OBJCOPY_##GROUP, \
+ OBJCOPY_##ALIAS, \
+ ALIASARGS, \
+ VALUES},
+#include "ObjcopyOpts.inc"
+#undef OPTION
+};
+
+class ObjcopyOptTable : public opt::OptTable {
+public:
+ ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {}
+};
+
+enum StripID {
+ STRIP_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ STRIP_##ID,
+#include "StripOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
+#include "StripOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info StripInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {STRIP_##PREFIX, NAME, HELPTEXT, \
+ METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, STRIP_##GROUP, \
+ STRIP_##ALIAS, ALIASARGS, VALUES},
+#include "StripOpts.inc"
+#undef OPTION
+};
+
+class StripOptTable : public opt::OptTable {
+public:
+ StripOptTable() : OptTable(StripInfoTable, true) {}
+};
+
+enum SectionFlag {
+ SecNone = 0,
+ SecAlloc = 1 << 0,
+ SecLoad = 1 << 1,
+ SecNoload = 1 << 2,
+ SecReadonly = 1 << 3,
+ SecDebug = 1 << 4,
+ SecCode = 1 << 5,
+ SecData = 1 << 6,
+ SecRom = 1 << 7,
+ SecMerge = 1 << 8,
+ SecStrings = 1 << 9,
+ SecContents = 1 << 10,
+ SecShare = 1 << 11,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
+};
+
+} // namespace
+
+static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
+ return llvm::StringSwitch<SectionFlag>(SectionName)
+ .Case("alloc", SectionFlag::SecAlloc)
+ .Case("load", SectionFlag::SecLoad)
+ .Case("noload", SectionFlag::SecNoload)
+ .Case("readonly", SectionFlag::SecReadonly)
+ .Case("debug", SectionFlag::SecDebug)
+ .Case("code", SectionFlag::SecCode)
+ .Case("data", SectionFlag::SecData)
+ .Case("rom", SectionFlag::SecRom)
+ .Case("merge", SectionFlag::SecMerge)
+ .Case("strings", SectionFlag::SecStrings)
+ .Case("contents", SectionFlag::SecContents)
+ .Case("share", SectionFlag::SecShare)
+ .Default(SectionFlag::SecNone);
+}
+
+static SectionRename parseRenameSectionValue(StringRef FlagValue) {
+ if (!FlagValue.contains('='))
+ error("Bad format for --rename-section: missing '='");
+
+ // Initial split: ".foo" = ".bar,f1,f2,..."
+ auto Old2New = FlagValue.split('=');
+ SectionRename SR;
+ SR.OriginalName = Old2New.first;
+
+ // Flags split: ".bar" "f1" "f2" ...
+ SmallVector<StringRef, 6> NameAndFlags;
+ Old2New.second.split(NameAndFlags, ',');
+ SR.NewName = NameAndFlags[0];
+
+ if (NameAndFlags.size() > 1) {
+ SectionFlag Flags = SectionFlag::SecNone;
+ for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
+ SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
+ if (Flag == SectionFlag::SecNone)
+ error("Unrecognized section flag '" + NameAndFlags[I] +
+ "'. Flags supported for GNU compatibility: alloc, load, noload, "
+ "readonly, debug, code, data, rom, share, contents, merge, "
+ "strings.");
+ Flags |= Flag;
+ }
+
+ SR.NewFlags = 0;
+ if (Flags & SectionFlag::SecAlloc)
+ *SR.NewFlags |= ELF::SHF_ALLOC;
+ if (!(Flags & SectionFlag::SecReadonly))
+ *SR.NewFlags |= ELF::SHF_WRITE;
+ if (Flags & SectionFlag::SecCode)
+ *SR.NewFlags |= ELF::SHF_EXECINSTR;
+ if (Flags & SectionFlag::SecMerge)
+ *SR.NewFlags |= ELF::SHF_MERGE;
+ if (Flags & SectionFlag::SecStrings)
+ *SR.NewFlags |= ELF::SHF_STRINGS;
+ }
+
+ return SR;
+}
+
+static const StringMap<MachineInfo> ArchMap{
+ // Name, {EMachine, 64bit, LittleEndian}
+ {"aarch64", {ELF::EM_AARCH64, true, true}},
+ {"arm", {ELF::EM_ARM, false, true}},
+ {"i386", {ELF::EM_386, false, true}},
+ {"i386:x86-64", {ELF::EM_X86_64, true, true}},
+ {"powerpc:common64", {ELF::EM_PPC64, true, true}},
+ {"sparc", {ELF::EM_SPARC, false, true}},
+ {"x86-64", {ELF::EM_X86_64, true, true}},
+};
+
+static const MachineInfo &getMachineInfo(StringRef Arch) {
+ auto Iter = ArchMap.find(Arch);
+ if (Iter == std::end(ArchMap))
+ error("Invalid architecture: '" + Arch + "'");
+ return Iter->getValue();
+}
+
+static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
+ StringRef Filename) {
+ SmallVector<StringRef, 16> Lines;
+ auto BufOrErr = MemoryBuffer::getFile(Filename);
+ if (!BufOrErr)
+ reportError(Filename, BufOrErr.getError());
+
+ BufOrErr.get()->getBuffer().split(Lines, '\n');
+ for (StringRef Line : Lines) {
+ // Ignore everything after '#', trim whitespace, and only add the symbol if
+ // it's not empty.
+ auto TrimmedLine = Line.split('#').first.trim();
+ if (!TrimmedLine.empty())
+ Symbols.push_back(TrimmedLine.str());
+ }
+}
+
+// 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<const char *> ArgsArr) {
+ ObjcopyOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ llvm::opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (InputArgs.size() == 0) {
+ T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
+ exit(1);
+ }
+
+ if (InputArgs.hasArg(OBJCOPY_help)) {
+ T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
+ exit(0);
+ }
+
+ if (InputArgs.hasArg(OBJCOPY_version)) {
+ cl::PrintVersionMessage();
+ exit(0);
+ }
+
+ SmallVector<const char *, 2> Positional;
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
+ error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
+ Positional.push_back(Arg->getValue());
+
+ if (Positional.empty())
+ error("No input file specified");
+
+ if (Positional.size() > 2)
+ error("Too many positional arguments");
+
+ CopyConfig Config;
+ Config.InputFilename = Positional[0];
+ Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
+ Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
+ Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
+ 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);
+ }
+
+ if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
+ OBJCOPY_compress_debug_sections_eq)) {
+ Config.CompressionType = DebugCompressionType::Z;
+
+ if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
+ Config.CompressionType =
+ StringSwitch<DebugCompressionType>(
+ InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
+ .Case("zlib-gnu", DebugCompressionType::GNU)
+ .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));
+ if (!zlib::isAvailable())
+ error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
+ }
+ }
+
+ Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
+ Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
+ Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
+ if (!StringRef(Arg->getValue()).contains('='))
+ error("Bad format for --redefine-sym");
+ auto Old2New = StringRef(Arg->getValue()).split('=');
+ if (!Config.SymbolsToRename.insert(Old2New).second)
+ error("Multiple redefinition of symbol " + Old2New.first);
+ }
+
+ 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);
+ }
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
+ Config.ToRemove.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
+ Config.Keep.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
+ Config.OnlyKeep.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
+ Config.AddSection.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
+ Config.DumpSection.push_back(Arg->getValue());
+ Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
+ Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
+ Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
+ Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
+ Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
+ Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
+ Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
+ Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
+ Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
+ Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
+ Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
+ Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
+ Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
+ Config.DecompressDebugSections =
+ InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
+ Config.SymbolsToLocalize.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
+ Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
+ addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
+ Config.SymbolsToGlobalize.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
+ Config.SymbolsToWeaken.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
+ Config.SymbolsToRemove.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
+ Config.SymbolsToKeep.push_back(Arg->getValue());
+
+ Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
+
+ DriverConfig DC;
+ DC.CopyConfigs.push_back(std::move(Config));
+ 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");
+ }
+
+ if (Config.DecompressDebugSections && !zlib::isAvailable())
+ error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
+
+ return DC;
+}
+
+// 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<const char *> ArgsArr) {
+ StripOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ llvm::opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (InputArgs.size() == 0) {
+ T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
+ exit(1);
+ }
+
+ if (InputArgs.hasArg(STRIP_help)) {
+ T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
+ exit(0);
+ }
+
+ if (InputArgs.hasArg(STRIP_version)) {
+ cl::PrintVersionMessage();
+ exit(0);
+ }
+
+ SmallVector<const char *, 2> Positional;
+ for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
+ error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
+ for (auto Arg : InputArgs.filtered(STRIP_INPUT))
+ Positional.push_back(Arg->getValue());
+
+ if (Positional.empty())
+ error("No input file specified");
+
+ if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
+ error("Multiple input files cannot be used in combination with -o");
+
+ CopyConfig Config;
+ Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
+
+ Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
+ Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
+ Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
+
+ if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
+ Config.StripAll = true;
+
+ for (auto Arg : InputArgs.filtered(STRIP_remove_section))
+ Config.ToRemove.push_back(Arg->getValue());
+
+ for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
+ Config.SymbolsToKeep.push_back(Arg->getValue());
+
+ Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
+
+ DriverConfig DC;
+ if (Positional.size() == 1) {
+ Config.InputFilename = Positional[0];
+ Config.OutputFilename =
+ InputArgs.getLastArgValue(STRIP_output, Positional[0]);
+ DC.CopyConfigs.push_back(std::move(Config));
+ } else {
+ for (const char *Filename : Positional) {
+ Config.InputFilename = Filename;
+ Config.OutputFilename = Filename;
+ DC.CopyConfigs.push_back(Config);
+ }
+ }
+
+ return DC;
+}
+
+} // namespace objcopy
+} // namespace llvm
Added: llvm/trunk/tools/llvm-objcopy/CopyConfig.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.h?rev=344307&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/CopyConfig.h (added)
+++ llvm/trunk/tools/llvm-objcopy/CopyConfig.h Thu Oct 11 15:33:50 2018
@@ -0,0 +1,113 @@
+//===- CopyConfig.h -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+// Necessary for llvm::DebugCompressionType::None
+#include "llvm/Target/TargetOptions.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+
+// 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
+// ELF file.
+struct MachineInfo {
+ uint16_t EMachine;
+ bool Is64Bit;
+ bool IsLittleEndian;
+};
+
+struct SectionRename {
+ StringRef OriginalName;
+ StringRef NewName;
+ Optional<uint64_t> NewFlags;
+};
+
+// Configuration for copying/stripping a single file.
+struct CopyConfig {
+ // Main input/output options
+ StringRef InputFilename;
+ StringRef InputFormat;
+ StringRef OutputFilename;
+ StringRef OutputFormat;
+
+ // Only applicable for --input-format=Binary
+ MachineInfo BinaryArch;
+
+ // Advanced options
+ StringRef AddGnuDebugLink;
+ StringRef SplitDWO;
+ StringRef SymbolsPrefix;
+
+ // Repeated options
+ std::vector<StringRef> AddSection;
+ std::vector<StringRef> DumpSection;
+ std::vector<StringRef> Keep;
+ std::vector<StringRef> OnlyKeep;
+ std::vector<StringRef> SymbolsToGlobalize;
+ std::vector<StringRef> SymbolsToKeep;
+ std::vector<StringRef> SymbolsToLocalize;
+ std::vector<StringRef> SymbolsToRemove;
+ std::vector<StringRef> SymbolsToWeaken;
+ std::vector<StringRef> ToRemove;
+ std::vector<std::string> SymbolsToKeepGlobal;
+
+ // Map options
+ StringMap<SectionRename> SectionsToRename;
+ StringMap<StringRef> SymbolsToRename;
+
+ // Boolean options
+ bool DiscardAll = false;
+ bool ExtractDWO = false;
+ bool KeepFileSymbols = false;
+ bool LocalizeHidden = false;
+ bool OnlyKeepDebug = false;
+ bool PreserveDates = false;
+ bool StripAll = false;
+ bool StripAllGNU = false;
+ bool StripDWO = false;
+ bool StripDebug = false;
+ bool StripNonAlloc = false;
+ bool StripSections = false;
+ bool StripUnneeded = false;
+ bool Weaken = false;
+ bool DecompressDebugSections = false;
+ DebugCompressionType CompressionType = DebugCompressionType::None;
+};
+
+// 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<CopyConfig, 1> CopyConfigs;
+};
+
+// 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<const char *> 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<const char *> ArgsArr);
+
+} // namespace objcopy
+} // namespace llvm
+
+#endif
Modified: llvm/trunk/tools/llvm-objcopy/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.h?rev=344307&r1=344306&r2=344307&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.h Thu Oct 11 15:33:50 2018
@@ -10,6 +10,7 @@
#ifndef LLVM_TOOLS_OBJCOPY_OBJECT_H
#define LLVM_TOOLS_OBJCOPY_OBJECT_H
+#include "CopyConfig.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -67,15 +68,6 @@ public:
enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE };
-// 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
-// ELF file.
-struct MachineInfo {
- uint16_t EMachine;
- bool Is64Bit;
- bool IsLittleEndian;
-};
-
class SectionVisitor {
public:
virtual ~SectionVisitor();
Modified: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp?rev=344307&r1=344306&r2=344307&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp Thu Oct 11 15:33:50 2018
@@ -8,8 +8,9 @@
//===----------------------------------------------------------------------===//
#include "llvm-objcopy.h"
-
+#include "CopyConfig.h"
#include "Object.h"
+
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
@@ -56,160 +57,8 @@ using namespace llvm::objcopy;
using namespace object;
using namespace ELF;
-namespace {
-
-enum ObjcopyID {
- OBJCOPY_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OBJCOPY_##ID,
-#include "ObjcopyOpts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
-#include "ObjcopyOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info ObjcopyInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {OBJCOPY_##PREFIX, \
- NAME, \
- HELPTEXT, \
- METAVAR, \
- OBJCOPY_##ID, \
- opt::Option::KIND##Class, \
- PARAM, \
- FLAGS, \
- OBJCOPY_##GROUP, \
- OBJCOPY_##ALIAS, \
- ALIASARGS, \
- VALUES},
-#include "ObjcopyOpts.inc"
-#undef OPTION
-};
-
-class ObjcopyOptTable : public opt::OptTable {
-public:
- ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {}
-};
-
-enum StripID {
- STRIP_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- STRIP_##ID,
-#include "StripOpts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
-#include "StripOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info StripInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {STRIP_##PREFIX, NAME, HELPTEXT, \
- METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, STRIP_##GROUP, \
- STRIP_##ALIAS, ALIASARGS, VALUES},
-#include "StripOpts.inc"
-#undef OPTION
-};
-
-class StripOptTable : public opt::OptTable {
-public:
- StripOptTable() : OptTable(StripInfoTable, true) {}
-};
-
-struct SectionRename {
- StringRef OriginalName;
- StringRef NewName;
- Optional<uint64_t> NewFlags;
-};
-
-// Configuration for copying/stripping a single file.
-struct CopyConfig {
- // Main input/output options
- StringRef InputFilename;
- StringRef InputFormat;
- StringRef OutputFilename;
- StringRef OutputFormat;
-
- // Only applicable for --input-format=Binary
- MachineInfo BinaryArch;
-
- // Advanced options
- StringRef AddGnuDebugLink;
- StringRef SplitDWO;
- StringRef SymbolsPrefix;
-
- // Repeated options
- std::vector<StringRef> AddSection;
- std::vector<StringRef> DumpSection;
- std::vector<StringRef> Keep;
- std::vector<StringRef> OnlyKeep;
- std::vector<StringRef> SymbolsToGlobalize;
- std::vector<StringRef> SymbolsToKeep;
- std::vector<StringRef> SymbolsToLocalize;
- std::vector<StringRef> SymbolsToRemove;
- std::vector<StringRef> SymbolsToWeaken;
- std::vector<StringRef> ToRemove;
- std::vector<std::string> SymbolsToKeepGlobal;
-
- // Map options
- StringMap<SectionRename> SectionsToRename;
- StringMap<StringRef> SymbolsToRename;
-
- // Boolean options
- bool DiscardAll = false;
- bool ExtractDWO = false;
- bool KeepFileSymbols = false;
- bool LocalizeHidden = false;
- bool OnlyKeepDebug = false;
- bool PreserveDates = false;
- bool StripAll = false;
- bool StripAllGNU = false;
- bool StripDWO = false;
- bool StripDebug = false;
- bool StripNonAlloc = false;
- bool StripSections = false;
- bool StripUnneeded = false;
- bool Weaken = false;
- bool DecompressDebugSections = false;
- DebugCompressionType CompressionType = DebugCompressionType::None;
-};
-
-// 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<CopyConfig, 1> CopyConfigs;
-};
-
using SectionPred = std::function<bool(const SectionBase &Sec)>;
-enum SectionFlag {
- SecNone = 0,
- SecAlloc = 1 << 0,
- SecLoad = 1 << 1,
- SecNoload = 1 << 2,
- SecReadonly = 1 << 3,
- SecDebug = 1 << 4,
- SecCode = 1 << 5,
- SecData = 1 << 6,
- SecRom = 1 << 7,
- SecMerge = 1 << 8,
- SecStrings = 1 << 9,
- SecContents = 1 << 10,
- SecShare = 1 << 11,
- LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
-};
-
-} // namespace
-
namespace llvm {
namespace objcopy {
@@ -242,65 +91,6 @@ LLVM_ATTRIBUTE_NORETURN void reportError
} // end namespace objcopy
} // end namespace llvm
-static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
- return llvm::StringSwitch<SectionFlag>(SectionName)
- .Case("alloc", SectionFlag::SecAlloc)
- .Case("load", SectionFlag::SecLoad)
- .Case("noload", SectionFlag::SecNoload)
- .Case("readonly", SectionFlag::SecReadonly)
- .Case("debug", SectionFlag::SecDebug)
- .Case("code", SectionFlag::SecCode)
- .Case("data", SectionFlag::SecData)
- .Case("rom", SectionFlag::SecRom)
- .Case("merge", SectionFlag::SecMerge)
- .Case("strings", SectionFlag::SecStrings)
- .Case("contents", SectionFlag::SecContents)
- .Case("share", SectionFlag::SecShare)
- .Default(SectionFlag::SecNone);
-}
-
-static SectionRename parseRenameSectionValue(StringRef FlagValue) {
- if (!FlagValue.contains('='))
- error("Bad format for --rename-section: missing '='");
-
- // Initial split: ".foo" = ".bar,f1,f2,..."
- auto Old2New = FlagValue.split('=');
- SectionRename SR;
- SR.OriginalName = Old2New.first;
-
- // Flags split: ".bar" "f1" "f2" ...
- SmallVector<StringRef, 6> NameAndFlags;
- Old2New.second.split(NameAndFlags, ',');
- SR.NewName = NameAndFlags[0];
-
- if (NameAndFlags.size() > 1) {
- SectionFlag Flags = SectionFlag::SecNone;
- for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
- SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
- if (Flag == SectionFlag::SecNone)
- error("Unrecognized section flag '" + NameAndFlags[I] +
- "'. Flags supported for GNU compatibility: alloc, load, noload, "
- "readonly, debug, code, data, rom, share, contents, merge, "
- "strings.");
- Flags |= Flag;
- }
-
- SR.NewFlags = 0;
- if (Flags & SectionFlag::SecAlloc)
- *SR.NewFlags |= ELF::SHF_ALLOC;
- if (!(Flags & SectionFlag::SecReadonly))
- *SR.NewFlags |= ELF::SHF_WRITE;
- if (Flags & SectionFlag::SecCode)
- *SR.NewFlags |= ELF::SHF_EXECINSTR;
- if (Flags & SectionFlag::SecMerge)
- *SR.NewFlags |= ELF::SHF_MERGE;
- if (Flags & SectionFlag::SecStrings)
- *SR.NewFlags |= ELF::SHF_STRINGS;
- }
-
- return SR;
-}
-
static bool isDebugSection(const SectionBase &Sec) {
return StringRef(Sec.Name).startswith(".debug") ||
StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
@@ -319,24 +109,6 @@ static bool onlyKeepDWOPred(const Object
return !isDWOSection(Sec);
}
-static const StringMap<MachineInfo> ArchMap{
- // Name, {EMachine, 64bit, LittleEndian}
- {"aarch64", {EM_AARCH64, true, true}},
- {"arm", {EM_ARM, false, true}},
- {"i386", {EM_386, false, true}},
- {"i386:x86-64", {EM_X86_64, true, true}},
- {"powerpc:common64", {EM_PPC64, true, true}},
- {"sparc", {EM_SPARC, false, true}},
- {"x86-64", {EM_X86_64, true, true}},
-};
-
-static const MachineInfo &getMachineInfo(StringRef Arch) {
- auto Iter = ArchMap.find(Arch);
- if (Iter == std::end(ArchMap))
- error("Invalid architecture: '" + Arch + "'");
- return Iter->getValue();
-}
-
static ElfType getOutputElfType(const Binary &Bin) {
// Infer output ELF type from the input ELF object
if (isa<ELFObjectFile<ELF32LE>>(Bin))
@@ -870,238 +642,6 @@ static void executeElfObjcopy(const Copy
}
}
-static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
- StringRef Filename) {
- SmallVector<StringRef, 16> Lines;
- auto BufOrErr = MemoryBuffer::getFile(Filename);
- if (!BufOrErr)
- reportError(Filename, BufOrErr.getError());
-
- BufOrErr.get()->getBuffer().split(Lines, '\n');
- for (StringRef Line : Lines) {
- // Ignore everything after '#', trim whitespace, and only add the symbol if
- // it's not empty.
- auto TrimmedLine = Line.split('#').first.trim();
- if (!TrimmedLine.empty())
- Symbols.push_back(TrimmedLine.str());
- }
-}
-
-// ParseObjcopyOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseObjcopyOptions will print the help messege and
-// exit.
-static DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
- ObjcopyOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- llvm::opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- if (InputArgs.size() == 0) {
- T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
- exit(1);
- }
-
- if (InputArgs.hasArg(OBJCOPY_help)) {
- T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
- exit(0);
- }
-
- if (InputArgs.hasArg(OBJCOPY_version)) {
- cl::PrintVersionMessage();
- exit(0);
- }
-
- SmallVector<const char *, 2> Positional;
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
- error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
- Positional.push_back(Arg->getValue());
-
- if (Positional.empty())
- error("No input file specified");
-
- if (Positional.size() > 2)
- error("Too many positional arguments");
-
- CopyConfig Config;
- Config.InputFilename = Positional[0];
- Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
- Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
- Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
- 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);
- }
-
- if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
- OBJCOPY_compress_debug_sections_eq)) {
- Config.CompressionType = DebugCompressionType::Z;
-
- if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
- Config.CompressionType =
- StringSwitch<DebugCompressionType>(
- InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
- .Case("zlib-gnu", DebugCompressionType::GNU)
- .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));
- if (!zlib::isAvailable())
- error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
- }
- }
-
- Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
- Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
- Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
- if (!StringRef(Arg->getValue()).contains('='))
- error("Bad format for --redefine-sym");
- auto Old2New = StringRef(Arg->getValue()).split('=');
- if (!Config.SymbolsToRename.insert(Old2New).second)
- error("Multiple redefinition of symbol " + Old2New.first);
- }
-
- 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);
- }
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
- Config.ToRemove.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
- Config.Keep.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
- Config.OnlyKeep.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
- Config.AddSection.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
- Config.DumpSection.push_back(Arg->getValue());
- Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
- Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
- Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
- Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
- Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
- Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
- Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
- Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
- Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
- Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
- Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
- Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
- Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
- Config.DecompressDebugSections =
- InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
- for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
- Config.SymbolsToLocalize.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
- Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
- addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
- Config.SymbolsToGlobalize.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
- Config.SymbolsToWeaken.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
- Config.SymbolsToRemove.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
- Config.SymbolsToKeep.push_back(Arg->getValue());
-
- Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
-
- DriverConfig DC;
- DC.CopyConfigs.push_back(std::move(Config));
- 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");
- }
-
- if (Config.DecompressDebugSections && !zlib::isAvailable())
- error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
-
- return DC;
-}
-
-// ParseStripOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseStripOptions will print the help messege and
-// exit.
-static DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
- StripOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- llvm::opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- static const char Usage[] = "llvm-strip [options] file...";
- if (InputArgs.size() == 0) {
- T.PrintHelp(errs(), Usage, "strip tool");
- exit(1);
- }
-
- if (InputArgs.hasArg(STRIP_help)) {
- T.PrintHelp(outs(), Usage, "strip tool");
- exit(0);
- }
-
- if (InputArgs.hasArg(STRIP_version)) {
- cl::PrintVersionMessage();
- exit(0);
- }
-
- SmallVector<const char *, 2> Positional;
- for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
- error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
- for (auto Arg : InputArgs.filtered(STRIP_INPUT))
- Positional.push_back(Arg->getValue());
-
- if (Positional.empty())
- error("No input file specified");
-
- if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
- error("Multiple input files cannot be used in combination with -o");
-
- CopyConfig Config;
- Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
-
- Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
- Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
- Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
-
- if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
- Config.StripAll = true;
-
- for (auto Arg : InputArgs.filtered(STRIP_remove_section))
- Config.ToRemove.push_back(Arg->getValue());
-
- for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
- Config.SymbolsToKeep.push_back(Arg->getValue());
-
- Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
-
- DriverConfig DC;
- if (Positional.size() == 1) {
- Config.InputFilename = Positional[0];
- Config.OutputFilename =
- InputArgs.getLastArgValue(STRIP_output, Positional[0]);
- DC.CopyConfigs.push_back(std::move(Config));
- } else {
- for (const char *Filename : Positional) {
- Config.InputFilename = Filename;
- Config.OutputFilename = Filename;
- DC.CopyConfigs.push_back(Config);
- }
- }
-
- return DC;
-}
-
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
ToolName = argv[0];
More information about the llvm-commits
mailing list