Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb][DWARFASTParserClang] Check DW_AT_declaration to determine static data members #68300

Merged
merged 2 commits into from
Oct 6, 2023
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
22 changes: 16 additions & 6 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2482,8 +2482,9 @@ struct MemberAttributes {
DWARFFormValue encoding_form;
/// Indicates the byte offset of the word from the base address of the
/// structure.
uint32_t member_byte_offset;
uint32_t member_byte_offset = UINT32_MAX;
bool is_artificial = false;
bool is_declaration = false;
};

/// Parsed form of all attributes that are relevant for parsing Objective-C
Expand Down Expand Up @@ -2656,8 +2657,6 @@ DiscriminantValue &VariantPart::discriminant() { return this->_discriminant; }
MemberAttributes::MemberAttributes(const DWARFDIE &die,
const DWARFDIE &parent_die,
ModuleSP module_sp) {
member_byte_offset = (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX;

DWARFAttributes attributes = die.GetAttributes();
for (size_t i = 0; i < attributes.Size(); ++i) {
const dw_attr_t attr = attributes.AttributeAtIndex(i);
Expand Down Expand Up @@ -2717,6 +2716,9 @@ MemberAttributes::MemberAttributes(const DWARFDIE &die,
case DW_AT_artificial:
is_artificial = form_value.Boolean();
break;
case DW_AT_declaration:
is_declaration = form_value.Boolean();
break;
default:
break;
}
Expand Down Expand Up @@ -2923,10 +2925,18 @@ void DWARFASTParserClang::ParseSingleMember(
if (class_is_objc_object_or_interface)
attrs.accessibility = eAccessNone;

// Handle static members, which is any member that doesn't have a bit or a
// byte member offset.
// Handle static members, which are typically members without
// locations. However, GCC *never* emits DW_AT_data_member_location
// for static data members of unions.
// Non-normative text pre-DWARFv5 recommends marking static
// data members with an DW_AT_external flag. Clang emits this consistently
// whereas GCC emits it only for static data members if not part of an
// anonymous namespace. The flag that is consistently emitted for static
// data members is DW_AT_declaration, so we check it instead.
// FIXME: Since DWARFv5, static data members are marked DW_AT_variable so we
// can consistently detect them on both GCC and Clang without below heuristic.
if (attrs.member_byte_offset == UINT32_MAX &&
attrs.data_bit_offset == UINT64_MAX) {
attrs.data_bit_offset == UINT64_MAX && attrs.is_declaration) {
Type *var_type = die.ResolveTypeUID(attrs.encoding_form.Reference());

if (var_type) {
Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/lang/cpp/union-static-data-members/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Tests that frame variable and expr work for
C++ unions and their static data members.
"""
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil

class CppUnionStaticMembersTestCase(TestBase):
def test(self):
"""Tests that frame variable and expr work
for union static data members"""
self.build()

(target, process, main_thread, _) = lldbutil.run_to_source_breakpoint(
self, "return 0", lldb.SBFileSpec("main.cpp")
)

self.expect("frame variable foo", substrs=["val = 42"])
self.expect("frame variable bar", substrs=["val = 137"])

self.expect_expr("foo", result_type="Foo", result_children=[ValueCheck(
name="val", value="42"
)])
self.expect_expr("bar", result_type="Bar", result_children=[ValueCheck(
name="val", value="137"
)])

self.expect_expr("Foo::sVal1", result_type="const int", result_value="-42")
self.expect_expr("Foo::sVal2", result_type="Foo", result_children=[ValueCheck(
name="val", value="42"
)])

@expectedFailureAll
def test_union_in_anon_namespace(self):
"""Tests that frame variable and expr work
for union static data members in anonymous
namespaces"""
self.expect_expr("Bar::sVal1", result_type="const int", result_value="-137")
self.expect_expr("Bar::sVal2", result_type="Bar", result_children=[ValueCheck(
name="val", value="137"
)])
25 changes: 25 additions & 0 deletions lldb/test/API/lang/cpp/union-static-data-members/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
union Foo {
int val = 42;
static const int sVal1 = -42;
static Foo sVal2;
};

Foo Foo::sVal2{};

namespace {
union Bar {
int val = 137;
static const int sVal1 = -137;
static Bar sVal2;
};

Bar Bar::sVal2{};
} // namespace

int main() {
Foo foo;
Bar bar;
auto sum = Bar::sVal1 + Foo::sVal1 + Foo::sVal2.val + Bar::sVal2.val;

return 0;
}