Index: test/tools/llvm-objcopy/only-keep-debug.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/only-keep-debug.test @@ -0,0 +1,70 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy --only-keep-debug %t %t2 +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + - Name: .symtab.dyn + Type: SHT_SYMTAB + Flags: [ SHF_ALLOC ] + Type: SHT_NOBITS + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Size: 4 + - Name: .debug_info + Type: SHT_PROGBITS + Flags: [ ] + AddressAlign: 0x1 + Size: 4 + - Name: .debug_loc + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + AddressAlign: 0x1 + Size: 4 + - Name: .zdebug_foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + - Name: .line + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + - Name: .stab + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + - Name: .gnu.linkonce.wi.1 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + - Name: .comment + Type: SHT_PROGBITS + - Name: .random_section_name + Type: SHT_PROGBITS + - Name: .debug_not_a_real_debug_section + Type: SHT_PROGBITS + - Name: .rel.text + Type: SHT_REL + Info: .text + - Name: .rela.text + Type: SHT_RELA + Info: .text + + +# CHECK: SectionHeaderCount: 11 + +# CHECK: Name: .debug_info +# CHECK: Name: .debug_loc +# CHECK: Name: .zdebug_foo +# CHECK: Name: .line +# CHECK: Name: .stab +# CHECK: Name: .gnu.linkonce.wi.1 +# CHECK: Name: .debug_not_a_real_debug_section +# 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 @@ -96,8 +96,12 @@ cl::value_desc("section")); static cl::alias OnlyKeepA("j", cl::desc("Alias for only-keep"), cl::aliasopt(OnlyKeep)); +static cl::opt + OnlyKeepDebug("only-keep-debug", + cl::desc("Removes all but debug information")); 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 @@ -284,6 +288,28 @@ }; } + if (OnlyKeepDebug) { + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + // Allow all implicit removes. + if (RemovePred(Sec)) + return true; + + // Only keep debug sections and the string + symbol table. + // This is much more aggressive than either GNU binutils or elftoolchain + // but GDB accepts this just fine + if (Obj.SectionNames == &Sec || Obj.SymbolTable == &Sec || + Obj.SymbolTable->getStrTab() == &Sec) + return false; + for (const char *S : {".debug", ".zdebug", ".gdb_index", ".line", ".stab", + ".gnu.linkonce.wi."}) + if (Sec.Name.startswith(S)) + return false; + + // Remove everything else. + return true; + }; + } + if (!Keep.empty()) { RemovePred = [RemovePred](const SectionBase &Sec) { // Explicitly keep these sections regardless of previous removes.