Skip to content

Commit dbb0934

Browse files
authored
Merge pull request #9952 from swiftlang/cherrypick-stable/20240723-ad32576cffc8-bb4007e56274-1808255a44e6
[🍒 stable/20240723] [DWARFVerifier] Allow overlapping ranges for ICF-merged functions (llvm#117952)
2 parents 482d091 + 024482d commit dbb0934

File tree

5 files changed

+175
-10
lines changed

5 files changed

+175
-10
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ class DWARFVerifier {
6868

6969
/// Inserts the address range. If the range overlaps with an existing
7070
/// range, the range that it overlaps with will be returned and the two
71-
/// address ranges will be unioned together in "Ranges".
71+
/// address ranges will be unioned together in "Ranges". If a duplicate
72+
/// entry is attempted to be added, the duplicate range will not actually be
73+
/// added and the returned iterator will point to end().
7274
///
7375
/// This is used for finding overlapping ranges in the DW_AT_ranges
7476
/// attribute of a DIE. It is also used as a set of address ranges that
@@ -77,7 +79,9 @@ class DWARFVerifier {
7779

7880
/// Inserts the address range info. If any of its ranges overlaps with a
7981
/// range in an existing range info, the range info is *not* added and an
80-
/// iterator to the overlapping range info.
82+
/// iterator to the overlapping range info. If a duplicate entry is
83+
/// attempted to be added, the duplicate range will not actually be added
84+
/// and the returned iterator will point to end().
8185
///
8286
/// This is used for finding overlapping children of the same DIE.
8387
die_range_info_iterator insert(const DieRangeInfo &RI);
@@ -86,7 +90,7 @@ class DWARFVerifier {
8690
bool contains(const DieRangeInfo &RHS) const;
8791

8892
/// Return true if any range in this object intersects with any range in
89-
/// RHS.
93+
/// RHS. Identical ranges are not considered to be intersecting.
9094
bool intersects(const DieRangeInfo &RHS) const;
9195
};
9296

llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
5252
auto End = Ranges.end();
5353
auto Pos = std::lower_bound(Begin, End, R);
5454

55+
// Check for exact duplicates which is an allowed special case
56+
if (Pos != End && *Pos == R) {
57+
return std::nullopt;
58+
}
59+
5560
if (Pos != End) {
5661
DWARFAddressRange Range(*Pos);
5762
if (Pos->merge(R))
@@ -112,8 +117,11 @@ bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const {
112117
auto I1 = Ranges.begin(), E1 = Ranges.end();
113118
auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
114119
while (I1 != E1 && I2 != E2) {
115-
if (I1->intersects(*I2))
116-
return true;
120+
if (I1->intersects(*I2)) {
121+
// Exact duplicates are allowed
122+
if (!(*I1 == *I2))
123+
return true;
124+
}
117125
if (I1->LowPC < I2->LowPC)
118126
++I1;
119127
else
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#--- comments.txt
2+
3+
# This test verifies several scenarios with DW_TAG_subprogram address ranges:
4+
# 1. Two subprograms can have identical ranges (shown with foo2 and foo3 having same low_pc/high_pc)
5+
# This is valid and can happen when ICF (Identical Code Folding) merges functions.
6+
# 2. Two subprograms can have overlapping ranges when using DW_AT_ranges
7+
# (shown with func1_with_ranges and func2_with_ranges sharing range 0x5000-0x6000)
8+
# This is also valid and can occur with -fbasic-block-sections=all
9+
# 3. The test also verifies that non-identical overlapping ranges are correctly flagged as errors:
10+
# - When modifying just the first range's high offset from 0x6000 to 0x5999, it creates an invalid subrange overlap
11+
# - When modifying just the first instance of DW_AT_high_pc 0x77 to 0x66, it creates an invalid function overlap
12+
# The test ensures llvm-dwarfdump --verify correctly validates these cases by:
13+
# a) Accepting valid identical overlapping ranges
14+
# b) Rejecting invalid non-identical overlapping ranges
15+
16+
# Need to use split-file in order for `sed` calls below to work correctly
17+
# RUN: split-file %s %t
18+
# RUN: yaml2obj %t/test.yaml | llvm-dwarfdump --error-display=details --verify - | FileCheck %s
19+
# CHECK: No errors.
20+
21+
# RUN: sed -e '1,/HighOffset: 0x6000/s/HighOffset: 0x6000/HighOffset: 0x5999/' %t/test.yaml | yaml2obj | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --check-prefix=CHECK-RANGES
22+
# CHECK-RANGES: error: DIEs have overlapping address ranges
23+
24+
# RUN: sed -e '1,/Value: 0x77/s/Value: 0x77/Value: 0x66/' %t/test.yaml | yaml2obj | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --check-prefix=CHECK-HIGH-PC
25+
# CHECK-HIGH-PC: error: DIEs have overlapping address ranges
26+
27+
# RUN: sed -e '1,/LowOffset: 0x880111/s/LowOffset: 0x880111/LowOffset: 0x880112/' %t/test.yaml | yaml2obj | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --check-prefix=CHECK-LEX-BLOCK
28+
# CHECK-LEX-BLOCK: DIE has overlapping ranges in DW_AT_ranges attribute
29+
30+
#--- test.yaml
31+
--- !ELF
32+
FileHeader:
33+
Class: ELFCLASS64
34+
Data: ELFDATA2LSB
35+
Type: ET_REL
36+
Machine: EM_X86_64
37+
DWARF:
38+
debug_abbrev:
39+
- Table:
40+
- Tag: DW_TAG_compile_unit
41+
Children: DW_CHILDREN_yes
42+
Attributes:
43+
- Attribute: DW_AT_producer
44+
Form: DW_FORM_string
45+
- Attribute: DW_AT_language
46+
Form: DW_FORM_data2
47+
- Attribute: DW_AT_name
48+
Form: DW_FORM_string
49+
- Attribute: DW_AT_low_pc
50+
Form: DW_FORM_addr
51+
- Attribute: DW_AT_high_pc
52+
Form: DW_FORM_data8
53+
- Tag: DW_TAG_subprogram
54+
Children: DW_CHILDREN_no
55+
Attributes:
56+
- Attribute: DW_AT_name
57+
Form: DW_FORM_string
58+
- Attribute: DW_AT_low_pc
59+
Form: DW_FORM_addr
60+
- Attribute: DW_AT_high_pc
61+
Form: DW_FORM_data8
62+
- Tag: DW_TAG_subprogram
63+
Children: DW_CHILDREN_no
64+
Attributes:
65+
- Attribute: DW_AT_name
66+
Form: DW_FORM_string
67+
- Attribute: DW_AT_ranges
68+
Form: DW_FORM_sec_offset
69+
- Tag: DW_TAG_base_type
70+
Children: DW_CHILDREN_no
71+
Attributes:
72+
- Attribute: DW_AT_name
73+
Form: DW_FORM_string
74+
- Tag: DW_TAG_lexical_block
75+
Children: DW_CHILDREN_no
76+
Attributes:
77+
- Attribute: DW_AT_ranges
78+
Form: DW_FORM_sec_offset
79+
debug_ranges:
80+
- Offset: 0x0
81+
AddrSize: 0x8
82+
Entries:
83+
- LowOffset: 0x1000
84+
HighOffset: 0x2000
85+
- LowOffset: 0x3000
86+
HighOffset: 0x4000
87+
- LowOffset: 0x5000 # Overlaps with 2nd range below
88+
HighOffset: 0x6000
89+
- LowOffset: 0x0
90+
HighOffset: 0x0
91+
- Offset: 0x50
92+
AddrSize: 0x8
93+
Entries:
94+
- LowOffset: 0x2500
95+
HighOffset: 0x2800
96+
- LowOffset: 0x5000 # Overlaps with 3rd range above
97+
HighOffset: 0x6000
98+
- LowOffset: 0x7000
99+
HighOffset: 0x8000
100+
- LowOffset: 0x0
101+
HighOffset: 0x0
102+
- Offset: 0xA0 # Added Range List #3 for lexical block
103+
AddrSize: 0x8
104+
Entries:
105+
- LowOffset: 0x880111
106+
HighOffset: 0x881222
107+
- LowOffset: 0x882333
108+
HighOffset: 0x883444
109+
- LowOffset: 0x880111 # Overlaps with 1st range in the same list
110+
HighOffset: 0x881222
111+
- LowOffset: 0x0 # End of list
112+
HighOffset: 0x0
113+
debug_info:
114+
- Version: 4
115+
Entries:
116+
- AbbrCode: 1
117+
Values:
118+
- CStr: by_hand
119+
- Value: 0x04
120+
- CStr: CU1
121+
- Value: 0x1000
122+
- Value: 0x100
123+
- AbbrCode: 4
124+
Values:
125+
- CStr: int
126+
- AbbrCode: 2
127+
Values:
128+
- CStr: foo1
129+
- Value: 0x1000
130+
- Value: 0x10
131+
- AbbrCode: 2
132+
Values:
133+
- CStr: foo2
134+
- Value: 0x0 # Overlaps with 'foo3' below
135+
- Value: 0x77
136+
- AbbrCode: 2
137+
Values:
138+
- CStr: foo3
139+
- Value: 0x0 # Overlaps with 'foo2' above
140+
- Value: 0x77
141+
- AbbrCode: 3
142+
Values:
143+
- CStr: func1_with_ranges
144+
- Value: 0x0
145+
- AbbrCode: 3
146+
Values:
147+
- CStr: func2_with_ranges
148+
- Value: 0x50
149+
- AbbrCode: 5 # Added lexical block using ranges
150+
Values:
151+
- Value: 0xA0 # Range list index in debug_ranges
152+
- AbbrCode: 0
153+
...

llvm/test/tools/llvm-dwarfdump/X86/verify_parent_zero_length.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
# DW_AT_high_pc (0x0000000000000000)
2020
#
2121
# 0x00000033: DW_TAG_lexical_block
22-
# DW_AT_low_pc (0x0000000000001000)
22+
# DW_AT_low_pc (0x0000000000001001)
2323
# DW_AT_high_pc (0x0000000000002000)
2424
#
2525
# 0x00000044: DW_TAG_lexical_block
@@ -47,7 +47,7 @@
4747

4848
# CHECK: error: DIEs have overlapping address ranges:
4949
# CHECK: 0x00000044: DW_TAG_lexical_block
50-
# CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000001000)
50+
# CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000001001)
5151
# CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000000002000)
5252

5353
# CHECK: 0x00000033: DW_TAG_lexical_block
@@ -61,7 +61,7 @@
6161
# CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000000000000)
6262

6363
# CHECK: 0x00000044: DW_TAG_lexical_block
64-
# CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000001000)
64+
# CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000001001)
6565
# CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000000002000)
6666

6767

@@ -229,7 +229,7 @@ DWARF:
229229
- Value: 0x0000000000002000
230230
- AbbrCode: 0x00000003
231231
Values:
232-
- Value: 0x0000000000001000
232+
- Value: 0x0000000000001001
233233
- Value: 0x0000000000002000
234234
- AbbrCode: 0x00000000
235235
- AbbrCode: 0x00000000

llvm/test/tools/llvm-dwarfutil/ELF/X86/verify.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ DWARF:
150150
Values:
151151
- CStr: foo3
152152
- Value: 0x0
153-
- Value: 0x100
153+
- Value: 0x80
154154
- Value: 0x00000040
155155
- AbbrCode: 0
156156
...

0 commit comments

Comments
 (0)