[llvm-objcopy] Add support for dwarf fission

This change adds support for dwarf fission.

Differential Revision: https://reviews.llvm.org/D39207

llvm-svn: 317350
This commit is contained in:
Jake Ehrlich 2017-11-03 18:58:41 +00:00
parent 9dcf099944
commit 5de70d996c
4 changed files with 110 additions and 15 deletions

Binary file not shown.

View File

@ -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

View File

@ -368,6 +368,7 @@ public:
Object(const object::ELFObjectFile<ELFT> &Obj);
virtual ~Object() = default;
const SectionBase *getSectionHeaderStrTab() const { return SectionNames; }
void removeSections(std::function<bool(const SectionBase &)> ToRemove);
virtual size_t totalSize() const = 0;
virtual void finalize() = 0;

View File

@ -83,12 +83,63 @@ static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"),
cl::aliasopt(ToRemove));
static cl::opt<bool> StripSections("strip-sections",
cl::desc("Remove all section headers"));
static cl::opt<bool>
StripDWO("strip-dwo", cl::desc("remove all DWARF .dwo sections from file"));
static cl::opt<bool> ExtractDWO(
"extract-dwo",
cl::desc("remove all sections that are not DWARF .dwo sections from file"));
static cl::opt<std::string>
SplitDWO("split-dwo",
cl::desc("equivalent to extract-dwo on the input file to "
"<dwo-file>, then strip-dwo on the input file"),
cl::value_desc("dwo-file"));
using SectionPred = std::function<bool(const SectionBase &Sec)>;
void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) {
bool IsDWOSection(const SectionBase &Sec) {
return Sec.Name.endswith(".dwo");
}
template <class ELFT>
bool OnlyKeepDWOPred(const Object<ELFT> &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 <class ELFT>
void WriteObjectFile(const Object<ELFT> &Obj, StringRef File) {
std::unique_ptr<FileOutputBuffer> Buffer;
ErrorOr<std::unique_ptr<FileOutputBuffer>> 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 <class ELFT>
void SplitDWOToFile(const ELFObjectFile<ELFT> &ObjFile, StringRef File) {
// Construct a second output file for the DWO sections.
ELFObject<ELFT> DWOFile(ObjFile);
DWOFile.removeSections([&](const SectionBase &Sec) {
return OnlyKeepDWOPred<ELFT>(DWOFile, Sec);
});
DWOFile.finalize();
WriteObjectFile(DWOFile, File);
}
void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) {
std::unique_ptr<Object<ELF64LE>> Obj;
if (!OutputFormat.empty() && OutputFormat != "binary")
error("invalid output format '" + OutputFormat + "'");
if (!OutputFormat.empty() && OutputFormat == "binary")
@ -96,6 +147,9 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) {
else
Obj = llvm::make_unique<ELFObject<ELF64LE>>(ObjFile);
if (!SplitDWO.empty())
SplitDWOToFile<ELF64LE>(ObjFile, SplitDWO.getValue());
SectionPred RemovePred = [](const SectionBase &) { return false; };
if (!ToRemove.empty()) {
@ -105,6 +159,16 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) {
};
}
if (StripDWO || !SplitDWO.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 (StripSections) {
RemovePred = [RemovePred](const SectionBase &Sec) {
return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
@ -113,21 +177,8 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) {
}
Obj->removeSections(RemovePred);
Obj->finalize();
ErrorOr<std::unique_ptr<FileOutputBuffer>> 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) {