[llvm] [BOLT] Support SHF_COMPRESSED DWARF debug sections. (PR #215835)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 13 06:10:07 PDT 2026


https://github.com/andreasmullen updated https://github.com/llvm/llvm-project/pull/215835

>From 983a8dc12786e7eca6bba6a00a9cddb7a3960dc3 Mon Sep 17 00:00:00 2001
From: Andreas Mullen <Andreas.Mullen at arm.com>
Date: Wed, 12 Aug 2026 08:53:10 +0000
Subject: [PATCH] [BOLT] Support SHF_COMPRESSED DWARF debug sections.

---
 bolt/lib/Core/DebugData.cpp                   |   8 +-
 bolt/lib/Rewrite/RewriteInstance.cpp          | 145 ++++++++-
 .../AArch64/compressed-debug-sections.test    |   7 +-
 .../AArch64/zlib-compressed-debug-sections.s  | 285 ++++++++++++++++++
 .../AArch64/zstd-compressed-debug-sections.s  | 285 ++++++++++++++++++
 bolt/test/CMakeLists.txt                      |   2 +
 bolt/test/lit.site.cfg.py.in                  |   2 +
 7 files changed, 715 insertions(+), 19 deletions(-)
 create mode 100644 bolt/test/AArch64/zlib-compressed-debug-sections.s
 create mode 100644 bolt/test/AArch64/zstd-compressed-debug-sections.s

diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index 6bae374b460a7..a2dac9091861e 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -1219,11 +1219,9 @@ void DwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
 // Bonus is that when we output a final binary we can reuse .debug_line_str
 // section. So we don't have to do the SHF_ALLOC trick we did with
 // .debug_line.
-static void parseAndPopulateDebugLineStr(BinarySection &LineStrSection,
-                                         MCDwarfLineStr &LineStr,
+static void parseAndPopulateDebugLineStr(MCDwarfLineStr &LineStr,
                                          BinaryContext &BC) {
-  DataExtractor StrData(LineStrSection.getContents(),
-                        BC.DwCtx->isLittleEndian());
+  DataExtractor StrData = BC.DwCtx->getLineStringExtractor();
   uint64_t Offset = 0;
   while (StrData.isValidOffset(Offset)) {
     const uint64_t StrOffset = Offset;
@@ -1262,7 +1260,7 @@ void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) {
   // .debug_line, so need to check if section exists.
   if (LineStrSection) {
     LineStr.emplace(*BC.Ctx);
-    parseAndPopulateDebugLineStr(*LineStrSection, *LineStr, BC);
+    parseAndPopulateDebugLineStr(*LineStr, BC);
   }
 
   // Switch to the section where the table will be emitted into.
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index fd445f7550d16..9b7d8b68415e6 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -48,10 +48,12 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/Decompressor.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Alignment.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
 #include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
@@ -61,6 +63,7 @@
 #include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
+#include <cstring>
 #include <fstream>
 #include <memory>
 #include <optional>
@@ -386,6 +389,38 @@ MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
 
 namespace {
 
+static Error reportDecompressionError(StringRef SectionName, Error E) {
+  return createStringError("failed to decompress section '" + SectionName +
+                           "': " + toString(std::move(E)));
+}
+
+static Error validateCompressedDebugSections(const ELFObjectFileBase &File) {
+  for (const SectionRef &Section : File.sections()) {
+    Expected<StringRef> NameOrErr = Section.getName();
+    if (!NameOrErr)
+      return NameOrErr.takeError();
+
+    if (!RewriteInstance::isDebugSection(*NameOrErr) || !Section.isCompressed())
+      continue;
+
+    Expected<StringRef> SectionContentsOrErr = Section.getContents();
+    if (!SectionContentsOrErr)
+      return SectionContentsOrErr.takeError();
+
+    Expected<Decompressor> DecompressorOrErr =
+        Decompressor::create(*NameOrErr, *SectionContentsOrErr,
+                             File.isLittleEndian(), File.is64Bit());
+    if (!DecompressorOrErr)
+      return reportDecompressionError(*NameOrErr,
+                                      DecompressorOrErr.takeError());
+
+    SmallVector<uint8_t, 0> DecompressedContents;
+    if (Error E = DecompressorOrErr->resizeAndDecompress(DecompressedContents))
+      return reportDecompressionError(*NameOrErr, std::move(E));
+  }
+  return Error::success();
+}
+
 bool refersToReorderedSection(ErrorOr<BinarySection &> Section) {
   return llvm::any_of(opts::ReorderData, [&](const std::string &SectionName) {
     return Section && Section->getName() == SectionName;
@@ -446,6 +481,13 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc,
     }
   }
 
+  if (opts::UpdateDebugSections) {
+    if (Error E = validateCompressedDebugSections(*File)) {
+      Err = std::move(E);
+      return;
+    }
+  }
+
   Relocation::Arch = TheTriple.getArch();
   auto BCOrErr = BinaryContext::createBinaryContext(
       TheTriple, std::make_shared<orc::SymbolStringPool>(), File->getFileName(),
@@ -2393,17 +2435,9 @@ Error RewriteInstance::readSpecialSections() {
     check_error(SectionNameOrErr.takeError(), "cannot get section name");
     StringRef SectionName = *SectionNameOrErr;
 
-    // Detect a debug section and check if it's compressed.
-    // Compressed debug sections currently aren't supported.
+    // Detect a debug section.
     if (isDebugSection(SectionName)) {
       HasDebugInfo = true;
-      if (opts::UpdateDebugSections && isCompressedDebugSection(Section)) {
-        return createStringError(errc::not_supported,
-                                 Twine("compressed debug section '") +
-                                     SectionName +
-                                     "' detected. --update-debug-sections "
-                                     "requires uncompressed debug info");
-      }
     }
 
     if (Error E = Section.getContents().takeError())
@@ -4964,6 +4998,66 @@ uint64_t appendPadding(raw_pwrite_stream &OS, uint64_t Offset,
 
 }
 
+template <typename ELFT>
+static Expected<uint64_t>
+writeCompressedDebugSection(StringRef SectionName,
+                            ArrayRef<uint8_t> CompressedSection,
+                            raw_ostream &OS, StringRef UncompressedSection) {
+  using ChdrTy = typename ELFT::Chdr;
+
+  if (CompressedSection.size() < sizeof(ChdrTy)) {
+    return createStringError(
+        errc::invalid_argument,
+        "Compressed debug section '" + SectionName +
+            "' is too small to contain a valid compression header.");
+  }
+
+  // Copy the InputHeader from the compressed section to the new recompressed
+  // section as they remain unchanged.
+  ChdrTy InputHeader{};
+  std::memcpy(&InputHeader, CompressedSection.data(), sizeof(ChdrTy));
+
+  DebugCompressionType CompressionMethod;
+  switch (InputHeader.ch_type) {
+  case ELF::ELFCOMPRESS_ZLIB:
+    CompressionMethod = DebugCompressionType::Zlib;
+    break;
+  case ELF::ELFCOMPRESS_ZSTD:
+    CompressionMethod = DebugCompressionType::Zstd;
+    break;
+  default:
+    return createStringError(
+        errc::not_supported,
+        "Unsupported compression method for debug section '" + SectionName +
+            "'");
+  }
+
+  // Ensure the compression method is supported by the current build.
+  if (const char *Reason = compression::getReasonIfUnsupported(
+          compression::formatFor(CompressionMethod))) {
+    return createStringError(errc::not_supported,
+                             "Compression method for debug section '" +
+                                 SectionName + "' is not supported: " + Reason);
+  }
+
+  SmallVector<uint8_t, 0> CompressedData;
+  compression::compress(compression::Params(CompressionMethod),
+                        arrayRefFromStringRef(UncompressedSection),
+                        CompressedData);
+
+  ChdrTy OutputHeader{};
+  OutputHeader.ch_type = InputHeader.ch_type;
+  OutputHeader.ch_addralign = InputHeader.ch_addralign;
+  OutputHeader.ch_size = UncompressedSection.size();
+
+  OS.write(reinterpret_cast<const char *>(&OutputHeader), sizeof(ChdrTy));
+  OS.write(reinterpret_cast<const char *>(CompressedData.data()),
+           CompressedData.size());
+
+  // Return the total size of the compressed section.
+  return sizeof(ChdrTy) + CompressedData.size();
+}
+
 template <typename ELFT>
 void RewriteInstance::rewriteNoteSections(ELFObjectFile<ELFT> *File) {
   using ShdrTy = typename ELFT::Shdr;
@@ -5019,7 +5113,9 @@ void RewriteInstance::rewriteNoteSections(ELFObjectFile<ELFT> *File) {
         DataWritten = true;
 
         // Add padding as the section extension might rely on the alignment.
-        Size = appendPadding(OS, Size, Section.sh_addralign);
+        if (!(Section.sh_flags & ELF::SHF_COMPRESSED)) {
+          Size = appendPadding(OS, Size, Section.sh_addralign);
+        }
       }
     }
 
@@ -5030,7 +5126,34 @@ void RewriteInstance::rewriteNoteSections(ELFObjectFile<ELFT> *File) {
     if (BSec->getAllocAddress()) {
       assert(!DataWritten && "Writing section twice.");
       (void)DataWritten;
-      Size += BSec->write(OS);
+
+      // If this is a debug-section and it is has been de-compressed.
+      if (isDebugSection(SectionName) &&
+          (Section.sh_flags & ELF::SHF_COMPRESSED)) {
+        // Get the uncompressed section data from the BinarySection.
+        Expected<ArrayRef<uint8_t>> UncompressedDataOrErr =
+            Obj.getSectionContents(Section);
+        if (!UncompressedDataOrErr) {
+          consumeError(UncompressedDataOrErr.takeError());
+          report_fatal_error("Failed to get uncompressed data for section '" +
+                             SectionName + "'");
+        }
+
+        // Write the re-compressed section to the output stream.
+        Expected<uint64_t> CompressedSizeOrErr =
+            writeCompressedDebugSection<ELFT>(SectionName,
+                                              *UncompressedDataOrErr, OS,
+                                              BSec->getOutputContents());
+        if (!CompressedSizeOrErr) {
+          consumeError(CompressedSizeOrErr.takeError());
+          report_fatal_error("Failed to write re-compressed debug section '" +
+                             SectionName + "'");
+        }
+
+        Size += *CompressedSizeOrErr;
+      } else {
+        Size += BSec->write(OS);
+      }
     }
 
     BSec->setOutputFileOffset(NextAvailableOffset);
diff --git a/bolt/test/AArch64/compressed-debug-sections.test b/bolt/test/AArch64/compressed-debug-sections.test
index 8d5231b36896a..939f8a9d6d092 100644
--- a/bolt/test/AArch64/compressed-debug-sections.test
+++ b/bolt/test/AArch64/compressed-debug-sections.test
@@ -1,6 +1,7 @@
-// Checks that BOLT correctly errors out on compressed debug sections.
+// Checks that BOLT can error gracefully when given corrupted, zstd compressed DWARF
+// debug information.
 //
+// REQUIRES: zstd
 // RUN: yaml2obj %p/Inputs/compressed-debug-sections.yaml -o %t.exe
 // RUN: not llvm-bolt %t.exe -o %t.bolt --update-debug-sections 2>&1 | FileCheck %s
-//
-// CHECK: compressed debug section '.debug_info' detected. --update-debug-sections requires uncompressed debug info
+// CHECK: failed to decompress section '.debug_info': Src size is incorrect
diff --git a/bolt/test/AArch64/zlib-compressed-debug-sections.s b/bolt/test/AArch64/zlib-compressed-debug-sections.s
new file mode 100644
index 0000000000000..a88f8c1418f4d
--- /dev/null
+++ b/bolt/test/AArch64/zlib-compressed-debug-sections.s
@@ -0,0 +1,285 @@
+## Checks that BOLT can correctly decompress, process and recompress zlib
+## compressed DWARF debug information.
+#
+# REQUIRES: zlib
+#
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux-gnu %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.exe
+# RUN: llvm-dwarfdump --verify %t.exe 2>&1 | FileCheck %s --check-prefix=VERIFY-DWARF
+# RUN: llvm-objcopy --compress-debug-sections=zlib %t.exe %t.zlib
+# RUN: llvm-readelf -t %t.zlib | FileCheck %s --check-prefix=INPUT-ELF
+# INPUT-ELF: .debug_info
+# INPUT-ELF: COMPRESSED
+# INPUT-ELF-NEXT: ZLIB,
+#
+# RUN: llvm-bolt %t.zlib -o %t.bolt.exe --update-debug-sections
+# RUN: llvm-readelf -t %t.bolt.exe | FileCheck %s --check-prefix=BOLTED-ELF
+# BOLTED-ELF: .debug_info
+# BOLTED-ELF-NEXT: {{.*}}PROGBITS
+# BOLTED-ELF-NEXT: {{.*}}COMPRESSED
+# BOLTED-ELF-NEXT: {{.*}}ZLIB,
+#
+# RUN: llvm-dwarfdump --verify %t.bolt.exe 2>&1 | FileCheck %s --check-prefix=VERIFY-DWARF
+# VERIFY-DWARF: No errors.
+
+	.file	"main.c"
+	.text
+	.globl	square                          // -- Begin function square
+	.p2align	2
+	.type	square, at function
+square:                                 // @square
+.Lfunc_begin0:
+	.file	0 "." "main.c" md5 0x23769560df9190f53a5be0173a252c67
+	.loc	0 1 0                           // main.c:1:0
+	.cfi_startproc
+// %bb.0:                               // %entry
+	sub	sp, sp, #16
+	.cfi_def_cfa_offset 16
+	str	w0, [sp, #12]
+.Ltmp1:
+	.loc	0 1 28 prologue_end             // main.c:1:28
+	ldr	w8, [sp, #12]
+	.loc	0 1 32 is_stmt 0                // main.c:1:32
+	ldr	w9, [sp, #12]
+	.loc	0 1 30                          // main.c:1:30
+	mul	w0, w8, w9
+	.loc	0 1 21 epilogue_begin           // main.c:1:21
+	add	sp, sp, #16
+	.cfi_def_cfa_offset 0
+	ret
+.Ltmp2:
+.Lfunc_end0:
+	.size	square, .Lfunc_end0-square
+	.cfi_endproc
+                                        // -- End function
+	.globl	main                            // -- Begin function main
+	.p2align	2
+	.type	main, at function
+main:                                   // @main
+.Lfunc_begin1:
+	.loc	0 2 0 is_stmt 1                 // main.c:2:0
+	.cfi_startproc
+// %bb.0:                               // %entry
+	sub	sp, sp, #32
+	.cfi_def_cfa_offset 32
+	stp	x29, x30, [sp, #16]             // 16-byte Folded Spill
+	add	x29, sp, #16
+	.cfi_def_cfa w29, 16
+	.cfi_offset w30, -8
+	.cfi_offset w29, -16
+	stur	wzr, [x29, #-4]
+.Ltmp3:
+	.loc	0 2 25 prologue_end             // main.c:2:25
+	mov	w0, #7                          // =0x7
+	bl	square
+	.loc	0 2 35 is_stmt 0                // main.c:2:35
+	subs	w8, w0, #49
+	cset	w0, ne
+	.cfi_def_cfa wsp, 32
+	.loc	0 2 18 epilogue_begin           // main.c:2:18
+	ldp	x29, x30, [sp, #16]             // 16-byte Folded Reload
+	add	sp, sp, #32
+	.cfi_def_cfa_offset 0
+	.cfi_restore w30
+	.cfi_restore w29
+	ret
+.Ltmp4:
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
+                                        // -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	1                               // Abbreviation Code
+	.byte	17                              // DW_TAG_compile_unit
+	.byte	1                               // DW_CHILDREN_yes
+	.byte	37                              // DW_AT_producer
+	.byte	37                              // DW_FORM_strx1
+	.byte	19                              // DW_AT_language
+	.byte	5                               // DW_FORM_data2
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	114                             // DW_AT_str_offsets_base
+	.byte	23                              // DW_FORM_sec_offset
+	.byte	16                              // DW_AT_stmt_list
+	.byte	23                              // DW_FORM_sec_offset
+	.byte	27                              // DW_AT_comp_dir
+	.byte	37                              // DW_FORM_strx1
+	.byte	17                              // DW_AT_low_pc
+	.byte	27                              // DW_FORM_addrx
+	.byte	18                              // DW_AT_high_pc
+	.byte	6                               // DW_FORM_data4
+	.byte	115                             // DW_AT_addr_base
+	.byte	23                              // DW_FORM_sec_offset
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	2                               // Abbreviation Code
+	.byte	46                              // DW_TAG_subprogram
+	.byte	1                               // DW_CHILDREN_yes
+	.byte	17                              // DW_AT_low_pc
+	.byte	27                              // DW_FORM_addrx
+	.byte	18                              // DW_AT_high_pc
+	.byte	6                               // DW_FORM_data4
+	.byte	64                              // DW_AT_frame_base
+	.byte	24                              // DW_FORM_exprloc
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	58                              // DW_AT_decl_file
+	.byte	11                              // DW_FORM_data1
+	.byte	59                              // DW_AT_decl_line
+	.byte	11                              // DW_FORM_data1
+	.byte	39                              // DW_AT_prototyped
+	.byte	25                              // DW_FORM_flag_present
+	.byte	73                              // DW_AT_type
+	.byte	19                              // DW_FORM_ref4
+	.byte	63                              // DW_AT_external
+	.byte	25                              // DW_FORM_flag_present
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	3                               // Abbreviation Code
+	.byte	5                               // DW_TAG_formal_parameter
+	.byte	0                               // DW_CHILDREN_no
+	.byte	2                               // DW_AT_location
+	.byte	24                              // DW_FORM_exprloc
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	58                              // DW_AT_decl_file
+	.byte	11                              // DW_FORM_data1
+	.byte	59                              // DW_AT_decl_line
+	.byte	11                              // DW_FORM_data1
+	.byte	73                              // DW_AT_type
+	.byte	19                              // DW_FORM_ref4
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	4                               // Abbreviation Code
+	.byte	46                              // DW_TAG_subprogram
+	.byte	0                               // DW_CHILDREN_no
+	.byte	17                              // DW_AT_low_pc
+	.byte	27                              // DW_FORM_addrx
+	.byte	18                              // DW_AT_high_pc
+	.byte	6                               // DW_FORM_data4
+	.byte	64                              // DW_AT_frame_base
+	.byte	24                              // DW_FORM_exprloc
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	58                              // DW_AT_decl_file
+	.byte	11                              // DW_FORM_data1
+	.byte	59                              // DW_AT_decl_line
+	.byte	11                              // DW_FORM_data1
+	.byte	39                              // DW_AT_prototyped
+	.byte	25                              // DW_FORM_flag_present
+	.byte	73                              // DW_AT_type
+	.byte	19                              // DW_FORM_ref4
+	.byte	63                              // DW_AT_external
+	.byte	25                              // DW_FORM_flag_present
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	5                               // Abbreviation Code
+	.byte	36                              // DW_TAG_base_type
+	.byte	0                               // DW_CHILDREN_no
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	62                              // DW_AT_encoding
+	.byte	11                              // DW_FORM_data1
+	.byte	11                              // DW_AT_byte_size
+	.byte	11                              // DW_FORM_data1
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	0                               // EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.word	.Ldebug_info_end0-.Ldebug_info_start0 // Length of Unit
+.Ldebug_info_start0:
+	.hword	5                               // DWARF version number
+	.byte	1                               // DWARF Unit Type
+	.byte	8                               // Address Size (in bytes)
+	.word	.debug_abbrev                   // Offset Into Abbrev. Section
+	.byte	1                               // Abbrev [1] 0xc:0x46 DW_TAG_compile_unit
+	.byte	0                               // DW_AT_producer
+	.hword	29                              // DW_AT_language
+	.byte	1                               // DW_AT_name
+	.word	.Lstr_offsets_base0             // DW_AT_str_offsets_base
+	.word	.Lline_table_start0             // DW_AT_stmt_list
+	.byte	2                               // DW_AT_comp_dir
+	.byte	0                               // DW_AT_low_pc
+	.word	.Lfunc_end1-.Lfunc_begin0       // DW_AT_high_pc
+	.word	.Laddr_table_base0              // DW_AT_addr_base
+	.byte	2                               // Abbrev [2] 0x23:0x1b DW_TAG_subprogram
+	.byte	0                               // DW_AT_low_pc
+	.word	.Lfunc_end0-.Lfunc_begin0       // DW_AT_high_pc
+	.byte	1                               // DW_AT_frame_base
+	.byte	111
+	.byte	3                               // DW_AT_name
+	.byte	0                               // DW_AT_decl_file
+	.byte	1                               // DW_AT_decl_line
+                                        // DW_AT_prototyped
+	.word	77                              // DW_AT_type
+                                        // DW_AT_external
+	.byte	3                               // Abbrev [3] 0x32:0xb DW_TAG_formal_parameter
+	.byte	2                               // DW_AT_location
+	.byte	145
+	.byte	12
+	.byte	6                               // DW_AT_name
+	.byte	0                               // DW_AT_decl_file
+	.byte	1                               // DW_AT_decl_line
+	.word	77                              // DW_AT_type
+	.byte	0                               // End Of Children Mark
+	.byte	4                               // Abbrev [4] 0x3e:0xf DW_TAG_subprogram
+	.byte	1                               // DW_AT_low_pc
+	.word	.Lfunc_end1-.Lfunc_begin1       // DW_AT_high_pc
+	.byte	1                               // DW_AT_frame_base
+	.byte	109
+	.byte	5                               // DW_AT_name
+	.byte	0                               // DW_AT_decl_file
+	.byte	2                               // DW_AT_decl_line
+                                        // DW_AT_prototyped
+	.word	77                              // DW_AT_type
+                                        // DW_AT_external
+	.byte	5                               // Abbrev [5] 0x4d:0x4 DW_TAG_base_type
+	.byte	4                               // DW_AT_name
+	.byte	5                               // DW_AT_encoding
+	.byte	4                               // DW_AT_byte_size
+	.byte	0                               // End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.word	32                              // Length of String Offsets Set
+	.hword	5
+	.hword	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang"                         // string offset=0 ; clang
+.Linfo_string1:
+	.asciz	"main.c"                        // string offset=6 ; main.c
+.Linfo_string2:
+	.asciz	"."                             // string offset=13 ; .
+.Linfo_string3:
+	.asciz	"square"                        // string offset=15 ; square
+.Linfo_string4:
+	.asciz	"int"                           // string offset=22 ; int
+.Linfo_string5:
+	.asciz	"main"                          // string offset=26 ; main
+.Linfo_string6:
+	.asciz	"x"                             // string offset=31 ; x
+	.section	.debug_str_offsets,"", at progbits
+	.word	.Linfo_string0
+	.word	.Linfo_string1
+	.word	.Linfo_string2
+	.word	.Linfo_string3
+	.word	.Linfo_string4
+	.word	.Linfo_string5
+	.word	.Linfo_string6
+	.section	.debug_addr,"", at progbits
+	.word	.Ldebug_addr_end0-.Ldebug_addr_start0 // Length of contribution
+.Ldebug_addr_start0:
+	.hword	5                               // DWARF version number
+	.byte	8                               // Address size
+	.byte	0                               // Segment selector size
+.Laddr_table_base0:
+	.xword	.Lfunc_begin0
+	.xword	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.addrsig_sym square
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/bolt/test/AArch64/zstd-compressed-debug-sections.s b/bolt/test/AArch64/zstd-compressed-debug-sections.s
new file mode 100644
index 0000000000000..4aeef2e1b82c4
--- /dev/null
+++ b/bolt/test/AArch64/zstd-compressed-debug-sections.s
@@ -0,0 +1,285 @@
+## Checks that BOLT can correctly decompress, process and recompress zstd
+## compressed DWARF debug information.
+#
+# REQUIRES: zstd
+#
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux-gnu %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.exe
+# RUN: llvm-dwarfdump --verify %t.exe 2>&1 | FileCheck %s --check-prefix=VERIFY-DWARF
+# RUN: llvm-objcopy --compress-debug-sections=zstd %t.exe %t.zstd
+# RUN: llvm-readelf -t %t.zstd | FileCheck %s --check-prefix=INPUT-ELF
+# INPUT-ELF: .debug_info
+# INPUT-ELF: COMPRESSED
+# INPUT-ELF-NEXT: ZSTD,
+#
+# RUN: llvm-bolt %t.zstd -o %t.bolt.exe --update-debug-sections
+# RUN: llvm-readelf -t %t.bolt.exe | FileCheck %s --check-prefix=BOLTED-ELF
+# BOLTED-ELF: .debug_info
+# BOLTED-ELF-NEXT: {{.*}}PROGBITS
+# BOLTED-ELF-NEXT: {{.*}}COMPRESSED
+# BOLTED-ELF-NEXT: {{.*}}ZSTD,
+#
+# RUN: llvm-dwarfdump --verify %t.bolt.exe 2>&1 | FileCheck %s --check-prefix=VERIFY-DWARF
+# VERIFY-DWARF: No errors.
+
+	.file	"main.c"
+	.text
+	.globl	square                          // -- Begin function square
+	.p2align	2
+	.type	square, at function
+square:                                 // @square
+.Lfunc_begin0:
+	.file	0 "." "main.c" md5 0x23769560df9190f53a5be0173a252c67
+	.loc	0 1 0                           // main.c:1:0
+	.cfi_startproc
+// %bb.0:                               // %entry
+	sub	sp, sp, #16
+	.cfi_def_cfa_offset 16
+	str	w0, [sp, #12]
+.Ltmp1:
+	.loc	0 1 28 prologue_end             // main.c:1:28
+	ldr	w8, [sp, #12]
+	.loc	0 1 32 is_stmt 0                // main.c:1:32
+	ldr	w9, [sp, #12]
+	.loc	0 1 30                          // main.c:1:30
+	mul	w0, w8, w9
+	.loc	0 1 21 epilogue_begin           // main.c:1:21
+	add	sp, sp, #16
+	.cfi_def_cfa_offset 0
+	ret
+.Ltmp2:
+.Lfunc_end0:
+	.size	square, .Lfunc_end0-square
+	.cfi_endproc
+                                        // -- End function
+	.globl	main                            // -- Begin function main
+	.p2align	2
+	.type	main, at function
+main:                                   // @main
+.Lfunc_begin1:
+	.loc	0 2 0 is_stmt 1                 // main.c:2:0
+	.cfi_startproc
+// %bb.0:                               // %entry
+	sub	sp, sp, #32
+	.cfi_def_cfa_offset 32
+	stp	x29, x30, [sp, #16]             // 16-byte Folded Spill
+	add	x29, sp, #16
+	.cfi_def_cfa w29, 16
+	.cfi_offset w30, -8
+	.cfi_offset w29, -16
+	stur	wzr, [x29, #-4]
+.Ltmp3:
+	.loc	0 2 25 prologue_end             // main.c:2:25
+	mov	w0, #7                          // =0x7
+	bl	square
+	.loc	0 2 35 is_stmt 0                // main.c:2:35
+	subs	w8, w0, #49
+	cset	w0, ne
+	.cfi_def_cfa wsp, 32
+	.loc	0 2 18 epilogue_begin           // main.c:2:18
+	ldp	x29, x30, [sp, #16]             // 16-byte Folded Reload
+	add	sp, sp, #32
+	.cfi_def_cfa_offset 0
+	.cfi_restore w30
+	.cfi_restore w29
+	ret
+.Ltmp4:
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
+                                        // -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	1                               // Abbreviation Code
+	.byte	17                              // DW_TAG_compile_unit
+	.byte	1                               // DW_CHILDREN_yes
+	.byte	37                              // DW_AT_producer
+	.byte	37                              // DW_FORM_strx1
+	.byte	19                              // DW_AT_language
+	.byte	5                               // DW_FORM_data2
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	114                             // DW_AT_str_offsets_base
+	.byte	23                              // DW_FORM_sec_offset
+	.byte	16                              // DW_AT_stmt_list
+	.byte	23                              // DW_FORM_sec_offset
+	.byte	27                              // DW_AT_comp_dir
+	.byte	37                              // DW_FORM_strx1
+	.byte	17                              // DW_AT_low_pc
+	.byte	27                              // DW_FORM_addrx
+	.byte	18                              // DW_AT_high_pc
+	.byte	6                               // DW_FORM_data4
+	.byte	115                             // DW_AT_addr_base
+	.byte	23                              // DW_FORM_sec_offset
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	2                               // Abbreviation Code
+	.byte	46                              // DW_TAG_subprogram
+	.byte	1                               // DW_CHILDREN_yes
+	.byte	17                              // DW_AT_low_pc
+	.byte	27                              // DW_FORM_addrx
+	.byte	18                              // DW_AT_high_pc
+	.byte	6                               // DW_FORM_data4
+	.byte	64                              // DW_AT_frame_base
+	.byte	24                              // DW_FORM_exprloc
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	58                              // DW_AT_decl_file
+	.byte	11                              // DW_FORM_data1
+	.byte	59                              // DW_AT_decl_line
+	.byte	11                              // DW_FORM_data1
+	.byte	39                              // DW_AT_prototyped
+	.byte	25                              // DW_FORM_flag_present
+	.byte	73                              // DW_AT_type
+	.byte	19                              // DW_FORM_ref4
+	.byte	63                              // DW_AT_external
+	.byte	25                              // DW_FORM_flag_present
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	3                               // Abbreviation Code
+	.byte	5                               // DW_TAG_formal_parameter
+	.byte	0                               // DW_CHILDREN_no
+	.byte	2                               // DW_AT_location
+	.byte	24                              // DW_FORM_exprloc
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	58                              // DW_AT_decl_file
+	.byte	11                              // DW_FORM_data1
+	.byte	59                              // DW_AT_decl_line
+	.byte	11                              // DW_FORM_data1
+	.byte	73                              // DW_AT_type
+	.byte	19                              // DW_FORM_ref4
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	4                               // Abbreviation Code
+	.byte	46                              // DW_TAG_subprogram
+	.byte	0                               // DW_CHILDREN_no
+	.byte	17                              // DW_AT_low_pc
+	.byte	27                              // DW_FORM_addrx
+	.byte	18                              // DW_AT_high_pc
+	.byte	6                               // DW_FORM_data4
+	.byte	64                              // DW_AT_frame_base
+	.byte	24                              // DW_FORM_exprloc
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	58                              // DW_AT_decl_file
+	.byte	11                              // DW_FORM_data1
+	.byte	59                              // DW_AT_decl_line
+	.byte	11                              // DW_FORM_data1
+	.byte	39                              // DW_AT_prototyped
+	.byte	25                              // DW_FORM_flag_present
+	.byte	73                              // DW_AT_type
+	.byte	19                              // DW_FORM_ref4
+	.byte	63                              // DW_AT_external
+	.byte	25                              // DW_FORM_flag_present
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	5                               // Abbreviation Code
+	.byte	36                              // DW_TAG_base_type
+	.byte	0                               // DW_CHILDREN_no
+	.byte	3                               // DW_AT_name
+	.byte	37                              // DW_FORM_strx1
+	.byte	62                              // DW_AT_encoding
+	.byte	11                              // DW_FORM_data1
+	.byte	11                              // DW_AT_byte_size
+	.byte	11                              // DW_FORM_data1
+	.byte	0                               // EOM(1)
+	.byte	0                               // EOM(2)
+	.byte	0                               // EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.word	.Ldebug_info_end0-.Ldebug_info_start0 // Length of Unit
+.Ldebug_info_start0:
+	.hword	5                               // DWARF version number
+	.byte	1                               // DWARF Unit Type
+	.byte	8                               // Address Size (in bytes)
+	.word	.debug_abbrev                   // Offset Into Abbrev. Section
+	.byte	1                               // Abbrev [1] 0xc:0x46 DW_TAG_compile_unit
+	.byte	0                               // DW_AT_producer
+	.hword	29                              // DW_AT_language
+	.byte	1                               // DW_AT_name
+	.word	.Lstr_offsets_base0             // DW_AT_str_offsets_base
+	.word	.Lline_table_start0             // DW_AT_stmt_list
+	.byte	2                               // DW_AT_comp_dir
+	.byte	0                               // DW_AT_low_pc
+	.word	.Lfunc_end1-.Lfunc_begin0       // DW_AT_high_pc
+	.word	.Laddr_table_base0              // DW_AT_addr_base
+	.byte	2                               // Abbrev [2] 0x23:0x1b DW_TAG_subprogram
+	.byte	0                               // DW_AT_low_pc
+	.word	.Lfunc_end0-.Lfunc_begin0       // DW_AT_high_pc
+	.byte	1                               // DW_AT_frame_base
+	.byte	111
+	.byte	3                               // DW_AT_name
+	.byte	0                               // DW_AT_decl_file
+	.byte	1                               // DW_AT_decl_line
+                                        // DW_AT_prototyped
+	.word	77                              // DW_AT_type
+                                        // DW_AT_external
+	.byte	3                               // Abbrev [3] 0x32:0xb DW_TAG_formal_parameter
+	.byte	2                               // DW_AT_location
+	.byte	145
+	.byte	12
+	.byte	6                               // DW_AT_name
+	.byte	0                               // DW_AT_decl_file
+	.byte	1                               // DW_AT_decl_line
+	.word	77                              // DW_AT_type
+	.byte	0                               // End Of Children Mark
+	.byte	4                               // Abbrev [4] 0x3e:0xf DW_TAG_subprogram
+	.byte	1                               // DW_AT_low_pc
+	.word	.Lfunc_end1-.Lfunc_begin1       // DW_AT_high_pc
+	.byte	1                               // DW_AT_frame_base
+	.byte	109
+	.byte	5                               // DW_AT_name
+	.byte	0                               // DW_AT_decl_file
+	.byte	2                               // DW_AT_decl_line
+                                        // DW_AT_prototyped
+	.word	77                              // DW_AT_type
+                                        // DW_AT_external
+	.byte	5                               // Abbrev [5] 0x4d:0x4 DW_TAG_base_type
+	.byte	4                               // DW_AT_name
+	.byte	5                               // DW_AT_encoding
+	.byte	4                               // DW_AT_byte_size
+	.byte	0                               // End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.word	32                              // Length of String Offsets Set
+	.hword	5
+	.hword	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang"                         // string offset=0 ; clang
+.Linfo_string1:
+	.asciz	"main.c"                        // string offset=6 ; main.c
+.Linfo_string2:
+	.asciz	"."                             // string offset=13 ; .
+.Linfo_string3:
+	.asciz	"square"                        // string offset=15 ; square
+.Linfo_string4:
+	.asciz	"int"                           // string offset=22 ; int
+.Linfo_string5:
+	.asciz	"main"                          // string offset=26 ; main
+.Linfo_string6:
+	.asciz	"x"                             // string offset=31 ; x
+	.section	.debug_str_offsets,"", at progbits
+	.word	.Linfo_string0
+	.word	.Linfo_string1
+	.word	.Linfo_string2
+	.word	.Linfo_string3
+	.word	.Linfo_string4
+	.word	.Linfo_string5
+	.word	.Linfo_string6
+	.section	.debug_addr,"", at progbits
+	.word	.Ldebug_addr_end0-.Ldebug_addr_start0 // Length of contribution
+.Ldebug_addr_start0:
+	.hword	5                               // DWARF version number
+	.byte	8                               // Address size
+	.byte	0                               // Segment selector size
+.Laddr_table_base0:
+	.xword	.Lfunc_begin0
+	.xword	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.addrsig_sym square
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/bolt/test/CMakeLists.txt b/bolt/test/CMakeLists.txt
index 6e18b028bddfc..fb3332065e3b2 100644
--- a/bolt/test/CMakeLists.txt
+++ b/bolt/test/CMakeLists.txt
@@ -1,5 +1,7 @@
 llvm_canonicalize_cmake_booleans(
   BOLT_ENABLE_RUNTIME
+  LLVM_ENABLE_ZLIB
+  LLVM_ENABLE_ZSTD
   )
 
 configure_lit_site_cfg(
diff --git a/bolt/test/lit.site.cfg.py.in b/bolt/test/lit.site.cfg.py.in
index 457908fc7c446..825e238591a93 100644
--- a/bolt/test/lit.site.cfg.py.in
+++ b/bolt/test/lit.site.cfg.py.in
@@ -13,6 +13,8 @@ config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
 config.host_triple = "@LLVM_HOST_TRIPLE@"
 config.target_triple = "@LLVM_TARGET_TRIPLE@"
 config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
+config.have_zlib = @LLVM_ENABLE_ZLIB@
+config.have_zstd = @LLVM_ENABLE_ZSTD@
 config.host_arch = "@HOST_ARCH@"
 config.python_executable = "@Python3_EXECUTABLE@"
 config.bolt_clang = "@BOLT_CLANG_EXE@"



More information about the llvm-commits mailing list