From: David Blaikie Date: Thu, 27 Mar 2014 20:45:58 +0000 (+0000) Subject: DebugInfo: Support for compressed debug info sections X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0a0c4cc56f8bb143443894cb5053c418002587b9;p=oota-llvm.git DebugInfo: Support for compressed debug info sections 1) When creating a .debug_* section and instead create a .zdebug_ section. 2) When creating a fragment in a .zdebug_* section, make it a compressed fragment. 3) When computing the size of a compressed section, compress the data and use the size of the compressed data. 4) Emit the compressed bytes. Also, check that only if a section has a compressed fragment, then that is the only fragment in the section. Assert-fail if the fragment's data is modified after it is compressed. Initial review on llvm-commits by Eric Christopher and Rafael Espindola. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@204958 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 4b519dd7c97..506e555e485 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -51,6 +51,7 @@ public: enum FragmentType { FT_Align, FT_Data, + FT_Compressed, FT_CompactEncodedInst, FT_Fill, FT_Relaxable, @@ -160,6 +161,7 @@ public: return false; case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: + case MCFragment::FT_Compressed: case MCFragment::FT_Data: return true; } @@ -194,7 +196,8 @@ public: static bool classof(const MCFragment *F) { MCFragment::FragmentType Kind = F->getKind(); - return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data; + return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data || + Kind == MCFragment::FT_Compressed; } }; @@ -213,6 +216,11 @@ class MCDataFragment : public MCEncodedFragmentWithFixups { /// Fixups - The list of fixups in this fragment. SmallVector Fixups; +protected: + MCDataFragment(MCFragment::FragmentType FType, MCSectionData *SD = 0) + : MCEncodedFragmentWithFixups(FType, SD), HasInstructions(false), + AlignToBundleEnd(false) {} + public: MCDataFragment(MCSectionData *SD = 0) : MCEncodedFragmentWithFixups(FT_Data, SD), @@ -246,10 +254,21 @@ public: const_fixup_iterator fixup_end() const override {return Fixups.end();} static bool classof(const MCFragment *F) { - return F->getKind() == MCFragment::FT_Data; + return F->getKind() == MCFragment::FT_Data || + F->getKind() == MCFragment::FT_Compressed; } }; +class MCCompressedFragment: public MCDataFragment { + mutable SmallVector CompressedContents; +public: + MCCompressedFragment(MCSectionData *SD = nullptr) + : MCDataFragment(FT_Compressed, SD) {} + const SmallVectorImpl &getCompressedContents() const; + using MCDataFragment::getContents; + SmallVectorImpl &getContents() override; +}; + /// This is a compact (memory-size-wise) fragment for holding an encoded /// instruction (non-relaxable) that has no fixups registered. When applicable, /// it can be used instead of MCDataFragment and lead to lower memory diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index f09bbd1a660..c78d3d574a4 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -100,6 +100,8 @@ MCAsmInfo::MCAsmInfo() { // architecture basis. // - The target subclasses for AArch64, ARM, and X86 handle these cases UseIntegratedAssembler = false; + + CompressDebugSections = false; } MCAsmInfo::~MCAsmInfo() { diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 910295c5d2b..fcf1b50a4f7 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -28,6 +28,9 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/Host.h" using namespace llvm; @@ -230,6 +233,39 @@ MCEncodedFragmentWithFixups::~MCEncodedFragmentWithFixups() { /* *** */ +const SmallVectorImpl &MCCompressedFragment::getCompressedContents() const { + assert(getParent()->size() == 1 && + "Only compress sections containing a single fragment"); + if (CompressedContents.empty()) { + std::unique_ptr CompressedSection; + zlib::Status Success = + zlib::compress(StringRef(getContents().data(), getContents().size()), + CompressedSection); + (void)Success; + assert(Success == zlib::StatusOK); + CompressedContents.push_back('Z'); + CompressedContents.push_back('L'); + CompressedContents.push_back('I'); + CompressedContents.push_back('B'); + uint64_t Size = getContents().size(); + if (sys::IsLittleEndianHost) + Size = sys::SwapByteOrder(Size); + CompressedContents.append(reinterpret_cast(&Size), + reinterpret_cast(&Size + 1)); + CompressedContents.append(CompressedSection->getBuffer().begin(), + CompressedSection->getBuffer().end()); + } + return CompressedContents; +} + +SmallVectorImpl &MCCompressedFragment::getContents() { + assert(CompressedContents.empty() && + "Fragment contents should not be altered after compression"); + return MCDataFragment::getContents(); +} + +/* *** */ + MCSectionData::MCSectionData() : Section(0) {} MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) @@ -430,6 +466,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: return cast(F).getContents().size(); + case MCFragment::FT_Compressed: + return cast(F).getCompressedContents().size(); case MCFragment::FT_Fill: return cast(F).getSize(); @@ -618,6 +656,11 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } + case MCFragment::FT_Compressed: + ++stats::EmittedDataFragments; + OW->WriteBytes(cast(F).getCompressedContents()); + break; + case MCFragment::FT_Data: ++stats::EmittedDataFragments; writeFragmentContents(F, OW); @@ -694,6 +737,7 @@ void MCAssembler::writeSectionData(const MCSectionData *SD, ie = SD->end(); it != ie; ++it) { switch (it->getKind()) { default: llvm_unreachable("Invalid fragment in virtual section!"); + case MCFragment::FT_Compressed: case MCFragment::FT_Data: { // Check that we aren't trying to write a non-zero contents (or fixups) // into a virtual section. This is to support clients which use standard @@ -1021,6 +1065,8 @@ void MCFragment::dump() { switch (getKind()) { case MCFragment::FT_Align: OS << "MCAlignFragment"; break; case MCFragment::FT_Data: OS << "MCDataFragment"; break; + case MCFragment::FT_Compressed: + OS << "MCCompressedFragment"; break; case MCFragment::FT_CompactEncodedInst: OS << "MCCompactEncodedInstFragment"; break; case MCFragment::FT_Fill: OS << "MCFillFragment"; break; @@ -1047,6 +1093,7 @@ void MCFragment::dump() { << " MaxBytesToEmit:" << AF->getMaxBytesToEmit() << ">"; break; } + case MCFragment::FT_Compressed: case MCFragment::FT_Data: { const MCDataFragment *DF = cast(this); OS << "\n "; diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index ede3b3cd235..b228d18ba7f 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -37,13 +37,13 @@ typedef std::map COFFUniqueMapTy; MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri, const MCObjectFileInfo *mofi, const SourceMgr *mgr, - bool DoAutoReset) : - SrcMgr(mgr), MAI(mai), MRI(mri), MOFI(mofi), - Allocator(), Symbols(Allocator), UsedNames(Allocator), - NextUniqueID(0), - CurrentDwarfLoc(0,0,0,DWARF2_FLAG_IS_STMT,0,0), - DwarfLocSeen(false), GenDwarfForAssembly(false), GenDwarfFileNumber(0), - AllowTemporaryLabels(true), DwarfCompileUnitID(0), AutoReset(DoAutoReset) { + bool DoAutoReset) + : SrcMgr(mgr), MAI(mai), MRI(mri), MOFI(mofi), Allocator(), + Symbols(Allocator), UsedNames(Allocator), NextUniqueID(0), + CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0), DwarfLocSeen(false), + GenDwarfForAssembly(false), GenDwarfFileNumber(0), + AllowTemporaryLabels(true), DwarfCompileUnitID(0), + AutoReset(DoAutoReset) { error_code EC = llvm::sys::fs::current_path(CompilationDir); if (EC) @@ -251,6 +251,11 @@ getELFSection(StringRef Section, unsigned Type, unsigned Flags, ELFUniquingMap = new ELFUniqueMapTy(); ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)ELFUniquingMap; + SmallString<32> ZDebugName; + if (MAI->compressDebugSections() && Section.startswith(".debug_") && + Section != ".debug_frame") + Section = (".z" + Section.drop_front(1)).toStringRef(ZDebugName); + // Do the lookup, if we have a hit, return it. std::pair Entry = Map.insert( std::make_pair(SectionGroupPair(Section, Group), (MCSectionELF *)0)); diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 809cb11e36d..35786accb42 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -20,6 +20,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/MC/MCSectionELF.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, MCAsmBackend &TAB, @@ -63,7 +64,11 @@ MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { // When bundling is enabled, we don't want to add data to a fragment that // already has instructions (see MCELFStreamer::EmitInstToData for details) if (!F || (Assembler->isBundlingEnabled() && F->hasInstructions())) { - F = new MCDataFragment(); + const auto *Sec = dyn_cast(&getCurrentSectionData()->getSection()); + if (Sec && Sec->getSectionName().startswith(".zdebug_")) + F = new MCCompressedFragment(); + else + F = new MCDataFragment(); insert(F); } return F; diff --git a/test/MC/ELF/compression.s b/test/MC/ELF/compression.s new file mode 100644 index 00000000000..0293a3c9c57 --- /dev/null +++ b/test/MC/ELF/compression.s @@ -0,0 +1,18 @@ +// RUN: llvm-mc -filetype=obj -compress-debug-sections -triple x86_64-pc-linux-gnu %s -o - | llvm-objdump -s - | FileCheck %s + +// CHECK: Contents of section .zdebug_line: +// Check for the 'ZLIB' file magic at the start of the section +// CHECK-NEXT: ZLIB +// We shouldn't compress the debug_frame section, since it can be relaxed +// CHECK: Contents of section .debug_frame +// CHECK-NOT: ZLIB + + .section .debug_line,"",@progbits + .text +foo: + .cfi_startproc + .file 1 "Driver.ii" + .loc 1 2 0 + nop + .cfi_endproc + .cfi_sections .debug_frame diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index a4b4a844f67..b2e7a81488d 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -49,6 +49,9 @@ OutputFilename("o", cl::desc("Output filename"), static cl::opt ShowEncoding("show-encoding", cl::desc("Show instruction encodings")); +static cl::opt +CompressDebugSections("compress-debug-sections", cl::desc("Compress DWARF debug sections")); + static cl::opt ShowInst("show-inst", cl::desc("Show internal instruction representation")); @@ -381,6 +384,9 @@ int main(int argc, char **argv) { std::unique_ptr MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); assert(MAI && "Unable to create target asm info!"); + if (CompressDebugSections) + MAI->setCompressDebugSections(true); + // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. std::unique_ptr MOFI(new MCObjectFileInfo());