Author: Michael Buch Date: 2025-10-31T13:27:09Z New Revision: deb54ba0cbab1e9c8d2ab0ea8a6e77dbb22b82d9
URL: https://github.com/llvm/llvm-project/commit/deb54ba0cbab1e9c8d2ab0ea8a6e77dbb22b82d9 DIFF: https://github.com/llvm/llvm-project/commit/deb54ba0cbab1e9c8d2ab0ea8a6e77dbb22b82d9.diff LOG: [lldb][TypeSystem] Better support for _BitInt types (#165689) Depends on: * https://github.com/llvm/llvm-project/pull/165686 This patch ensures we make use of the `DW_AT_bit_size` on `DW_TAG_base_type`s (which since https://github.com/llvm/llvm-project/pull/164372 can exist on `_BitInt`s) and adjusts `TypeSystemClang` to recognize `_BitInt`. For DWARF from older versions of Clang that didn't emit a `DW_AT_bit_size`, we would create `_BitInt`s using the byte-size. Not sure we can do much better than that. But the situation beforehand wasn't much better. Before: ``` (lldb) v (char) a = '\x01' (unsigned char) b = '\x01' (long) c = 2 (unsigned long) d = 2 ``` After: ``` (lldb) v (_BitInt(2)) a = 1 (unsigned _BitInt(2)) b = 1 (_BitInt(52)) c = 2 (unsigned _BitInt(52)) d = 2 ``` Fixes https://github.com/llvm/llvm-project/issues/110273 Added: Modified: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp lldb/unittests/Symbol/TestTypeSystemClang.cpp lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 47fa27b0a81a7..63b2dc4ab82b0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -814,13 +814,18 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, // there... [[fallthrough]]; - case DW_TAG_base_type: + case DW_TAG_base_type: { resolve_state = Type::ResolveState::Full; + // If a builtin type's size isn't a multiple of a byte, DWARF producers may + // add a precise bit-size to the type. Use the most precise bit-size + // possible. + const uint64_t bit_size = attrs.data_bit_size + ? *attrs.data_bit_size + : attrs.byte_size.value_or(0) * 8; clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( - attrs.name.GetStringRef(), attrs.encoding, - attrs.byte_size.value_or(0) * 8); + attrs.name.GetStringRef(), attrs.encoding, bit_size); break; - + } case DW_TAG_pointer_type: encoding_data_type = Type::eEncodingIsPointerUID; break; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 67186542fb705..51cb883748514 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1000,6 +1000,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize( case DW_ATE_signed: if (!type_name.empty()) { + if (type_name.starts_with("_BitInt")) + return GetType(ast.getBitIntType(/*Unsigned=*/false, bit_size)); if (type_name == "wchar_t" && QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) && (getTargetInfo() && @@ -1056,6 +1058,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize( case DW_ATE_unsigned: if (!type_name.empty()) { + if (type_name.starts_with("unsigned _BitInt")) + return GetType(ast.getBitIntType(/*Unsigned=*/true, bit_size)); if (type_name == "wchar_t") { if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) { if (!(getTargetInfo() && @@ -3889,6 +3893,13 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, ->getModifiedType() .getAsOpaquePtr(), pointee_or_element_clang_type); + case clang::Type::BitInt: { + uint32_t type_flags = eTypeIsScalar | eTypeIsInteger | eTypeHasValue; + if (qual_type->isSignedIntegerType()) + type_flags |= eTypeIsSigned; + + return type_flags; + } case clang::Type::Builtin: { const clang::BuiltinType *builtin_type = llvm::cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal()); diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index 4de595fd62825..155fc743934c2 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -52,6 +52,12 @@ class TestTypeSystemClang : public testing::Test { return ClangUtil::GetQualType( m_ast->GetBuiltinTypeByName(ConstString(name))); } + + CompilerType GetBuiltinTypeForDWARFEncodingAndBitSize( + llvm::StringRef type_name, uint32_t encoding, uint32_t bit_size) const { + return m_ast->GetBuiltinTypeForDWARFEncodingAndBitSize(type_name, encoding, + bit_size); + } }; TEST_F(TestTypeSystemClang, TestGetBasicTypeFromEnum) { @@ -238,6 +244,91 @@ TEST_F(TestTypeSystemClang, TestBuiltinTypeForEncodingAndBitSize) { VerifyEncodingAndBitSize(*m_ast, eEncodingIEEE754, 64); } +TEST_F(TestTypeSystemClang, TestGetBuiltinTypeForDWARFEncodingAndBitSize) { + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitIn", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "BitInt", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(2)", llvm::dwarf::DW_ATE_signed_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(2)", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(2)", llvm::dwarf::DW_ATE_signed, 2) + .GetTypeName(), + "_BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed, 2) + .GetTypeName(), + "_BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(129)", llvm::dwarf::DW_ATE_signed, 129) + .GetTypeName(), + "_BitInt(129)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed, 129) + .GetTypeName(), + "_BitInt(129)"); + + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitIn", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_unsigned_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_unsigned, 2) + .GetTypeName(), + "unsigned _BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .GetTypeName(), + "unsigned _BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(129)", llvm::dwarf::DW_ATE_unsigned, 129) + .GetTypeName(), + "unsigned _BitInt(129)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 129) + .GetTypeName(), + "unsigned _BitInt(129)"); +} + +TEST_F(TestTypeSystemClang, TestBitIntTypeInfo) { + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed, 2) + .GetTypeInfo(), + eTypeIsSigned | eTypeIsScalar | eTypeHasValue | eTypeIsInteger); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .GetTypeInfo(), + eTypeIsScalar | eTypeHasValue | eTypeIsInteger); +} + TEST_F(TestTypeSystemClang, TestBuiltinTypeForEmptyTriple) { // Test that we can access type-info of builtin Clang AST // types without crashing even when the target triple is diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp index 064ed6d1d3e58..cef3a25a4a960 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp @@ -1741,3 +1741,215 @@ TEST_F(DWARFASTParserClangTests, TestTypeBitSize) { EXPECT_EQ(llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), 1U); } + +TEST_F(DWARFASTParserClangTests, TestBitIntParsing) { + // Tests that we correctly parse the DW_AT_base_type for a _BitInt. + // Older versions of Clang only emit the `_BitInt` string into the + // DW_AT_name (not including the bitsize). Make sure we understand + // those too. + + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_AARCH64 +DWARF: + debug_str: + - _BitInt(2) + - _BitInt + - unsigned _BitInt(2) + - unsigned _BitInt + debug_abbrev: + - ID: 0 + Table: + - Code: 0x1 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x2 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + - Attribute: DW_AT_bit_size + Form: DW_FORM_data1 + - Code: 0x3 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + + debug_info: + - Version: 5 + UnitType: DW_UT_compile + AddrSize: 8 + Entries: + +# DW_TAG_compile_unit +# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) + + - AbbrCode: 0x1 + Values: + - Value: 0x04 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('_BitInt(2)') + + - AbbrCode: 0x2 + Values: + - Value: 0x0 + - Value: 0x05 + - Value: 0x01 + - Value: 0x02 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('_BitInt') + + - AbbrCode: 0x2 + Values: + - Value: 0x0b + - Value: 0x05 + - Value: 0x08 + - Value: 0x34 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('unsigned _BitInt(2)') + + - AbbrCode: 0x2 + Values: + - Value: 0x13 + - Value: 0x07 + - Value: 0x01 + - Value: 0x02 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('unsigned _BitInt') + + - AbbrCode: 0x2 + Values: + - Value: 0x27 + - Value: 0x07 + - Value: 0x08 + - Value: 0x34 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('_BitInt') + + - AbbrCode: 0x3 + Values: + - Value: 0x0b + - Value: 0x05 + - Value: 0x08 +... + +)"; + + YAMLModuleTester t(yamldata); + + DWARFUnit *unit = t.GetDwarfUnit(); + ASSERT_NE(unit, nullptr); + const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); + ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); + ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus); + DWARFDIE cu_die(unit, cu_entry); + + auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast"); + auto &ast_ctx = *holder->GetAST(); + DWARFASTParserClangStub ast_parser(ast_ctx); + + auto type_die = cu_die.GetFirstChild(); + ASSERT_TRUE(type_die.IsValid()); + + { + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 1U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingSint); + EXPECT_EQ(type_sp->GetName(), "_BitInt(2)"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(2)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 8U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingSint); + EXPECT_EQ(type_sp->GetName(), "_BitInt"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(52)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 1U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingUint); + EXPECT_EQ(type_sp->GetName(), "unsigned _BitInt(2)"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), + "unsigned _BitInt(2)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 8U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingUint); + EXPECT_EQ(type_sp->GetName(), "unsigned _BitInt"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), + "unsigned _BitInt(52)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 8U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingSint); + EXPECT_EQ(type_sp->GetName(), "_BitInt"); + + // Older versions of Clang didn't emit a DW_AT_bit_size for _BitInt. In + // those cases we would format the CompilerType name using the byte-size. + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(64)"); + } +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
