diff --git a/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test @@ -0,0 +1,20 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --only-keep-debug %t %t.dbg +# RUN: llvm-readobj --sections %t.dbg | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Content: "c3c3c3c3" + +# CHECK: Index: 1 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ (0x6) 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 @@ -581,7 +581,23 @@ return &Obj.addSection(*CS); }); - return Obj.removeSections(Config.AllowBrokenLinks, RemovePred); + if (Error E = Obj.removeSections(Config.AllowBrokenLinks, RemovePred)) + return E; + + if (Config.OnlyKeepDebug) { + for (auto &Sec : Obj.sections()) { + if (Sec.Flags & (SHF_ALLOC | SHF_GROUP) && Sec.Type != SHT_NOTE) { + if (Sec.Type == SHT_SYMTAB) { + Sec.Flags &= ~SHF_ALLOC; + continue; + } + Sec.Type = SHT_NOBITS; + Sec.clearSectionContents(); + } + } + } + + return Error::success(); } // This function handles the high level operations of GNU objcopy including 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 @@ -417,6 +417,7 @@ virtual void markSymbols(); virtual void replaceSectionReferences(const DenseMap &); + virtual void clearSectionContents(); }; class Segment { @@ -479,6 +480,7 @@ function_ref ToRemove) override; void initialize(SectionTableRef SecTable) override; void finalize() override; + void clearSectionContents() override; }; class OwnedDataSection : public SectionBase { @@ -507,6 +509,7 @@ void appendHexData(StringRef HexData); void accept(SectionVisitor &Sec) const override; void accept(MutableSectionVisitor &Visitor) override; + void clearSectionContents() override; }; class CompressedSection : public SectionBase { diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -81,6 +81,10 @@ Shdr.sh_entsize = Sec.EntrySize; } +void SectionBase::clearSectionContents() { + assert(0 && "Cannot clear this sections contents"); +} + template void ELFSectionSizer::visit(Section &Sec) {} template @@ -468,6 +472,10 @@ Size = Data.size(); } +void OwnedDataSection::clearSectionContents() { + Data.clear(); +} + void BinarySectionWriter::visit(const CompressedSection &Sec) { error("cannot write compressed section '" + Sec.Name + "' "); } @@ -997,6 +1005,10 @@ void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; } +void Section::clearSectionContents() { + this->Contents = ArrayRef(); +} + void GnuDebugLinkSection::init(StringRef File) { FileName = sys::path::filename(File); // The format for the .gnu_debuglink starts with the file name and is