From fbf5e87219c5690c9ae1496a5bbda1198ee87b83 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 8 Sep 2022 01:00:06 -0700 Subject: [PATCH] [MC] Support writing ELFCOMPRESS_ZSTD compressed debug info sections and add --compress-debug-sections=zstd to llvm-mc for testing. Reviewed By: dblaikie Differential Revision: https://reviews.llvm.org/D130724 --- llvm/lib/MC/ELFObjectWriter.cpp | 31 +++-- ...compress-debug-sections-zlib-unavailable.s | 3 +- ...compress-debug-sections-zstd-unavailable.s | 5 + .../MC/ELF/compress-debug-sections-zstd.s | 115 ++++++++++++++++++ llvm/tools/llvm-mc/llvm-mc.cpp | 12 +- 5 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 llvm/test/MC/ELF/compress-debug-sections-zstd-unavailable.s create mode 100644 llvm/test/MC/ELF/compress-debug-sections-zstd.s diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index f6360c4e2f21..bb058690ebda 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -848,27 +848,34 @@ void ELFWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, auto &MC = Asm.getContext(); const auto &MAI = MC.getAsmInfo(); - bool CompressionEnabled = - MAI->compressDebugSections() != DebugCompressionType::None; - if (!CompressionEnabled || !SectionName.startswith(".debug_")) { + const DebugCompressionType CompressionType = MAI->compressDebugSections(); + if (CompressionType == DebugCompressionType::None || + !SectionName.startswith(".debug_")) { Asm.writeSectionData(W.OS, &Section, Layout); return; } - assert(MAI->compressDebugSections() == DebugCompressionType::Z && - "expected zlib style compression"); - SmallVector UncompressedData; raw_svector_ostream VecOS(UncompressedData); Asm.writeSectionData(VecOS, &Section, Layout); + ArrayRef Uncompressed = + makeArrayRef(reinterpret_cast(UncompressedData.data()), + UncompressedData.size()); SmallVector Compressed; - const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB; - compression::zlib::compress( - makeArrayRef(reinterpret_cast(UncompressedData.data()), - UncompressedData.size()), - Compressed); - + uint32_t ChType; + switch (CompressionType) { + case DebugCompressionType::None: + llvm_unreachable("has been handled"); + case DebugCompressionType::Z: + ChType = ELF::ELFCOMPRESS_ZLIB; + break; + case DebugCompressionType::Zstd: + ChType = ELF::ELFCOMPRESS_ZSTD; + break; + } + compression::compress(compression::Params(CompressionType), Uncompressed, + Compressed); if (!maybeWriteCompression(ChType, UncompressedData.size(), Compressed, Sec.getAlignment())) { W.OS << UncompressedData; diff --git a/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s b/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s index 31391582ec2d..fa5ce9f614c5 100644 --- a/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s +++ b/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s @@ -1,4 +1,5 @@ // REQUIRES: !zlib // RUN: not llvm-mc -filetype=obj -compress-debug-sections=zlib -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s -// CHECK: llvm-mc{{[^:]*}}: error: build tools with zlib to enable -compress-debug-sections +// CHECK: llvm-mc{{[^:]*}}: error: build tools with LLVM_ENABLE_ZLIB to enable --compress-debug-sections=zlib +// CHECK-NOT: {{.}} diff --git a/llvm/test/MC/ELF/compress-debug-sections-zstd-unavailable.s b/llvm/test/MC/ELF/compress-debug-sections-zstd-unavailable.s new file mode 100644 index 000000000000..3db2b2752045 --- /dev/null +++ b/llvm/test/MC/ELF/compress-debug-sections-zstd-unavailable.s @@ -0,0 +1,5 @@ +# UNSUPPORTED: zstd +# RUN: not llvm-mc -filetype=obj -compress-debug-sections=zstd -triple x86_64 %s 2>&1 | FileCheck %s + +# CHECK: error: --compress-debug-sections: LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at build time +# CHECK-NOT: {{.}} diff --git a/llvm/test/MC/ELF/compress-debug-sections-zstd.s b/llvm/test/MC/ELF/compress-debug-sections-zstd.s new file mode 100644 index 000000000000..01ae21a2b8ab --- /dev/null +++ b/llvm/test/MC/ELF/compress-debug-sections-zstd.s @@ -0,0 +1,115 @@ +# REQUIRES: zstd + +# RUN: llvm-mc -filetype=obj -triple=x86_64 -compress-debug-sections=zstd %s -o %t +# RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SEC +# RUN: llvm-objdump -s %t | FileCheck %s + +## Check that the large debug sections .debug_line and .debug_frame are compressed +## and have the SHF_COMPRESSED flag. +# SEC: .nonalloc PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 0 0 1 +# SEC: .debug_line PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 C 0 0 8 +# SEC: .debug_abbrev PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 0 0 1 +# SEC: .debug_info PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 0 0 1 +# SEC: .debug_str PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 01 MSC 0 0 8 +# SEC: .debug_frame PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 C 0 0 8 + +# CHECK: Contents of section .debug_line +## ch_type == ELFCOMPRESS_ZSTD (2) +# CHECK-NEXT: 0000 02000000 00000000 55010000 00000000 +# CHECK-NEXT: 0010 01000000 00000000 {{.*}} + +## The compress/decompress round trip should be identical to the uncompressed output. +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.uncom +# RUN: llvm-objcopy --decompress-debug-sections %t %t.decom +# RUN: cmp %t.uncom %t.decom + +## Don't compress a section not named .debug_*. + .section .nonalloc,"",@progbits +.rept 50 +.asciz "aaaaaaaaaa" +.endr + + .section .debug_line,"",@progbits + + .section .debug_abbrev,"",@progbits +.Lsection_abbrev: + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .section .debug_info,"",@progbits + .long 12 # Length of Unit + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_comp_dir + + .text +foo: + .cfi_startproc + .file 1 "Driver.ii" + +.rept 3 +.ifdef I386 + pushl %ebp + .cfi_def_cfa_offset 8 + .cfi_offset %ebp, -8 + movl %esp, %ebp + .cfi_def_cfa_register %ebp + pushl %ebx + pushl %edi + pushl %esi + .cfi_offset %esi, -20 + .cfi_offset %edi, -16 + .cfi_offset %ebx, -12 + .loc 1 1 1 prologue_end + popl %esi + popl %edi + popl %ebx + popl %ebp + .cfi_def_cfa %esp, 4 +.else + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %rbx + .cfi_offset %rbx, -56 + .cfi_offset %r12, -48 + .cfi_offset %r13, -40 + .cfi_offset %r14, -32 + .cfi_offset %r15, -24 + .loc 1 1 1 prologue_end + popq %rbx + popq %r12 + popq %r13 + popq %r14 + popq %r15 + popq %rbp + .cfi_def_cfa %rsp, 8 +.endif +.endr + +# pad out the line table to make sure it's big enough to warrant compression + .irpc i, 123456789 + .irpc j, 0123456789 + .loc 1 \i\j \j + nop + .endr + .endr + .cfi_endproc + .cfi_sections .debug_frame + + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "perfectly compressable data sample *****************************************" diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp index aa380d3fe9bc..1ca30d19fecc 100644 --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -76,8 +76,8 @@ static cl::opt CompressDebugSections( cl::init(DebugCompressionType::None), cl::desc("Choose DWARF debug sections compression:"), cl::values(clEnumValN(DebugCompressionType::None, "none", "No compression"), - clEnumValN(DebugCompressionType::Z, "zlib", - "Use zlib compression")), + clEnumValN(DebugCompressionType::Z, "zlib", "Use zlib"), + clEnumValN(DebugCompressionType::Zstd, "zstd", "Use zstd")), cl::cat(MCCategory)); static cl::opt @@ -399,15 +399,15 @@ int main(int argc, char **argv) { assert(MAI && "Unable to create target asm info!"); MAI->setRelaxELFRelocations(RelaxELFRel); - if (CompressDebugSections != DebugCompressionType::None) { - if (!compression::zlib::isAvailable()) { + if (const char *Reason = compression::getReasonIfUnsupported( + compression::formatFor(CompressDebugSections))) { WithColor::error(errs(), ProgName) - << "build tools with zlib to enable -compress-debug-sections"; + << "--compress-debug-sections: " << Reason; return 1; } - MAI->setCompressDebugSections(CompressDebugSections); } + MAI->setCompressDebugSections(CompressDebugSections); MAI->setPreserveAsmComments(PreserveComments); // Package up features to be passed to target/subtarget