[Lldb-commits] [lldb] 0e285a1 - [lldb] Support compressed CTF

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Thu Jul 13 15:10:31 PDT 2023


Author: Jonas Devlieghere
Date: 2023-07-13T15:10:25-07:00
New Revision: 0e285a13eb7f25d7609d6795fb2f3439c8b1c270

URL: https://github.com/llvm/llvm-project/commit/0e285a13eb7f25d7609d6795fb2f3439c8b1c270
DIFF: https://github.com/llvm/llvm-project/commit/0e285a13eb7f25d7609d6795fb2f3439c8b1c270.diff

LOG: [lldb] Support compressed CTF

Add support for compressed CTF data. The flags in the header can
indicate whether the CTF body is compressed with zlib deflate. This
patch supports inflating the data before parsing.

Differential revision: https://reviews.llvm.org/D155221

Added: 
    

Modified: 
    lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
    lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
    lldb/test/API/macosx/ctf/Makefile
    lldb/test/API/macosx/ctf/TestCTF.py

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
index d0680dc458888d..783584f5fec71d 100644
--- a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
+++ b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
@@ -11,6 +11,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/StreamBuffer.h"
+#include "lldb/Host/Config.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -35,6 +36,10 @@
 #include <memory>
 #include <optional>
 
+#if LLVM_ENABLE_ZLIB
+#include <zlib.h>
+#endif
+
 using namespace llvm;
 using namespace lldb;
 using namespace lldb_private;
@@ -129,24 +134,79 @@ bool SymbolFileCTF::ParseHeader() {
   LLDB_LOG(log, "Parsed valid CTF preamble: version {0}, flags {1:x}",
            ctf_header.preamble.version, ctf_header.preamble.flags);
 
-  const lldb::offset_t header_offset = offset;
+  m_body_offset = offset;
+
+  if (ctf_header.preamble.flags & eFlagCompress) {
+    // The body has been compressed with zlib deflate. Header offsets point into
+    // the decompressed data.
+#if LLVM_ENABLE_ZLIB
+    const std::size_t decompressed_size = ctf_header.stroff + ctf_header.strlen;
+    DataBufferSP decompressed_data =
+        std::make_shared<DataBufferHeap>(decompressed_size, 0x0);
+
+    z_stream zstr;
+    memset(&zstr, 0, sizeof(zstr));
+    zstr.next_in = (Bytef *)const_cast<uint8_t *>(m_data.GetDataStart() +
+                                                  sizeof(ctf_header_t));
+    zstr.avail_in = m_data.BytesLeft(offset);
+    zstr.next_out =
+        (Bytef *)const_cast<uint8_t *>(decompressed_data->GetBytes());
+    zstr.avail_out = decompressed_size;
+
+    int rc = inflateInit(&zstr);
+    if (rc != Z_OK) {
+      LLDB_LOG(log, "CTF parsing failed: inflate initialization error: {0}",
+               zError(rc));
+      return false;
+    }
+
+    rc = inflate(&zstr, Z_FINISH);
+    if (rc != Z_STREAM_END) {
+      LLDB_LOG(log, "CTF parsing failed: inflate error: {0}", zError(rc));
+      return false;
+    }
+
+    rc = inflateEnd(&zstr);
+    if (rc != Z_OK) {
+      LLDB_LOG(log, "CTF parsing failed: inflate end error: {0}", zError(rc));
+      return false;
+    }
+
+    if (zstr.total_out != decompressed_size) {
+      LLDB_LOG(log,
+               "CTF parsing failed: decompressed size ({0}) doesn't match "
+               "expected size ([1})",
+               zstr.total_out, decompressed_size);
+      return false;
+    }
+
+    m_data = DataExtractor(decompressed_data, m_data.GetByteOrder(),
+                           m_data.GetAddressByteSize());
+    m_body_offset = 0;
+#else
+    LLDB_LOG(
+        log,
+        "CTF parsing failed: data is compressed but no zlib inflate support");
+    return false;
+#endif
+  }
 
   // Validate the header.
-  if (!m_data.ValidOffset(header_offset + ctf_header.lbloff)) {
+  if (!m_data.ValidOffset(m_body_offset + ctf_header.lbloff)) {
     LLDB_LOG(log,
              "CTF parsing failed: invalid label section offset in header: {0}",
              ctf_header.lbloff);
     return false;
   }
 
-  if (!m_data.ValidOffset(header_offset + ctf_header.objtoff)) {
+  if (!m_data.ValidOffset(m_body_offset + ctf_header.objtoff)) {
     LLDB_LOG(log,
              "CTF parsing failed: invalid object section offset in header: {0}",
              ctf_header.objtoff);
     return false;
   }
 
-  if (!m_data.ValidOffset(header_offset + ctf_header.funcoff)) {
+  if (!m_data.ValidOffset(m_body_offset + ctf_header.funcoff)) {
     LLDB_LOG(
         log,
         "CTF parsing failed: invalid function section offset in header: {0}",
@@ -154,14 +214,14 @@ bool SymbolFileCTF::ParseHeader() {
     return false;
   }
 
-  if (!m_data.ValidOffset(header_offset + ctf_header.typeoff)) {
+  if (!m_data.ValidOffset(m_body_offset + ctf_header.typeoff)) {
     LLDB_LOG(log,
              "CTF parsing failed: invalid type section offset in header: {0}",
              ctf_header.typeoff);
     return false;
   }
 
-  if (!m_data.ValidOffset(header_offset + ctf_header.stroff)) {
+  if (!m_data.ValidOffset(m_body_offset + ctf_header.stroff)) {
     LLDB_LOG(log,
              "CTF parsing failed: invalid string section offset in header: {0}",
              ctf_header.stroff);
@@ -169,7 +229,7 @@ bool SymbolFileCTF::ParseHeader() {
   }
 
   const lldb::offset_t str_end_offset =
-      header_offset + ctf_header.stroff + ctf_header.strlen;
+      m_body_offset + ctf_header.stroff + ctf_header.strlen;
   if (!m_data.ValidOffset(str_end_offset - 1)) {
     LLDB_LOG(log,
              "CTF parsing failed: invalid string section length in header: {0}",
@@ -177,7 +237,7 @@ bool SymbolFileCTF::ParseHeader() {
     return false;
   }
 
-  if (header_offset + ctf_header.stroff + ctf_header.parlabel >
+  if (m_body_offset + ctf_header.stroff + ctf_header.parlabel >
       str_end_offset) {
     LLDB_LOG(log,
              "CTF parsing failed: invalid parent label offset: {0} exceeds end "
@@ -186,7 +246,7 @@ bool SymbolFileCTF::ParseHeader() {
     return false;
   }
 
-  if (header_offset + ctf_header.stroff + ctf_header.parname > str_end_offset) {
+  if (m_body_offset + ctf_header.stroff + ctf_header.parname > str_end_offset) {
     LLDB_LOG(log,
              "CTF parsing failed: invalid parent name offset: {0} exceeds end "
              "of string section ({1})",
@@ -222,7 +282,7 @@ void SymbolFileCTF::InitializeObject() {
 }
 
 llvm::StringRef SymbolFileCTF::ReadString(lldb::offset_t str_offset) const {
-  lldb::offset_t offset = sizeof(ctf_header_t) + m_header->stroff + str_offset;
+  lldb::offset_t offset = m_body_offset + m_header->stroff + str_offset;
   if (!m_data.ValidOffset(offset))
     return "(invalid)";
   const char *str = m_data.GetCStr(&offset);
@@ -539,9 +599,8 @@ size_t SymbolFileCTF::ParseTypes(CompileUnit &cu) {
   Log *log = GetLog(LLDBLog::Symbols);
   LLDB_LOG(log, "Parsing CTF types");
 
-  lldb::offset_t type_offset = sizeof(ctf_header_t) + m_header->typeoff;
-  const lldb::offset_t type_offset_end =
-      sizeof(ctf_header_t) + m_header->stroff;
+  lldb::offset_t type_offset = m_body_offset + m_header->typeoff;
+  const lldb::offset_t type_offset_end = m_body_offset + m_header->stroff;
 
   lldb::user_id_t type_uid = 1;
   while (type_offset < type_offset_end) {
@@ -597,9 +656,8 @@ size_t SymbolFileCTF::ParseFunctions(CompileUnit &cu) {
   Log *log = GetLog(LLDBLog::Symbols);
   LLDB_LOG(log, "Parsing CTF functions");
 
-  lldb::offset_t function_offset = sizeof(ctf_header_t) + m_header->funcoff;
-  const lldb::offset_t function_offset_end =
-      sizeof(ctf_header_t) + m_header->typeoff;
+  lldb::offset_t function_offset = m_body_offset + m_header->funcoff;
+  const lldb::offset_t function_offset_end = m_body_offset + m_header->typeoff;
 
   uint32_t symbol_idx = 0;
   Declaration decl;
@@ -713,9 +771,8 @@ size_t SymbolFileCTF::ParseObjects(CompileUnit &comp_unit) {
   Log *log = GetLog(LLDBLog::Symbols);
   LLDB_LOG(log, "Parsing CTF objects");
 
-  lldb::offset_t object_offset = sizeof(ctf_header_t) + m_header->objtoff;
-  const lldb::offset_t object_offset_end =
-      sizeof(ctf_header_t) + m_header->funcoff;
+  lldb::offset_t object_offset = m_body_offset + m_header->objtoff;
+  const lldb::offset_t object_offset_end = m_body_offset + m_header->funcoff;
 
   uint32_t symbol_idx = 0;
   Declaration decl;

diff  --git a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
index 7bb2b8bc41d17b..bdd6dcdc3fda32 100644
--- a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
+++ b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
@@ -155,6 +155,13 @@ class SymbolFileCTF : public lldb_private::SymbolFileCommon {
   };
 
 private:
+  enum Flags : uint32_t {
+    eFlagCompress = (1u << 0),
+    eFlagNewFuncInfo = (1u << 1),
+    eFlagIdxSorted = (1u << 2),
+    eFlagDynStr = (1u << 3),
+  };
+
   enum IntEncoding : uint32_t {
     eSigned = 0x1,
     eChar = 0x2,
@@ -270,6 +277,13 @@ class SymbolFileCTF : public lldb_private::SymbolFileCommon {
                                       uint32_t fields, uint32_t struct_size);
 
   DataExtractor m_data;
+
+  /// The start offset of the CTF body into m_data. If the body is uncompressed,
+  /// m_data contains the header and the body and the body starts after the
+  /// header. If the body is compressed, m_data only contains the body and the
+  /// offset is zero.
+  lldb::offset_t m_body_offset = 0;
+
   TypeSystemClang *m_ast;
   lldb::CompUnitSP m_comp_unit_sp;
 

diff  --git a/lldb/test/API/macosx/ctf/Makefile b/lldb/test/API/macosx/ctf/Makefile
index 77d7306df27faf..efe1043cc584ab 100644
--- a/lldb/test/API/macosx/ctf/Makefile
+++ b/lldb/test/API/macosx/ctf/Makefile
@@ -1,21 +1,30 @@
 C_SOURCES := test.c
 MAKE_DSYM := YES
 
+ifeq "$(COMPRESS_CTF)" "YES"
+	COMPRESS := -c
+else
+	 COMPRESS :=
+endif
+
 all: a.out a.ctf
 
 include Makefile.rules
 
 a.ctf: a.out.dSYM
-				ctfconvert -l a -o a.ctf a.out.dSYM/Contents/Resources/DWARF/a.out
-				$(OBJCOPY) \
-          -R __DWARF,__debug_line \
-          -R __DWARF,__debug_aranges \
-          -R __DWARF,__debug_info \
-          -R __DWARF,__debug_abbrev \
-          -R __DWARF,__debug_str \
-          -R __DWARF,__apple_names \
-          -R __DWARF,__apple_namespac \
-          -R __DWARF,__apple_types \
-          -R __DWARF,__apple_objc \
-          a.ctf a.ctf
-				rm -rf a.out.dSYM
+	ctfconvert $(COMPRESS) \
+		-l a \
+		-o a.ctf \
+		a.out.dSYM/Contents/Resources/DWARF/a.out
+	$(OBJCOPY) \
+		-R __DWARF,__debug_line \
+		-R __DWARF,__debug_aranges \
+		-R __DWARF,__debug_info \
+		-R __DWARF,__debug_abbrev \
+		-R __DWARF,__debug_str \
+		-R __DWARF,__apple_names \
+		-R __DWARF,__apple_namespac \
+		-R __DWARF,__apple_types \
+		-R __DWARF,__apple_objc \
+		a.ctf a.ctf
+	rm -rf a.out.dSYM

diff  --git a/lldb/test/API/macosx/ctf/TestCTF.py b/lldb/test/API/macosx/ctf/TestCTF.py
index 0a751af44affa8..fc6d7cf5ee6775 100644
--- a/lldb/test/API/macosx/ctf/TestCTF.py
+++ b/lldb/test/API/macosx/ctf/TestCTF.py
@@ -18,12 +18,18 @@ def no_objcopy(self):
             return "llvm-objcopy not found in environment"
         return None
 
-    @skipTestIfFn(no_ctf_convert)
-    @skipTestIfFn(no_objcopy)
-    @skipUnlessDarwin
     def test(self):
         self.build()
+        self.do_test()
+
+    def test_compressed(self):
+        self.build(dictionary={"COMPRESS_CTF": "YES"})
+        self.do_test()
 
+    @skipTestIfFn(no_ctf_convert)
+    @skipTestIfFn(no_objcopy)
+    @skipUnlessDarwin
+    def do_test(self):
         lldbutil.run_to_name_breakpoint(self, "printf")
 
         symbol_file = self.getBuildArtifact("a.ctf")


        


More information about the lldb-commits mailing list