`DWARFASTParserClang::ParseSingleMember` turns DWARF DIEs that describe struct/class members into their respective Clang representation (e.g., clang::FieldDecl). It also updates a record of where the last field started/ended so that we can speculatively fill any holes between a field and a bitfield with unnamed bitfield padding. Right now we are completely ignoring 'artificial' members when parsing the DWARF of a struct/class. The only artificial member that seems to be emitted in practice for C/C++ seems to be the vtable pointer. By completely skipping both the Clang AST node creation and the updating of the last-field record, we essentially leave a hole in our layout with the size of our artificial member. If the next member is a bitfield we then speculatively fill the hole with an unnamed bitfield. During CodeGen Clang inserts an artificial vtable pointer into the layout again which now occupies the same offset as the unnamed bitfield. This later brings down Clang's `CGRecordLowering::insertPadding` when it checks that none of the fields of the generated record layout overlap. Note that this is not a Clang bug. We explicitly set the offset of our fields in LLDB and overwrite whatever Clang makes up. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D112697
173 lines
7.1 KiB
Python
173 lines
7.1 KiB
Python
"""Show bitfields and check that they display correctly."""
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
|
|
class CppBitfieldsTestCase(TestBase):
|
|
|
|
mydir = TestBase.compute_mydir(__file__)
|
|
|
|
@no_debug_info_test
|
|
def test_bitfields(self):
|
|
self.build()
|
|
lldbutil.run_to_source_breakpoint(self, '// break here',
|
|
lldb.SBFileSpec("main.cpp", False))
|
|
|
|
# Accessing LargeBitsA.
|
|
self.expect_expr("lba", result_children=[
|
|
ValueCheck(name="", type="int:32"),
|
|
ValueCheck(name="a", type="unsigned int:20", value="2")
|
|
])
|
|
self.expect_expr("lba.a", result_type="unsigned int", result_value="2")
|
|
|
|
|
|
# Accessing LargeBitsB.
|
|
self.expect_expr("lbb", result_children=[
|
|
ValueCheck(name="a", type="unsigned int:1", value="1"),
|
|
ValueCheck(name="", type="int:31"),
|
|
ValueCheck(name="b", type="unsigned int:20", value="3")
|
|
])
|
|
self.expect_expr("lbb.b", result_type="unsigned int", result_value="3")
|
|
|
|
|
|
# Accessing LargeBitsC.
|
|
self.expect_expr("lbc", result_children=[
|
|
ValueCheck(name="", type="int:22"),
|
|
ValueCheck(name="a", type="unsigned int:1", value="1"),
|
|
ValueCheck(name="b", type="unsigned int:1", value="0"),
|
|
ValueCheck(name="c", type="unsigned int:5", value="4"),
|
|
ValueCheck(name="d", type="unsigned int:1", value="1"),
|
|
ValueCheck(name="", type="int:2"),
|
|
ValueCheck(name="e", type="unsigned int:20", value="20"),
|
|
])
|
|
self.expect_expr("lbc.c", result_type="unsigned int", result_value="4")
|
|
|
|
|
|
# Accessing LargeBitsD.
|
|
self.expect_expr("lbd", result_children=[
|
|
ValueCheck(name="arr", type="char[3]", summary='"ab"'),
|
|
ValueCheck(name="", type="int:32"),
|
|
ValueCheck(name="a", type="unsigned int:20", value="5")
|
|
])
|
|
self.expect_expr("lbd.a", result_type="unsigned int", result_value="5")
|
|
|
|
|
|
# Test BitfieldsInStructInUnion.
|
|
# FIXME: This needs some more explanation for what it's actually testing.
|
|
nested_struct_children = [
|
|
ValueCheck(name="", type="int:22"),
|
|
ValueCheck(name="a", type="uint64_t:1", value="1"),
|
|
ValueCheck(name="b", type="uint64_t:1", value="0"),
|
|
ValueCheck(name="c", type="uint64_t:1", value="1"),
|
|
ValueCheck(name="d", type="uint64_t:1", value="0"),
|
|
ValueCheck(name="e", type="uint64_t:1", value="1"),
|
|
ValueCheck(name="f", type="uint64_t:1", value="0"),
|
|
ValueCheck(name="g", type="uint64_t:1", value="1"),
|
|
ValueCheck(name="h", type="uint64_t:1", value="0"),
|
|
ValueCheck(name="i", type="uint64_t:1", value="1"),
|
|
ValueCheck(name="j", type="uint64_t:1", value="0"),
|
|
ValueCheck(name="k", type="uint64_t:1", value="1")
|
|
]
|
|
self.expect_expr("bitfields_in_struct_in_union",
|
|
result_type="BitfieldsInStructInUnion",
|
|
result_children=[ValueCheck(name="", children=[
|
|
ValueCheck(name="f", children=nested_struct_children)
|
|
])]
|
|
)
|
|
self.expect_expr("bitfields_in_struct_in_union.f.a",
|
|
result_type="uint64_t", result_value="1")
|
|
|
|
|
|
# Unions with bitfields.
|
|
self.expect_expr("uwbf", result_type="UnionWithBitfields", result_children=[
|
|
ValueCheck(name="a", value="255"),
|
|
ValueCheck(name="b", value="65535"),
|
|
ValueCheck(name="c", value="4294967295"),
|
|
ValueCheck(name="x", value="4294967295")
|
|
])
|
|
self.expect_expr("uwubf", result_type="UnionWithUnnamedBitfield",
|
|
result_children=[
|
|
ValueCheck(name="a", value="16777215"),
|
|
ValueCheck(name="x", value="4294967295")
|
|
]
|
|
)
|
|
|
|
# Class with a base class and a bitfield.
|
|
self.expect_expr("derived", result_type="Derived", result_children=[
|
|
ValueCheck(name="Base", children=[
|
|
ValueCheck(name="b_a", value="2", type="uint32_t")
|
|
]),
|
|
ValueCheck(name="d_a", value="1", type="uint32_t:1")
|
|
])
|
|
|
|
|
|
# Struct with bool bitfields.
|
|
self.expect_expr("bb", result_type="", result_children=[
|
|
ValueCheck(name="a", value="true", type="bool:1"),
|
|
ValueCheck(name="b", value="false", type="bool:1"),
|
|
ValueCheck(name="c", value="true", type="bool:2"),
|
|
ValueCheck(name="d", value="true", type="bool:2")
|
|
])
|
|
|
|
bb = self.frame().FindVariable('bb')
|
|
self.assertSuccess(bb.GetError())
|
|
|
|
bb_a = bb.GetChildAtIndex(0)
|
|
self.assertSuccess(bb_a.GetError())
|
|
self.assertEqual(bb_a.GetValueAsUnsigned(), 1)
|
|
self.assertEqual(bb_a.GetValueAsSigned(), 1)
|
|
|
|
bb_b = bb.GetChildAtIndex(1)
|
|
self.assertSuccess(bb_b.GetError())
|
|
self.assertEqual(bb_b.GetValueAsUnsigned(), 0)
|
|
self.assertEqual(bb_b.GetValueAsSigned(), 0)
|
|
|
|
bb_c = bb.GetChildAtIndex(2)
|
|
self.assertSuccess(bb_c.GetError())
|
|
self.assertEqual(bb_c.GetValueAsUnsigned(), 1)
|
|
self.assertEqual(bb_c.GetValueAsSigned(), 1)
|
|
|
|
bb_d = bb.GetChildAtIndex(3)
|
|
self.assertSuccess(bb_d.GetError())
|
|
self.assertEqual(bb_d.GetValueAsUnsigned(), 1)
|
|
self.assertEqual(bb_d.GetValueAsSigned(), 1)
|
|
|
|
# Test a class with a base class that has a vtable ptr. The derived
|
|
# class has bitfields.
|
|
base_with_vtable_children = [
|
|
ValueCheck(name="a", type="unsigned int:4", value="5"),
|
|
ValueCheck(name="b", type="unsigned int:4", value="0"),
|
|
ValueCheck(name="c", type="unsigned int:4", value="5")
|
|
]
|
|
self.expect_expr("base_with_vtable", result_children=base_with_vtable_children)
|
|
self.expect_var_path("base_with_vtable", children=base_with_vtable_children)
|
|
|
|
@no_debug_info_test
|
|
def test_bitfield_behind_vtable_ptr(self):
|
|
self.build()
|
|
lldbutil.run_to_source_breakpoint(self, '// break here',
|
|
lldb.SBFileSpec("main.cpp", False))
|
|
|
|
# Test a class with a vtable ptr and bitfields.
|
|
with_vtable_children = [
|
|
ValueCheck(name="a", type="unsigned int:4", value="5"),
|
|
ValueCheck(name="b", type="unsigned int:4", value="0"),
|
|
ValueCheck(name="c", type="unsigned int:4", value="5")
|
|
]
|
|
self.expect_expr("with_vtable", result_children=with_vtable_children)
|
|
self.expect_var_path("with_vtable", children=with_vtable_children)
|
|
|
|
# Test a class with a vtable ptr and unnamed bitfield directly after.
|
|
with_vtable_and_unnamed_children = [
|
|
ValueCheck(name="", type="int:4", value="0"),
|
|
ValueCheck(name="b", type="unsigned int:4", value="0"),
|
|
ValueCheck(name="c", type="unsigned int:4", value="5")
|
|
]
|
|
self.expect_expr("with_vtable_and_unnamed",
|
|
result_children=with_vtable_and_unnamed_children)
|
|
self.expect_var_path("with_vtable_and_unnamed",
|
|
children=with_vtable_and_unnamed_children)
|