Index: llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test @@ -0,0 +1,50 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --only-keep-debug %t %t.dbg +# RUN: llvm-readobj --sections %t.dbg | FileCheck %s +# RUN: llvm-readobj --sections %t.dbg | FileCheck --check-prefix=NOTE %s +# RUN: llvm-readobj --sections %t.dbg | FileCheck --check-prefix=DEBUG %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" + - Name: .note + Type: SHT_NOTE + Flags: [ SHF_ALLOC ] + Content: 040000001000000003000000474E55004FCB712AA6387724A9F465A32CD8C14B + - Name: .debug + Type: SHT_PROGBITS + Content: "031F" + +## Checks that alloc segment is marked no bits. +## It has no contents but size should stay the same. +# CHECK: Index: 1 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: SHF_EXECINSTR (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 64 + +## SHT_NOTE does not change. +# NOTE: Index: 2 +# NOTE-NEXT: Name: .note +# NOTE-NEXT: Type: SHT_NOTE +# NOTE-NEXT: Flags [ (0x2) +# NOTE-NEXT: SHF_ALLOC (0x2) + +## .debug sections should never change. +# DEBUG: Index: 3 +# DEBUG-NEXT: Name: .debug +# DEBUG-NEXT: Type: SHT_PROGBITS +# DEBUG-NEXT: Flags [ (0x0) Index: llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -579,7 +579,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 Index: llvm/tools/llvm-objcopy/ELF/Object.h =================================================================== --- llvm/tools/llvm-objcopy/ELF/Object.h +++ 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 { Index: llvm/tools/llvm-objcopy/ELF/Object.cpp =================================================================== --- llvm/tools/llvm-objcopy/ELF/Object.cpp +++ 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