Index: llvm/trunk/test/tools/llvm-objcopy/strip-all.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/strip-all.test +++ llvm/trunk/test/tools/llvm-objcopy/strip-all.test @@ -2,6 +2,14 @@ # RUN: llvm-objcopy --strip-all %t %t2 # RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s +# We run yaml2obj again rather than copy %t to avoid interfering +# with llvm-objcopy's test (which potentially could have corrupted/updated the binary). + +# RUN: yaml2obj %s > %t3 +# RUN: llvm-strip %t3 +# RUN: llvm-readobj -file-headers -sections %t3 | FileCheck %s +# RUN: cmp %t2 %t3 + !ELF FileHeader: Class: ELFCLASS64 Index: llvm/trunk/test/tools/llvm-objcopy/strip-debug.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/strip-debug.test +++ llvm/trunk/test/tools/llvm-objcopy/strip-debug.test @@ -2,6 +2,16 @@ # RUN: llvm-objcopy -strip-debug %t %t2 # RUN: llvm-readobj -file-headers -sections -symbols %t2 | FileCheck %s +# We run yaml2obj again rather than copy %t to avoid interfering +# with llvm-objcopy's test (which potentially could have corrupted/updated the binary). + +# RUN: yaml2obj %s > %t3 +# RUN: llvm-strip -strip-debug %t3 +# RUN: llvm-readobj -file-headers -sections -symbols %t3 | FileCheck %s +# RUN: cmp %t2 %t3 + +# RUN: not llvm-strip -strip-debug 2>&1 | FileCheck %s --check-prefix=NO-INPUT-FILES + !ELF FileHeader: Class: ELFCLASS64 @@ -52,3 +62,5 @@ # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: ] + +# NO-INPUT-FILES: No input file specified Index: llvm/trunk/tools/llvm-objcopy/CMakeLists.txt =================================================================== --- llvm/trunk/tools/llvm-objcopy/CMakeLists.txt +++ llvm/trunk/tools/llvm-objcopy/CMakeLists.txt @@ -5,18 +5,25 @@ MC ) -set(LLVM_TARGET_DEFINITIONS Opts.td) +set(LLVM_TARGET_DEFINITIONS ObjcopyOpts.td) +tablegen(LLVM ObjcopyOpts.inc -gen-opt-parser-defs) +add_public_tablegen_target(ObjcopyOptsTableGen) -tablegen(LLVM Opts.inc -gen-opt-parser-defs) -add_public_tablegen_target(ObjcopyTableGen) +set(LLVM_TARGET_DEFINITIONS StripOpts.td) +tablegen(LLVM StripOpts.inc -gen-opt-parser-defs) +add_public_tablegen_target(StripOptsTableGen) add_llvm_tool(llvm-objcopy llvm-objcopy.cpp Object.cpp DEPENDS - ObjcopyTableGen + ObjcopyOptsTableGen + StripOptsTableGen ) +add_llvm_tool_symlink(llvm-strip llvm-objcopy) + if(LLVM_INSTALL_BINUTILS_SYMLINKS) add_llvm_tool_symlink(objcopy llvm-objcopy) + add_llvm_tool_symlink(strip llvm-objcopy) endif() Index: llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td =================================================================== --- llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td +++ llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td @@ -0,0 +1,80 @@ +include "llvm/Option/OptParser.td" + +multiclass Eq { + def NAME: Separate<["--", "-"], name>; + def NAME # _eq: Joined<["--", "-"], name # "=">, Alias(NAME)>; +} + +def help : Flag<["-", "--"], "help">; +defm binary_architecture : Eq<"binary-architecture">, + HelpText<"Used when transforming an architecture-less format (such as binary) to another format">; +def B : JoinedOrSeparate<["-"], "B">, + Alias; +defm input_target : Eq<"input-target">, + HelpText<"Format of the input file">, + Values<"binary">; +defm output_target : Eq<"output-target">, + HelpText<"Format of the output file">, + Values<"binary">; +def O : JoinedOrSeparate<["-"], "O">, + Alias; +defm split_dwo : Eq<"split-dwo">, + MetaVarName<"dwo-file">, + HelpText<"Equivalent to extract-dwo on the input file to , then strip-dwo on the input file">; +defm add_gnu_debuglink : Eq<"add-gnu-debuglink">, + MetaVarName<"debug-file">, + HelpText<"Add a .gnu_debuglink for ">; +defm remove_section : Eq<"remove-section">, + MetaVarName<"section">, + HelpText<"Remove
">; +defm redefine_symbol : Eq<"redefine-sym">, + MetaVarName<"old=new">, + HelpText<"Change the name of a symbol old to new">; +def R : JoinedOrSeparate<["-"], "R">, + Alias; +defm keep : Eq<"keep">, + MetaVarName<"section">, + HelpText<"Keep
">; +defm only_keep : Eq<"only-keep">, + MetaVarName<"section">, + HelpText<"Remove all but
">; +def j : JoinedOrSeparate<["-"], "j">, + Alias; +defm add_section : Eq<"add-section">, + MetaVarName<"section=file">, + HelpText<"Make a section named
with the contents of .">; +def strip_all : Flag<["-", "--"], "strip-all">, + HelpText<"Remove non-allocated sections other than .gnu.warning* sections">; +def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">, + HelpText<"Compaitable with GNU objcopy's --strip-all">; +def strip_debug : Flag<["-", "--"], "strip-debug">, + HelpText<"Remove all debug information">; +def strip_dwo : Flag<["-", "--"], "strip-dwo">, + HelpText<"Remove all DWARF .dwo sections from file">; +def strip_sections : Flag<["-", "--"], "strip-sections">, + HelpText<"Remove all section headers">; +def strip_non_alloc : Flag<["-", "--"], "strip-non-alloc">, + HelpText<"Remove all non-allocated sections">; +def extract_dwo : Flag<["-", "--"], "extract-dwo">, + HelpText<"Remove all sections that are not DWARF .dwo sections from file">; +def localize_hidden : Flag<["-", "--"], "localize-hidden">, + HelpText<"Mark all symbols that have hidden or internal visibility as local">; +defm localize_symbol : Eq<"localize-symbol">, + MetaVarName<"symbol">, + HelpText<"Mark as local">; +def L : JoinedOrSeparate<["-"], "L">, + Alias; +defm globalize_symbol : Eq<"globalize-symbol">, + MetaVarName<"symbol">, + HelpText<"Mark as global">; +defm weaken_symbol : Eq<"weaken-symbol">, + MetaVarName<"symbol">, + HelpText<"Mark as weak">; +def W : JoinedOrSeparate<["-"], "W">, + Alias; +def weaken : Flag<["-", "--"], "weaken">, + HelpText<"Mark all global symbols as weak">; +def discard_all : Flag<["-", "--"], "discard-all">, + HelpText<"Remove all local symbols except file and section symbols">; +def x : Flag<["-"], "x">, + Alias; Index: llvm/trunk/tools/llvm-objcopy/Opts.td =================================================================== --- llvm/trunk/tools/llvm-objcopy/Opts.td +++ llvm/trunk/tools/llvm-objcopy/Opts.td @@ -1,80 +0,0 @@ -include "llvm/Option/OptParser.td" - -multiclass Eq { - def NAME: Separate<["--", "-"], name>; - def NAME # _eq: Joined<["--", "-"], name # "=">, Alias(NAME)>; -} - -def help : Flag<["-", "--"], "help">; -defm binary_architecture : Eq<"binary-architecture">, - HelpText<"Used when transforming an architecture-less format (such as binary) to another format">; -def B : JoinedOrSeparate<["-"], "B">, - Alias; -defm input_target : Eq<"input-target">, - HelpText<"Format of the input file">, - Values<"binary">; -defm output_target : Eq<"output-target">, - HelpText<"Format of the output file">, - Values<"binary">; -def O : JoinedOrSeparate<["-"], "O">, - Alias; -defm split_dwo : Eq<"split-dwo">, - MetaVarName<"dwo-file">, - HelpText<"Equivalent to extract-dwo on the input file to , then strip-dwo on the input file">; -defm add_gnu_debuglink : Eq<"add-gnu-debuglink">, - MetaVarName<"debug-file">, - HelpText<"Add a .gnu_debuglink for ">; -defm remove_section : Eq<"remove-section">, - MetaVarName<"section">, - HelpText<"Remove
">; -defm redefine_symbol : Eq<"redefine-sym">, - MetaVarName<"old=new">, - HelpText<"Change the name of a symbol old to new">; -def R : JoinedOrSeparate<["-"], "R">, - Alias; -defm keep : Eq<"keep">, - MetaVarName<"section">, - HelpText<"Keep
">; -defm only_keep : Eq<"only-keep">, - MetaVarName<"section">, - HelpText<"Remove all but
">; -def j : JoinedOrSeparate<["-"], "j">, - Alias; -defm add_section : Eq<"add-section">, - MetaVarName<"section=file">, - HelpText<"Make a section named
with the contents of .">; -def strip_all : Flag<["-", "--"], "strip-all">, - HelpText<"Remove non-allocated sections other than .gnu.warning* sections">; -def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">, - HelpText<"Compaitable with GNU objcopy's --strip-all">; -def strip_debug : Flag<["-", "--"], "strip-debug">, - HelpText<"Remove all debug information">; -def strip_dwo : Flag<["-", "--"], "strip-dwo">, - HelpText<"Remove all DWARF .dwo sections from file">; -def strip_sections : Flag<["-", "--"], "strip-sections">, - HelpText<"Remove all section headers">; -def strip_non_alloc : Flag<["-", "--"], "strip-non-alloc">, - HelpText<"Remove all non-allocated sections">; -def extract_dwo : Flag<["-", "--"], "extract-dwo">, - HelpText<"Remove all sections that are not DWARF .dwo sections from file">; -def localize_hidden : Flag<["-", "--"], "localize-hidden">, - HelpText<"Mark all symbols that have hidden or internal visibility as local">; -defm localize_symbol : Eq<"localize-symbol">, - MetaVarName<"symbol">, - HelpText<"Mark as local">; -def L : JoinedOrSeparate<["-"], "L">, - Alias; -defm globalize_symbol : Eq<"globalize-symbol">, - MetaVarName<"symbol">, - HelpText<"Mark as global">; -defm weaken_symbol : Eq<"weaken-symbol">, - MetaVarName<"symbol">, - HelpText<"Mark as weak">; -def W : JoinedOrSeparate<["-"], "W">, - Alias; -def weaken : Flag<["-", "--"], "weaken">, - HelpText<"Mark all global symbols as weak">; -def discard_all : Flag<["-", "--"], "discard-all">, - HelpText<"Remove all local symbols except file and section symbols">; -def x : Flag<["-"], "x">, - Alias; Index: llvm/trunk/tools/llvm-objcopy/StripOpts.td =================================================================== --- llvm/trunk/tools/llvm-objcopy/StripOpts.td +++ llvm/trunk/tools/llvm-objcopy/StripOpts.td @@ -0,0 +1,12 @@ +include "llvm/Option/OptParser.td" + +multiclass Eq { + def NAME: Separate<["--", "-"], name>; + def NAME # _eq: Joined<["--", "-"], name # "=">, Alias(NAME)>; +} + +def help : Flag<["-", "--"], "help">; + +def strip_debug : Flag<["-", "--"], "strip-debug">, + HelpText<"Remove debugging symbols only">; + Index: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp +++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -45,17 +46,17 @@ namespace { -enum ID { +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 "Opts.inc" +#include "ObjcopyOpts.inc" #undef OPTION }; #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "Opts.inc" +#include "ObjcopyOpts.inc" #undef PREFIX static const opt::OptTable::Info ObjcopyInfoTable[] = { @@ -65,7 +66,7 @@ METAVAR, OBJCOPY_##ID, opt::Option::KIND##Class, \ PARAM, FLAGS, OBJCOPY_##GROUP, \ OBJCOPY_##ALIAS, ALIASARGS, VALUES}, -#include "Opts.inc" +#include "ObjcopyOpts.inc" #undef OPTION }; @@ -74,6 +75,31 @@ 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 +}; + +static const opt::OptTable::Info StripInfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {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) {} +}; + } // namespace // The name this program was invoked as. @@ -122,16 +148,16 @@ std::vector SymbolsToGlobalize; std::vector SymbolsToWeaken; StringMap SymbolsToRename; - bool StripAll; - bool StripAllGNU; - bool StripDebug; - bool StripSections; - bool StripNonAlloc; - bool StripDWO; - bool ExtractDWO; - bool LocalizeHidden; - bool Weaken; - bool DiscardAll; + bool StripAll = false; + bool StripAllGNU = false; + bool StripDebug = false; + bool StripSections = false; + bool StripNonAlloc = false; + bool StripDWO = false; + bool ExtractDWO = false; + bool LocalizeHidden = false; + bool Weaken = false; + bool DiscardAll = false; }; using SectionPred = std::function; @@ -449,10 +475,50 @@ return Config; } +// ParseStripOptions returns the config and sets the input arguments. If a +// help flag is set then ParseStripOptions will print the help messege and +// exit. +CopyConfig ParseStripOptions(ArrayRef ArgsArr) { + StripOptTable T; + unsigned MissingArgumentIndex, MissingArgumentCount; + llvm::opt::InputArgList InputArgs = + T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); + + if (InputArgs.size() == 0 || InputArgs.hasArg(STRIP_help)) { + T.PrintHelp(outs(), "llvm-strip [ ]", "strip tool"); + exit(0); + } + + SmallVector 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() > 2) + error("Support for multiple input files is not implemented yet"); + + CopyConfig Config; + Config.InputFilename = Positional[0]; + Config.OutputFilename = Positional[0]; + + // Strip debug info only. + Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); + if (!Config.StripDebug) + Config.StripAll = true; + return Config; +} + int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - - CopyConfig Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc)); + CopyConfig Config; + if (sys::path::stem(ToolName).endswith_lower("strip")) + Config = ParseStripOptions(makeArrayRef(argv + 1, argc)); + else + Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc)); ExecuteElfObjcopy(Config); }