Index: llvm/trunk/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/trunk/include/llvm/MC/MCAsmInfo.h +++ llvm/trunk/include/llvm/MC/MCAsmInfo.h @@ -53,6 +53,12 @@ enum LCOMMType { NoAlignment, ByteAlignment, Log2Alignment }; } +enum class DebugCompressionType { + DCT_None, // no compression + DCT_Zlib, // zlib style complession + DCT_ZlibGnu // zlib-gnu style compression +}; + /// This class is intended to be used as a base class for asm /// properties and features specific to the target. class MCAsmInfo { @@ -356,8 +362,8 @@ /// construction (see LLVMTargetMachine::initAsmInfo()). bool UseIntegratedAssembler; - /// Compress DWARF debug sections. Defaults to false. - bool CompressDebugSections; + /// Compress DWARF debug sections. Defaults to no compression. + DebugCompressionType CompressDebugSections; /// True if the integrated assembler should interpret 'a >> b' constant /// expressions as logical rather than arithmetic. @@ -565,9 +571,11 @@ UseIntegratedAssembler = Value; } - bool compressDebugSections() const { return CompressDebugSections; } + DebugCompressionType compressDebugSections() const { + return CompressDebugSections; + } - void setCompressDebugSections(bool CompressDebugSections) { + void setCompressDebugSections(DebugCompressionType CompressDebugSections) { this->CompressDebugSections = CompressDebugSections; } Index: llvm/trunk/include/llvm/MC/MCSectionELF.h =================================================================== --- llvm/trunk/include/llvm/MC/MCSectionELF.h +++ llvm/trunk/include/llvm/MC/MCSectionELF.h @@ -75,6 +75,7 @@ unsigned getType() const { return Type; } unsigned getFlags() const { return Flags; } unsigned getEntrySize() const { return EntrySize; } + void setFlags(unsigned F) { Flags = F; } const MCSymbolELF *getGroup() const { return Group; } void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, Index: llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp +++ llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp @@ -71,7 +71,7 @@ TmpAsmInfo->setUseIntegratedAssembler(false); if (Options.CompressDebugSections) - TmpAsmInfo->setCompressDebugSections(true); + TmpAsmInfo->setCompressDebugSections(DebugCompressionType::DCT_ZlibGnu); AsmInfo = TmpAsmInfo; } Index: llvm/trunk/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/trunk/lib/MC/ELFObjectWriter.cpp +++ llvm/trunk/lib/MC/ELFObjectWriter.cpp @@ -136,6 +136,10 @@ void align(unsigned Alignment); + bool maybeWriteCompression(uint64_t Size, + SmallVectorImpl &CompressedContents, + bool ZLibStyle, unsigned Alignment); + public: ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) @@ -979,23 +983,38 @@ return RelaSection; } -// Include the debug info compression header: -// "ZLIB" followed by 8 bytes representing the uncompressed size of the section, -// useful for consumers to preallocate a buffer to decompress into. -static bool -prependCompressionHeader(uint64_t Size, - SmallVectorImpl &CompressedContents) { +// Include the debug info compression header. +bool ELFObjectWriter::maybeWriteCompression( + uint64_t Size, SmallVectorImpl &CompressedContents, bool ZLibStyle, + unsigned Alignment) { + if (ZLibStyle) { + uint64_t HdrSize = + is64Bit() ? sizeof(ELF::Elf32_Chdr) : sizeof(ELF::Elf64_Chdr); + if (Size <= HdrSize + CompressedContents.size()) + return false; + // Platform specific header is followed by compressed data. + if (is64Bit()) { + // Write Elf64_Chdr header. + write(static_cast(ELF::ELFCOMPRESS_ZLIB)); + write(static_cast(0)); // ch_reserved field. + write(static_cast(Size)); + write(static_cast(Alignment)); + } else { + // Write Elf32_Chdr header otherwise. + write(static_cast(ELF::ELFCOMPRESS_ZLIB)); + write(static_cast(Size)); + write(static_cast(Alignment)); + } + return true; + } + + // "ZLIB" followed by 8 bytes representing the uncompressed size of the section, + // useful for consumers to preallocate a buffer to decompress into. const StringRef Magic = "ZLIB"; if (Size <= Magic.size() + sizeof(Size) + CompressedContents.size()) return false; - if (sys::IsLittleEndianHost) - sys::swapByteOrder(Size); - CompressedContents.insert(CompressedContents.begin(), - Magic.size() + sizeof(Size), 0); - std::copy(Magic.begin(), Magic.end(), CompressedContents.begin()); - std::copy(reinterpret_cast(&Size), - reinterpret_cast(&Size + 1), - CompressedContents.begin() + Magic.size()); + write(ArrayRef(Magic.begin(), Magic.size())); + writeBE64(Size); return true; } @@ -1007,8 +1026,11 @@ // Compressing debug_frame requires handling alignment fragments which is // more work (possibly generalizing MCAssembler.cpp:writeFragment to allow // for writing to arbitrary buffers) for little benefit. - if (!Asm.getContext().getAsmInfo()->compressDebugSections() || - !SectionName.startswith(".debug_") || SectionName == ".debug_frame") { + bool CompressionEnabled = + Asm.getContext().getAsmInfo()->compressDebugSections() != + DebugCompressionType::DCT_None; + if (!CompressionEnabled || !SectionName.startswith(".debug_") || + SectionName == ".debug_frame") { Asm.writeSectionData(&Section, Layout); return; } @@ -1029,12 +1051,21 @@ return; } - if (!prependCompressionHeader(UncompressedData.size(), CompressedContents)) { + bool ZlibStyle = Asm.getContext().getAsmInfo()->compressDebugSections() == + DebugCompressionType::DCT_Zlib; + if (!maybeWriteCompression(UncompressedData.size(), CompressedContents, + ZlibStyle, Sec.getAlignment())) { getStream() << UncompressedData; return; } - Asm.getContext().renameELFSection(&Section, - (".z" + SectionName.drop_front(1)).str()); + + if (ZlibStyle) + // Set the compressed flag. That is zlib style. + Section.setFlags(Section.getFlags() | ELF::SHF_COMPRESSED); + else + // Add "z" prefix to section name. This is zlib-gnu style. + Asm.getContext().renameELFSection(&Section, + (".z" + SectionName.drop_front(1)).str()); getStream() << CompressedContents; } Index: llvm/trunk/lib/MC/MCAsmInfo.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmInfo.cpp +++ llvm/trunk/lib/MC/MCAsmInfo.cpp @@ -108,7 +108,7 @@ // - The target subclasses for AArch64, ARM, and X86 handle these cases UseIntegratedAssembler = false; - CompressDebugSections = false; + CompressDebugSections = DebugCompressionType::DCT_None; } MCAsmInfo::~MCAsmInfo() { Index: llvm/trunk/test/MC/ELF/compression.s =================================================================== --- llvm/trunk/test/MC/ELF/compression.s +++ llvm/trunk/test/MC/ELF/compression.s @@ -1,27 +1,35 @@ -// RUN: llvm-mc -filetype=obj -compress-debug-sections -triple x86_64-pc-linux-gnu < %s -o %t -// RUN: llvm-objdump -s %t | FileCheck %s +// Check zlib-gnu style +// RUN: llvm-mc -filetype=obj -compress-debug-sections=zlib-gnu -triple x86_64-pc-linux-gnu < %s -o %t +// RUN: llvm-objdump -s %t | FileCheck --check-prefix=CHECK-GNU-STYLE %s // RUN: llvm-dwarfdump -debug-dump=str %t | FileCheck --check-prefix=STR %s -// RUN: llvm-mc -filetype=obj -compress-debug-sections -triple i386-pc-linux-gnu < %s \ -// RUN: | llvm-readobj -symbols - | FileCheck --check-prefix=386-SYMBOLS %s +// RUN: llvm-mc -filetype=obj -compress-debug-sections=zlib-gnu -triple i386-pc-linux-gnu < %s \ +// RUN: | llvm-readobj -symbols - | FileCheck --check-prefix=386-SYMBOLS-GNU %s + +// Check zlib style +// RUN: llvm-mc -filetype=obj -compress-debug-sections=zlib -triple x86_64-pc-linux-gnu < %s -o %t +// RUN: llvm-objdump -s %t | FileCheck --check-prefix=CHECK-ZLIB-STYLE %s +// RUN: llvm-dwarfdump -debug-dump=str %t | FileCheck --check-prefix=STR %s +// RUN: llvm-mc -filetype=obj -compress-debug-sections=zlib -triple i386-pc-linux-gnu < %s \ +// RUN: | llvm-readobj -symbols - | FileCheck --check-prefix=386-SYMBOLS-ZLIB %s +// RUN: llvm-readobj -sections %t | FileCheck --check-prefix=ZLIB-STYLE-FLAGS %s // REQUIRES: zlib // Don't compress small sections, such as this simple debug_abbrev example -// CHECK: Contents of section .debug_abbrev: -// CHECK-NOT: ZLIB -// CHECK-NOT: Contents of +// CHECK-GNU-STYLE: Contents of section .debug_abbrev: +// CHECK-GNU-STYLE-NOT: ZLIB +// CHECK-GNU-STYLE-NOT: Contents of -// CHECK: Contents of section .debug_info: +// CHECK-GNU-STYLE: Contents of section .debug_info: -// CHECK: Contents of section .zdebug_str: +// CHECK-GNU-STYLE: Contents of section .zdebug_str: // Check for the 'ZLIB' file magic at the start of the section only -// CHECK-NEXT: ZLIB -// CHECK-NOT: ZLIB - +// CHECK-GNU-STYLE-NEXT: ZLIB +// CHECK-GNU-STYLE-NOT: ZLIB // FIXME: Handle compressing alignment fragments to support compressing debug_frame -// CHECK: Contents of section .debug_frame: -// CHECK-NOT: ZLIB -// CHECK: Contents of +// CHECK-GNU-STYLE: Contents of section .debug_frame: +// CHECK-GNU-STYLE-NOT: ZLIB +// CHECK-GNU-STYLE: Contents of // Decompress one valid dwarf section just to check that this roundtrips, // we use .zdebug_str section for that @@ -29,9 +37,34 @@ // In x86 32 bit named symbols are used for temporary symbols in merge // sections, so make sure we handle symbols inside compressed sections -// 386-SYMBOLS: Name: .Linfo_string0 -// 386-SYMBOLS-NOT: } -// 386-SYMBOLS: Section: .zdebug_str +// 386-SYMBOLS-GNU: Name: .Linfo_string0 +// 386-SYMBOLS-GNU-NOT: } +// 386-SYMBOLS-GNU: Section: .zdebug_str + +// Now check the zlib style output: + +// Don't compress small sections, such as this simple debug_abbrev example +// CHECK-ZLIB-STYLE: Contents of section .debug_abbrev: +// CHECK-ZLIB-STYLE-NOT: ZLIB +// CHECK-ZLIB-STYLE-NOT: Contents of +// CHECK-ZLIB-STYLE: Contents of section .debug_info: +// FIXME: Handle compressing alignment fragments to support compressing debug_frame +// CHECK-ZLIB-STYLE: Contents of section .debug_frame: +// CHECK-ZLIB-STYLE-NOT: ZLIB +// CHECK-ZLIB-STYLE: Contents of + +// Check that debug_line section was not renamed, so it is +// zlib-style, not zlib-gnu one. Check that SHF_COMPRESSED was set. +// ZLIB-STYLE-FLAGS: Section { +// ZLIB-STYLE-FLAGS: Index: +// ZLIB-STYLE-FLAGS: Name: .debug_str +// ZLIB-STYLE-FLAGS-NEXT: Type: SHT_PROGBITS +// ZLIB-STYLE-FLAGS-NEXT: Flags [ +// ZLIB-STYLE-FLAGS-NEXT: SHF_COMPRESSED + +// 386-SYMBOLS-ZLIB: Name: .Linfo_string0 +// 386-SYMBOLS-ZLIB-NOT: } +// 386-SYMBOLS-ZLIB: Section: .debug_str .section .debug_line,"",@progbits Index: llvm/trunk/tools/llvm-mc/llvm-mc.cpp =================================================================== --- llvm/trunk/tools/llvm-mc/llvm-mc.cpp +++ llvm/trunk/tools/llvm-mc/llvm-mc.cpp @@ -52,9 +52,18 @@ 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 +CompressDebugSections("compress-debug-sections", cl::ValueOptional, + cl::init(DebugCompressionType::DCT_None), + cl::desc("Choose DWARF debug sections compression:"), + cl::values( + clEnumValN(DebugCompressionType::DCT_None, "none", + "No compression"), + clEnumValN(DebugCompressionType::DCT_Zlib, "zlib", + "Use zlib compression"), + clEnumValN(DebugCompressionType::DCT_ZlibGnu, "zlib-gnu", + "Use zlib-gnu compression (depricated)"), + clEnumValEnd)); static cl::opt ShowInst("show-inst", cl::desc("Show internal instruction representation")); @@ -407,13 +416,13 @@ std::unique_ptr MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); assert(MAI && "Unable to create target asm info!"); - if (CompressDebugSections) { + if (CompressDebugSections != DebugCompressionType::DCT_None) { if (!zlib::isAvailable()) { errs() << ProgName << ": build tools with zlib to enable -compress-debug-sections"; return 1; } - MAI->setCompressDebugSections(true); + MAI->setCompressDebugSections(CompressDebugSections); } // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and