Index: test/tools/llvm-objcopy/basic-strip.test =================================================================== --- test/tools/llvm-objcopy/basic-strip.test +++ test/tools/llvm-objcopy/basic-strip.test @@ -21,12 +21,9 @@ - Name: .gnu.warning.foo Type: SHT_PROGBITS -# CHECK: SectionHeaderCount: 8 +# CHECK: SectionHeaderCount: 5 # CHECK: Name: .bss # CHECK: Name: .text -# CHECK: Name: .blarg # CHECK: Name: .gnu.warning.foo -# CHECK: Name: .symtab -# CHECK: Name: .strtab # CHECK: Name: .shstrtab Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" @@ -71,48 +72,6 @@ } // end namespace llvm -static cl::opt InputFilename(cl::Positional, cl::desc("")); -static cl::opt OutputFilename(cl::Positional, cl::desc(""), - cl::init("-")); -static cl::opt - OutputFormat("O", cl::desc("Set output format to one of the following:" - "\n\tbinary")); -static cl::list ToRemove("remove-section", - cl::desc("Remove
"), - cl::value_desc("section")); -static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), - cl::aliasopt(ToRemove)); -static cl::opt StripAll( - "strip-all", - cl::desc( - "Removes non-allocated sections other than .gnu.warning* sections")); -static cl::opt - StripAllGNU("strip-all-gnu", - cl::desc("Removes symbol, relocation, and debug information")); -static cl::list Keep("keep", cl::desc("Keep
"), - cl::value_desc("section")); -static cl::list OnlyKeep("only-keep", - cl::desc("Remove all but
"), - cl::value_desc("section")); -static cl::alias OnlyKeepA("j", cl::desc("Alias for only-keep"), - cl::aliasopt(OnlyKeep)); -static cl::opt StripDebug("strip-debug", - cl::desc("Removes all debug information")); -static cl::opt StripSections("strip-sections", - cl::desc("Remove all section headers")); -static cl::opt StripNonAlloc("strip-non-alloc", - cl::desc("Remove all non-allocated sections")); -static cl::opt - StripDWO("strip-dwo", cl::desc("Remove all DWARF .dwo sections from file")); -static cl::opt ExtractDWO( - "extract-dwo", - cl::desc("Remove all sections that are not DWARF .dwo sections from file")); -static cl::opt - SplitDWO("split-dwo", - cl::desc("Equivalent to extract-dwo on the input file to " - ", then strip-dwo on the input file"), - cl::value_desc("dwo-file")); - using SectionPred = std::function; bool IsDWOSection(const SectionBase &Sec) { @@ -135,8 +94,8 @@ Expected> BufferOrErr = FileOutputBuffer::create(File, Obj.totalSize(), FileOutputBuffer::F_executable); - handleAllErrors(BufferOrErr.takeError(), [](const ErrorInfoBase &) { - error("failed to open " + OutputFilename); + handleAllErrors(BufferOrErr.takeError(), [=](const ErrorInfoBase &) { + error("failed to open " + File); }); Buffer = std::move(*BufferOrErr); @@ -157,6 +116,26 @@ WriteObjectFile(DWOFile, File); } +template +struct CopyConfig { + StringRef OutputFilename; + StringRef OutputFormat; + const ELFObjectFile &ObjFile; + std::vector ToRemove; + std::vector Keep; + std::vector OnlyKeep; + bool StripAll; + bool StripAllGNU; + bool StripSections; + bool StripDebug; + bool StripNonAlloc; + bool StripDWO; + bool ExtractDWO; + Optional SplitDWO; + CopyConfig(const ELFObjectFile &ObjFile) : ObjFile(ObjFile) {} + void copyBinary(); +}; + // This function handles the high level operations of GNU objcopy including // handling command line options. It's important to outline certain properties // we expect to hold of the command line operations. Any operation that "keeps" @@ -165,31 +144,31 @@ // 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. template -void CopyBinary(const ELFObjectFile &ObjFile) { +void CopyConfig::copyBinary() { std::unique_ptr> Obj; - if (!OutputFormat.empty() && OutputFormat != "binary") + if (OutputFormat != "elf" && OutputFormat != "binary") error("invalid output format '" + OutputFormat + "'"); - if (!OutputFormat.empty() && OutputFormat == "binary") + if (OutputFormat == "binary") Obj = llvm::make_unique>(ObjFile); else Obj = llvm::make_unique>(ObjFile); - if (!SplitDWO.empty()) - SplitDWOToFile(ObjFile, SplitDWO.getValue()); + if (SplitDWO) + SplitDWOToFile(ObjFile, *SplitDWO); SectionPred RemovePred = [](const SectionBase &) { return false; }; // Removes: if (!ToRemove.empty()) { - RemovePred = [&](const SectionBase &Sec) { + RemovePred = [&, this](const SectionBase &Sec) { return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) != std::end(ToRemove); }; } - if (StripDWO || !SplitDWO.empty()) + if (StripDWO || SplitDWO) RemovePred = [RemovePred](const SectionBase &Sec) { return IsDWOSection(Sec) || RemovePred(Sec); }; @@ -253,7 +232,7 @@ // Explicit copies: if (!OnlyKeep.empty()) { - RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + RemovePred = [RemovePred, &Obj, this](const SectionBase &Sec) { // Explicitly keep these sections regardless of previous removes. if (std::find(std::begin(OnlyKeep), std::end(OnlyKeep), Sec.Name) != std::end(OnlyKeep)) @@ -277,7 +256,7 @@ } if (!Keep.empty()) { - RemovePred = [RemovePred](const SectionBase &Sec) { + RemovePred = [RemovePred, this](const SectionBase &Sec) { // Explicitly keep these sections regardless of previous removes. if (std::find(std::begin(Keep), std::end(Keep), Sec.Name) != std::end(Keep)) @@ -289,7 +268,108 @@ Obj->removeSections(RemovePred); Obj->finalize(); - WriteObjectFile(*Obj, OutputFilename.getValue()); + WriteObjectFile(*Obj, OutputFilename); +} + +// This namespace hides our flags so that only our driver functions see them. +namespace flags { + +static cl::opt InputFilename(cl::Positional, cl::desc("")); +static cl::opt OutputFilename(cl::Positional, cl::desc("")); +static cl::opt + OutputFormat("O", cl::desc("Set output format to one of the following:" + "\n\tbinary\n\telf"), cl::init("elf")); +static cl::list ToRemove("remove-section", + cl::desc("Remove
"), + cl::value_desc("section")); +static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), + cl::aliasopt(ToRemove)); +static cl::opt StripAll( + "strip-all", + cl::desc( + "Removes non-allocated sections other than .gnu.warning* sections")); +static cl::opt + StripAllGNU("strip-all-gnu", + cl::desc("Removes symbol, relocation, and debug information")); +static cl::list Keep("keep", cl::desc("Keep
"), + cl::value_desc("section")); +static cl::list OnlyKeep("only-keep", + cl::desc("Remove all but
"), + cl::value_desc("section")); +static cl::alias OnlyKeepA("j", cl::desc("Alias for only-keep"), + cl::aliasopt(OnlyKeep)); +static cl::opt StripDebug("strip-debug", + cl::desc("Removes all debug information")); +static cl::opt StripSections("strip-sections", + cl::desc("Remove all section headers")); +static cl::opt StripNonAlloc("strip-non-alloc", + cl::desc("Remove all non-allocated sections")); +static cl::opt + StripDWO("strip-dwo", cl::desc("Remove all DWARF .dwo sections from file")); +static cl::opt ExtractDWO( + "extract-dwo", + cl::desc("Remove all sections that are not DWARF .dwo sections from file")); +static cl::opt + SplitDWO("split-dwo", + cl::desc("Equivalent to extract-dwo on the input file to " + ", then strip-dwo on the input file"), + cl::value_desc("dwo-file")); + +} + +// This nameless namespace is just to scope the useage of the flags namespace. +namespace { + +using namespace flags; + +template +void CommonConfig(CopyConfig& Config) { + if (OutputFilename.empty()) + Config.OutputFilename = InputFilename; + else + Config.OutputFilename = OutputFilename; + Config.OutputFormat = OutputFormat.getValue(); + Config.ExtractDWO = ExtractDWO; + Config.Keep.insert(std::end(Config.Keep), std::begin(Keep), std::end(Keep)); + Config.OnlyKeep.insert(std::end(Config.OnlyKeep), std::begin(OnlyKeep), std::end(OnlyKeep)); + Config.ToRemove.insert(std::end(Config.ToRemove), std::begin(ToRemove), std::end(ToRemove)); + if(!SplitDWO.empty()) + Config.SplitDWO = SplitDWO; + Config.StripDWO = StripDWO; + Config.StripSections = StripSections; + Config.StripAllGNU = StripAllGNU; + Config.StripDebug = StripDebug; + Config.StripNonAlloc = StripNonAlloc; +} + +template +void Strip(const ELFObjectFile& ObjFile) { + CopyConfig Config(ObjFile); + CommonConfig(Config); + Config.StripAll = StripAll || + !(StripAllGNU || StripDebug || StripDWO || StripNonAlloc || + StripSections); + Config.copyBinary(); +} + +template +void Objcopy(const ELFObjectFile& ObjFile) { + CopyConfig Config(ObjFile); + CommonConfig(Config); + Config.StripAll = StripAll; + Config.copyBinary(); +} + +} + +template +void InvokeMain(const ELFObjectFile& ObjFile) { + StringRef Stem = sys::path::stem(ToolName); + if (Stem.find("strip") != StringRef::npos) { + Strip(ObjFile); + } else { + Objcopy(ObjFile); + } } int main(int argc, char **argv) { @@ -308,19 +388,19 @@ reportError(InputFilename, BinaryOrErr.takeError()); Binary &Binary = *BinaryOrErr.get().getBinary(); if (auto *o = dyn_cast>(&Binary)) { - CopyBinary(*o); + InvokeMain(*o); return 0; } if (auto *o = dyn_cast>(&Binary)) { - CopyBinary(*o); + InvokeMain(*o); return 0; } if (auto *o = dyn_cast>(&Binary)) { - CopyBinary(*o); + InvokeMain(*o); return 0; } if (auto *o = dyn_cast>(&Binary)) { - CopyBinary(*o); + InvokeMain(*o); return 0; } reportError(InputFilename, object_error::invalid_file_type);