Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 40 additions & 19 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2839,10 +2839,9 @@ void DWARFASTParserClang::ParseSingleMember(
die.GetCU()->Supports_unnamed_objc_bitfields();

if (detect_unnamed_bitfields) {
llvm::Optional<FieldInfo> unnamed_field_info;
uint64_t last_field_end = 0;

last_field_end = last_field_info.bit_offset + last_field_info.bit_size;
std::optional<FieldInfo> unnamed_field_info;
uint64_t last_field_end =
last_field_info.bit_offset + last_field_info.bit_size;

if (!last_field_info.IsBitfield()) {
// The last field was not a bit-field...
Expand All @@ -2853,20 +2852,8 @@ void DWARFASTParserClang::ParseSingleMember(
last_field_end += word_width - (last_field_end % word_width);
}

// If we have a gap between the last_field_end and the current
// field we have an unnamed bit-field.
// If we have a base class, we assume there is no unnamed
// bit-field if this is the first field since the gap can be
// attributed to the members from the base class. This assumption
// is not correct if the first field of the derived class is
// indeed an unnamed bit-field. We currently do not have the
// machinary to track the offset of the last field of classes we
// have seen before, so we are not handling this case.
if (this_field_info.bit_offset != last_field_end &&
this_field_info.bit_offset > last_field_end &&
!(last_field_info.bit_offset == 0 &&
last_field_info.bit_size == 0 &&
layout_info.base_offsets.size() != 0)) {
if (ShouldCreateUnnamedBitfield(last_field_info, last_field_end,
this_field_info, layout_info)) {
unnamed_field_info = FieldInfo{};
unnamed_field_info->bit_size =
this_field_info.bit_offset - last_field_end;
Expand Down Expand Up @@ -2907,8 +2894,10 @@ void DWARFASTParserClang::ParseSingleMember(
// artificial member with (unnamed bitfield) padding.
// FIXME: This check should verify that this is indeed an artificial member
// we are supposed to ignore.
if (attrs.is_artificial)
if (attrs.is_artificial) {
last_field_info.SetIsArtificial(true);
return;
}

if (!member_clang_type.IsCompleteType())
member_clang_type.GetCompleteType();
Expand Down Expand Up @@ -3660,3 +3649,35 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(

return !failures.empty();
}

bool DWARFASTParserClang::ShouldCreateUnnamedBitfield(
FieldInfo const &last_field_info, uint64_t last_field_end,
FieldInfo const &this_field_info,
lldb_private::ClangASTImporter::LayoutInfo const &layout_info) const {
// If we have a gap between the last_field_end and the current
// field we have an unnamed bit-field.
if (this_field_info.bit_offset <= last_field_end)
return false;

// If we have a base class, we assume there is no unnamed
// bit-field if either of the following is true:
// (a) this is the first field since the gap can be
// attributed to the members from the base class.
// FIXME: This assumption is not correct if the first field of
// the derived class is indeed an unnamed bit-field. We currently
// do not have the machinary to track the offset of the last field
// of classes we have seen before, so we are not handling this case.
// (b) Or, the first member of the derived class was a vtable pointer.
// In this case we don't want to create an unnamed bitfield either
// since those will be inserted by clang later.
const bool have_base = layout_info.base_offsets.size() != 0;
const bool this_is_first_field =
last_field_info.bit_offset == 0 && last_field_info.bit_size == 0;
const bool first_field_is_vptr =
last_field_info.bit_offset == 0 && last_field_info.IsArtificial();

if (have_base && (this_is_first_field || first_field_is_vptr))
return false;

return true;
}
20 changes: 20 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,19 +206,39 @@ class DWARFASTParserClang : public DWARFASTParser {
uint64_t bit_size = 0;
uint64_t bit_offset = 0;
bool is_bitfield = false;
bool is_artificial = false;

FieldInfo() = default;

void SetIsBitfield(bool flag) { is_bitfield = flag; }
bool IsBitfield() { return is_bitfield; }

void SetIsArtificial(bool flag) { is_artificial = flag; }
bool IsArtificial() const { return is_artificial; }

bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const {
// Any subsequent bitfields must not overlap and must be at a higher
// bit offset than any previous bitfield + size.
return (bit_size + bit_offset) <= next_bit_offset;
}
};

/// Returns 'true' if we should create an unnamed bitfield
/// and add it to the parser's current AST.
///
/// \param[in] last_field_info FieldInfo of the previous DW_TAG_member
/// we parsed.
/// \param[in] last_field_end Offset (in bits) where the last parsed field
/// ended.
/// \param[in] this_field_info FieldInfo of the current DW_TAG_member
/// being parsed.
/// \param[in] layout_info Layout information of all decls parsed by the
/// current parser.
bool ShouldCreateUnnamedBitfield(
FieldInfo const &last_field_info, uint64_t last_field_end,
FieldInfo const &this_field_info,
lldb_private::ClangASTImporter::LayoutInfo const &layout_info) const;

/// Parses a DW_TAG_APPLE_property DIE and appends the parsed data to the
/// list of delayed Objective-C properties.
///
Expand Down
11 changes: 11 additions & 0 deletions lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,14 @@ def test_bitfield_behind_vtable_ptr(self):
result_children=with_vtable_and_unnamed_children)
self.expect_var_path("with_vtable_and_unnamed",
children=with_vtable_and_unnamed_children)

derived_with_vtable_children = [
ValueCheck(name="Base", children=[
ValueCheck(name="b_a", value="2", type="uint32_t")
]),
ValueCheck(name="a", value="1", type="unsigned int:1")
]
self.expect_expr("derived_with_vtable",
result_children=derived_with_vtable_children)
self.expect_var_path("derived_with_vtable",
children=derived_with_vtable_children)
9 changes: 9 additions & 0 deletions lldb/test/API/lang/cpp/bitfields/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ struct HasBaseWithVTable : BaseWithVTable {
};
HasBaseWithVTable base_with_vtable;

struct DerivedWithVTable : public Base {
virtual ~DerivedWithVTable() {}
unsigned a : 1;
};
DerivedWithVTable derived_with_vtable;

int main(int argc, char const *argv[]) {
lba.a = 2;

Expand Down Expand Up @@ -153,5 +159,8 @@ int main(int argc, char const *argv[]) {
base_with_vtable.b = 0;
base_with_vtable.c = 5;

derived_with_vtable.b_a = 2;
derived_with_vtable.a = 1;

return 0; // break here
}