Skip to content

Commit 1956cf1

Browse files
committed
[lldb/DWARF] Don't treat class declarations with children as definitions
Summary: This effectively reverts r188124, which added code to handle (DW_AT_)declarations of structures with some kinds of children as definitions. The commit message claims this is a workaround for some kind of debug info produced by gcc. However, it does not go into specifics, so it's hard to reproduce or verify that this is indeed still a problem. Having this code is definitely a problem though, because it mistakenly declares incomplete dwarf declarations to be complete. Both clang (with -flimit-debug-info) and gcc (by default) generate DW_AT_declarations of structs with children. This happens when full debug info for a class is not emitted in a given compile unit (e.g. because of vtable homing), but the class has inline methods which are used in the given compile unit. In that case, the compilers emit a DW_AT_declaration of a class, but add a DW_TAG_subprogram child to it to describe the inlined instance of the method. Even though the class tag has some children, it definitely does not contain enough information to construct a full class definition (most notably, it lacks any members). Keeping the class as incomplete allows us to search for a real definition in other modules, helping the -flimit-debug-info flow. And in case the definition is not found we can display a error message saying that, instead of just showing an empty struct. Reviewers: clayborg, aprantl, JDevlieghere, shafik Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D83302
1 parent 6701c0b commit 1956cf1

File tree

7 files changed

+208
-31
lines changed

7 files changed

+208
-31
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

-27
Original file line numberDiff line numberDiff line change
@@ -1641,33 +1641,6 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
16411641
dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename,
16421642
*unique_ast_entry_up);
16431643

1644-
if (attrs.is_forward_declaration && die.HasChildren()) {
1645-
// Check to see if the DIE actually has a definition, some version of
1646-
// GCC will
1647-
// emit DIEs with DW_AT_declaration set to true, but yet still have
1648-
// subprogram, members, or inheritance, so we can't trust it
1649-
DWARFDIE child_die = die.GetFirstChild();
1650-
while (child_die) {
1651-
switch (child_die.Tag()) {
1652-
case DW_TAG_inheritance:
1653-
case DW_TAG_subprogram:
1654-
case DW_TAG_member:
1655-
case DW_TAG_APPLE_property:
1656-
case DW_TAG_class_type:
1657-
case DW_TAG_structure_type:
1658-
case DW_TAG_enumeration_type:
1659-
case DW_TAG_typedef:
1660-
case DW_TAG_union_type:
1661-
child_die.Clear();
1662-
attrs.is_forward_declaration = false;
1663-
break;
1664-
default:
1665-
child_die = child_die.GetSibling();
1666-
break;
1667-
}
1668-
}
1669-
}
1670-
16711644
if (!attrs.is_forward_declaration) {
16721645
// Always start the definition for a class type so that if the class
16731646
// has child classes or types that require the class to be created

lldb/test/API/functionalities/limit-debug-info/TestLimitDebugInfo.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def test_one_and_two_debug(self):
3838

3939
self._check_debug_info_is_limited(target)
4040

41-
self.registerSharedLibrariesWithTarget(target, ["one", "two"])
41+
lldbutil.run_to_name_breakpoint(self, "main",
42+
extra_images=["one", "two"])
4243

4344
# But when other shared libraries are loaded, we should be able to see
4445
# all members.
@@ -58,6 +59,10 @@ def test_one_and_two_debug(self):
5859
self.expect_expr("array_of_two[2].one[2].member", result_value="174")
5960
self.expect_expr("array_of_two[2].member", result_value="274")
6061

62+
self.expect_expr("get_one().member", result_value="124")
63+
self.expect_expr("get_two().one().member", result_value="124")
64+
self.expect_expr("get_two().member", result_value="224")
65+
6166
@skipIf(bugnumber="pr46284", debug_info="gmodules")
6267
@skipIfWindows # Clang emits type info even with -flimit-debug-info
6368
def test_two_debug(self):
@@ -66,7 +71,8 @@ def test_two_debug(self):
6671

6772
self._check_debug_info_is_limited(target)
6873

69-
self.registerSharedLibrariesWithTarget(target, ["one", "two"])
74+
lldbutil.run_to_name_breakpoint(self, "main",
75+
extra_images=["one", "two"])
7076

7177
# This time, we should only see the members from the second library.
7278
self.expect_expr("inherits_from_one.member", result_value="47")
@@ -91,6 +97,12 @@ def test_two_debug(self):
9197
substrs=["no member named 'member' in 'array::One'"])
9298
self.expect_expr("array_of_two[2].member", result_value="274")
9399

100+
self.expect("expr get_one().member", error=True,
101+
substrs=["calling 'get_one' with incomplete return type 'result::One'"])
102+
self.expect("expr get_two().one().member", error=True,
103+
substrs=["calling 'one' with incomplete return type 'result::One'"])
104+
self.expect_expr("get_two().member", result_value="224")
105+
94106
@skipIf(bugnumber="pr46284", debug_info="gmodules")
95107
@skipIfWindows # Clang emits type info even with -flimit-debug-info
96108
def test_one_debug(self):
@@ -99,7 +111,8 @@ def test_one_debug(self):
99111

100112
self._check_debug_info_is_limited(target)
101113

102-
self.registerSharedLibrariesWithTarget(target, ["one", "two"])
114+
lldbutil.run_to_name_breakpoint(self, "main",
115+
extra_images=["one", "two"])
103116

104117
# In this case we should only see the members from the second library.
105118
# Note that we cannot see inherits_from_two.one because without debug
@@ -126,3 +139,9 @@ def test_one_debug(self):
126139
substrs=["no member named 'one' in 'array::Two'"])
127140
self.expect("expr array_of_two[2].member", error=True,
128141
substrs=["no member named 'member' in 'array::Two'"])
142+
143+
self.expect_expr("get_one().member", result_value="124")
144+
self.expect("expr get_two().one().member", error=True,
145+
substrs=["calling 'get_two' with incomplete return type 'result::Two'"])
146+
self.expect("expr get_two().member", error=True,
147+
substrs=["calling 'get_two' with incomplete return type 'result::Two'"])

lldb/test/API/functionalities/limit-debug-info/main.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ struct TwoAsMember {
2525
array::One array_of_one[3];
2626
array::Two array_of_two[3];
2727

28-
int main() { return 0; }
28+
result::One get_one() { return result::One(124); }
29+
result::Two get_two() { return result::Two(224); }
30+
31+
int main() { return get_one().member; }

lldb/test/API/functionalities/limit-debug-info/one.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
One::~One() = default;
44
member::One::~One() = default;
55
array::One::~One() = default;
6+
7+
result::One::One(int member) : member(member) {}
8+
result::One::~One() = default;

lldb/test/API/functionalities/limit-debug-info/onetwo.h

+15
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,18 @@ struct Two {
3939
virtual ~Two();
4040
};
4141
} // namespace array
42+
43+
namespace result {
44+
struct One {
45+
int member;
46+
One(int member);
47+
virtual ~One();
48+
};
49+
50+
struct Two {
51+
int member;
52+
Two(int member);
53+
One one() const;
54+
virtual ~Two();
55+
};
56+
} // namespace result

lldb/test/API/functionalities/limit-debug-info/two.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
Two::~Two() = default;
44
member::Two::~Two() = default;
55
array::Two::~Two() = default;
6+
7+
result::Two::Two(int member) : member(member) {}
8+
result::Two::~Two() = default;
9+
result::One result::Two::one() const { return One(member - 100); }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Test that a forward-declared (DW_AT_declaration) structure is treated as a
2+
# forward-declaration even if it has children. These types can be produced due
3+
# to vtable-based type homing, or other -flimit-debug-info optimizations.
4+
5+
# REQUIRES: x86
6+
7+
# RUN: llvm-mc --triple x86_64-pc-linux %s --filetype=obj > %t
8+
# RUN: %lldb %t -o "expr a" -o exit 2>&1 | FileCheck %s --check-prefix=EXPR
9+
# RUN: %lldb %t -o "target var a" -o exit 2>&1 | FileCheck %s --check-prefix=VAR
10+
11+
# EXPR: incomplete type 'A' where a complete type is required
12+
13+
# FIXME: This should also produce some kind of an error.
14+
# VAR: (A) a = {}
15+
16+
.text
17+
_ZN1AC2Ev:
18+
retq
19+
.LZN1AC2Ev_end:
20+
21+
.data
22+
a:
23+
.quad $_ZTV1A+16
24+
.quad $0xdeadbeef
25+
26+
.section .debug_abbrev,"",@progbits
27+
.byte 1 # Abbreviation Code
28+
.byte 17 # DW_TAG_compile_unit
29+
.byte 1 # DW_CHILDREN_yes
30+
.byte 37 # DW_AT_producer
31+
.byte 8 # DW_FORM_string
32+
.byte 17 # DW_AT_low_pc
33+
.byte 1 # DW_FORM_addr
34+
.byte 18 # DW_AT_high_pc
35+
.byte 6 # DW_FORM_data4
36+
.byte 0 # EOM(1)
37+
.byte 0 # EOM(2)
38+
.byte 2 # Abbreviation Code
39+
.byte 52 # DW_TAG_variable
40+
.byte 0 # DW_CHILDREN_no
41+
.byte 3 # DW_AT_name
42+
.byte 8 # DW_FORM_string
43+
.byte 73 # DW_AT_type
44+
.byte 19 # DW_FORM_ref4
45+
.byte 2 # DW_AT_location
46+
.byte 24 # DW_FORM_exprloc
47+
.byte 0 # EOM(1)
48+
.byte 0 # EOM(2)
49+
.byte 3 # Abbreviation Code
50+
.byte 19 # DW_TAG_structure_type
51+
.byte 1 # DW_CHILDREN_yes
52+
.byte 3 # DW_AT_name
53+
.byte 8 # DW_FORM_string
54+
.byte 60 # DW_AT_declaration
55+
.byte 25 # DW_FORM_flag_present
56+
.byte 0 # EOM(1)
57+
.byte 0 # EOM(2)
58+
.byte 4 # Abbreviation Code
59+
.byte 46 # DW_TAG_subprogram
60+
.byte 1 # DW_CHILDREN_yes
61+
.byte 3 # DW_AT_name
62+
.byte 8 # DW_FORM_string
63+
.byte 60 # DW_AT_declaration
64+
.byte 25 # DW_FORM_flag_present
65+
.byte 0 # EOM(1)
66+
.byte 0 # EOM(2)
67+
.byte 5 # Abbreviation Code
68+
.byte 5 # DW_TAG_formal_parameter
69+
.byte 0 # DW_CHILDREN_no
70+
.byte 73 # DW_AT_type
71+
.byte 19 # DW_FORM_ref4
72+
.byte 52 # DW_AT_artificial
73+
.byte 25 # DW_FORM_flag_present
74+
.byte 0 # EOM(1)
75+
.byte 0 # EOM(2)
76+
.byte 8 # Abbreviation Code
77+
.byte 15 # DW_TAG_pointer_type
78+
.byte 0 # DW_CHILDREN_no
79+
.byte 73 # DW_AT_type
80+
.byte 19 # DW_FORM_ref4
81+
.byte 0 # EOM(1)
82+
.byte 0 # EOM(2)
83+
.byte 10 # Abbreviation Code
84+
.byte 46 # DW_TAG_subprogram
85+
.byte 1 # DW_CHILDREN_yes
86+
.byte 17 # DW_AT_low_pc
87+
.byte 1 # DW_FORM_addr
88+
.byte 18 # DW_AT_high_pc
89+
.byte 6 # DW_FORM_data4
90+
.byte 64 # DW_AT_frame_base
91+
.byte 24 # DW_FORM_exprloc
92+
.byte 100 # DW_AT_object_pointer
93+
.byte 19 # DW_FORM_ref4
94+
.byte 71 # DW_AT_specification
95+
.byte 19 # DW_FORM_ref4
96+
.byte 0 # EOM(1)
97+
.byte 0 # EOM(2)
98+
.byte 11 # Abbreviation Code
99+
.byte 5 # DW_TAG_formal_parameter
100+
.byte 0 # DW_CHILDREN_no
101+
.byte 2 # DW_AT_location
102+
.byte 24 # DW_FORM_exprloc
103+
.byte 3 # DW_AT_name
104+
.byte 8 # DW_FORM_string
105+
.byte 73 # DW_AT_type
106+
.byte 19 # DW_FORM_ref4
107+
.byte 52 # DW_AT_artificial
108+
.byte 25 # DW_FORM_flag_present
109+
.byte 0 # EOM(1)
110+
.byte 0 # EOM(2)
111+
.byte 0 # EOM(3)
112+
.section .debug_info,"",@progbits
113+
.Lcu_begin0:
114+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
115+
.Ldebug_info_start0:
116+
.short 4 # DWARF version number
117+
.long .debug_abbrev # Offset Into Abbrev. Section
118+
.byte 8 # Address Size (in bytes)
119+
.byte 1 # Abbrev [1] DW_TAG_compile_unit
120+
.asciz "Hand-written DWARF" # DW_AT_producer
121+
.quad _ZN1AC2Ev # DW_AT_low_pc
122+
.long .LZN1AC2Ev_end-_ZN1AC2Ev # DW_AT_high_pc
123+
.byte 2 # Abbrev [2] DW_TAG_variable
124+
.asciz "a" # DW_AT_name
125+
.long .LA-.Lcu_begin0 # DW_AT_type
126+
.byte 9 # DW_AT_location
127+
.byte 3
128+
.quad a
129+
.LA:
130+
.byte 3 # Abbrev [3] DW_TAG_structure_type
131+
.asciz "A" # DW_AT_name
132+
# DW_AT_declaration
133+
.byte 4 # Abbrev [4] DW_TAG_subprogram
134+
.asciz "A" # DW_AT_name
135+
# DW_AT_declaration
136+
.byte 5 # Abbrev [5] DW_TAG_formal_parameter
137+
.long .LAptr-.Lcu_begin0 # DW_AT_type
138+
# DW_AT_artificial
139+
.byte 0 # End Of Children Mark
140+
.byte 0 # End Of Children Mark
141+
.LAptr:
142+
.byte 8 # Abbrev [8] DW_TAG_pointer_type
143+
.long .LA-.Lcu_begin0 # DW_AT_type
144+
.byte 10 # Abbrev [10] DW_TAG_subprogram
145+
.quad _ZN1AC2Ev # DW_AT_low_pc
146+
.long .LZN1AC2Ev_end-_ZN1AC2Ev # DW_AT_high_pc
147+
.byte 1 # DW_AT_frame_base
148+
.byte 86
149+
.long 147 # DW_AT_object_pointer
150+
.long 68 # DW_AT_specification
151+
.byte 11 # Abbrev [11] DW_TAG_formal_parameter
152+
.byte 2 # DW_AT_location
153+
.byte 145
154+
.byte 120
155+
.asciz "this" # DW_AT_name
156+
.long .LAptr-.Lcu_begin0 # DW_AT_type
157+
# DW_AT_artificial
158+
.byte 0 # End Of Children Mark
159+
.byte 0 # End Of Children Mark
160+
.Ldebug_info_end0:

0 commit comments

Comments
 (0)