[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
This commit is contained in:
Michael Buch
2025-10-31 13:27:09 +00:00
committed by GitHub
parent 7b29b49c3e
commit deb54ba0cb
4 changed files with 323 additions and 4 deletions

View File

@@ -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;

View File

@@ -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());

View File

@@ -52,6 +52,12 @@ protected:
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

View File

@@ -1741,3 +1741,215 @@ DWARF:
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)");
}
}