Index: test/tools/llvm-objcopy/drawf-fission.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/drawf-fission.test @@ -0,0 +1,43 @@ +# RUN: llvm-objcopy -extract-dwo %p/Inputs/dwarf.dwo %t +# RUN: llvm-objcopy -strip-dwo %p/Inputs/dwarf.dwo %t2 +# RUN: llvm-objcopy -split-dwo=%t3 %p/Inputs/dwarf.dwo %t4 +# RUN: llvm-readobj -file-headers -sections %t | FileCheck %s -check-prefix=DWARF +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s -check-prefix=STRIP +# RUN: diff %t %t3 +# RUN: diff %t2 %t4 + +#DWARF: SectionHeaderCount: 8 + +#DWARF: Name: .debug_loc.dwo +#DWARF: Name: .debug_str.dwo +#DWARF: Name: .debug_str_offsets.dwo +#DWARF: Name: .debug_info.dwo +#DWARF: Name: .debug_abbrev.dwo +#DWARF: Name: .debug_line.dwo +#DWARF: Name: .strtab + +#STRIP: SectionHeaderCount: 24 + +#STRIP: Name: .text +#STRIP: Name: .rodata.str1.1 +#STRIP: Name: .debug_str +#STRIP: Name: .debug_abbrev +#STRIP: Name: .debug_info +#STRIP: Name: .debug_ranges +#STRIP: Name: .debug_macinfo +#STRIP: Name: .debug_addr +#STRIP: Name: .debug_pubnames +#STRIP: Name: .debug_pubtypes +#STRIP: Name: .comment +#STRIP: Name: .note.GNU-stack +#STRIP: Name: .debug_frame +#STRIP: Name: .debug_line +#STRIP: Name: .symtab +#STRIP: Name: .rela.text +#STRIP: Name: .rela.debug_info +#STRIP: Name: .rela.debug_addr +#STRIP: Name: .rela.debug_pubnames +#STRIP: Name: .rela.debug_pubtypes +#STRIP: Name: .rela.debug_frame +#STRIP: Name: .rela.debug_line +#STRIP: Name: .strtab Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -349,6 +349,7 @@ bool WriteSectionHeaders = true; Object(const llvm::object::ELFObjectFile &Obj); + const SectionBase *getSectionHeaderStrTab() const { return SectionNames; } void removeSections(std::function ToRemove); virtual size_t totalSize() const = 0; virtual void finalize() = 0; Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -62,12 +62,62 @@ cl::aliasopt(ToRemove)); cl::opt StripSections("strip-sections", cl::desc("Remove all section headers")); +cl::opt StripDWO("strip-dwo", + cl::desc("remove all DWARF .dwo sections from file")); +cl::opt ExtractDWO( + "extract-dwo", + cl::desc("remove all sections that are not DWARF .dwo sections from file")); +cl::opt + GSplitDwarf("split-dwo", + cl::desc("equivalent to strip-dwo and then extract-dwo on " + "the strip-dwo file")); + +bool IsDWOSection(const SectionBase &Sec) { + return Sec.Name.endswith(".dwo"); +} + +template +bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { + // We can't remove the section header string table. + if (&Sec == Obj.getSectionHeaderStrTab()) + return false; + // Short of keeping the string table we want to keep everything that is a DWO + // section and remove everything else. + return !IsDWOSection(Sec); +} + +template +void WriteObjectFile(const Object &Obj, StringRef File) { + std::unique_ptr Buffer; + ErrorOr> BufferOrErr = + FileOutputBuffer::create(File, Obj.totalSize(), + FileOutputBuffer::F_executable); + if (BufferOrErr.getError()) + error("failed to open " + OutputFilename); + else + Buffer = std::move(*BufferOrErr); + Obj.write(*Buffer); + if (auto EC = Buffer->commit()) + reportError(File, EC); +} + +template +void SplitDWOToFile(const ELFObjectFile &ObjFile, StringRef File) { + // Construct a second output file for the DWO sections. + ELFObject GSplitObj(ObjFile); + + GSplitObj.removeSections([&](const SectionBase &Sec) { + return OnlyKeepDWOPred(GSplitObj, Sec); + }); + GSplitObj.finalize(); + WriteObjectFile(GSplitObj, File); +} typedef std::function SectionPred; void CopyBinary(const ELFObjectFile &ObjFile) { - std::unique_ptr Buffer; std::unique_ptr> Obj; + if (!OutputFormat.empty() && OutputFormat != "binary") error("invalid output format '" + OutputFormat + "'"); if (!OutputFormat.empty() && OutputFormat == "binary") @@ -84,6 +134,19 @@ }; } + if (StripDWO || !GSplitDwarf.empty()) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + return IsDWOSection(Sec) || RemovePred(Sec); + }; + + if (ExtractDWO) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + return OnlyKeepDWOPred(*Obj, Sec) || RemovePred(Sec); + }; + + if (!GSplitDwarf.empty()) + SplitDWOToFile(ObjFile, GSplitDwarf.getValue()); + if (StripSections) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; @@ -92,21 +155,8 @@ } Obj->removeSections(RemovePred); - Obj->finalize(); - ErrorOr> BufferOrErr = - FileOutputBuffer::create(OutputFilename, Obj->totalSize(), - FileOutputBuffer::F_executable); - if (BufferOrErr.getError()) - error("failed to open " + OutputFilename); - else - Buffer = std::move(*BufferOrErr); - std::error_code EC; - if (EC) - report_fatal_error(EC.message()); - Obj->write(*Buffer); - if (auto EC = Buffer->commit()) - reportError(OutputFilename, EC); + WriteObjectFile(*Obj, OutputFilename.getValue()); } int main(int argc, char **argv) {