diff --git a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h --- a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h +++ b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h @@ -155,6 +155,13 @@ }; 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 @@ 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/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp --- 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 #include +#if LLVM_ENABLE_ZLIB +#include +#endif + using namespace llvm; using namespace lldb; using namespace lldb_private; @@ -129,24 +134,79 @@ 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(decompressed_size, 0x0); + + z_stream zstr; + memset(&zstr, 0, sizeof(zstr)); + zstr.next_in = (Bytef *)const_cast(m_data.GetDataStart() + + sizeof(ctf_header_t)); + zstr.avail_in = m_data.BytesLeft(offset); + zstr.next_out = + (Bytef *)const_cast(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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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/test/API/macosx/ctf/Makefile b/lldb/test/API/macosx/ctf/Makefile --- 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 --- a/lldb/test/API/macosx/ctf/TestCTF.py +++ b/lldb/test/API/macosx/ctf/TestCTF.py @@ -18,12 +18,18 @@ 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")