-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[DWARFVerifier] Allow overlapping ranges for ICF-merged functions #117952
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
Changes from 3 commits
a5f73d2
a466e50
f6daae5
0e873b7
22f8f8a
8fc6a58
d55fd0d
156614b
a7f9e46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,14 +70,15 @@ DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { | |
| } | ||
|
|
||
| DWARFVerifier::DieRangeInfo::die_range_info_iterator | ||
| DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { | ||
| DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI, | ||
| bool AllowDuplicates) { | ||
| if (RI.Ranges.empty()) | ||
| return Children.end(); | ||
|
|
||
| auto End = Children.end(); | ||
| auto Iter = Children.begin(); | ||
| while (Iter != End) { | ||
| if (Iter->intersects(RI)) | ||
| if (Iter->intersects(RI, AllowDuplicates)) | ||
| return Iter; | ||
| ++Iter; | ||
| } | ||
|
|
@@ -109,12 +110,16 @@ bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const { | |
| return false; | ||
| } | ||
|
|
||
| bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const { | ||
| bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS, | ||
| bool AllowDuplicates) const { | ||
| auto I1 = Ranges.begin(), E1 = Ranges.end(); | ||
| auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); | ||
| while (I1 != E1 && I2 != E2) { | ||
| if (I1->intersects(*I2)) | ||
| return true; | ||
| if (I1->intersects(*I2)) { | ||
| bool IsDuplicate = *I1 == *I2; | ||
| if (!AllowDuplicates || !IsDuplicate) | ||
| return true; | ||
| } | ||
| if (I1->LowPC < I2->LowPC) | ||
| ++I1; | ||
| else | ||
|
|
@@ -146,11 +151,13 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, | |
| if (Version >= 5) { | ||
| UnitType = DebugInfoData.getU8(Offset); | ||
| AddrSize = DebugInfoData.getU8(Offset); | ||
| AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); | ||
| AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) | ||
| : DebugInfoData.getU32(Offset); | ||
| ValidType = dwarf::isUnitType(UnitType); | ||
| } else { | ||
| UnitType = 0; | ||
| AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); | ||
| AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) | ||
| : DebugInfoData.getU32(Offset); | ||
| AddrSize = DebugInfoData.getU8(Offset); | ||
| } | ||
|
|
||
|
|
@@ -412,7 +419,7 @@ unsigned DWARFVerifier::verifyUnits(const DWARFUnitVector &Units) { | |
| unsigned Index = 1; | ||
| for (const auto &Unit : Units) { | ||
| OS << "Verifying unit: " << Index << " / " << Units.getNumUnits(); | ||
| if (const char* Name = Unit->getUnitDIE(true).getShortName()) | ||
| if (const char *Name = Unit->getUnitDIE(true).getShortName()) | ||
| OS << ", \"" << Name << '\"'; | ||
| OS << '\n'; | ||
| OS.flush(); | ||
|
|
@@ -531,14 +538,12 @@ bool DWARFVerifier::handleDebugInfo() { | |
| unsigned NumErrors = 0; | ||
|
|
||
| OS << "Verifying .debug_info Unit Header Chain...\n"; | ||
| DObj.forEachInfoSections([&](const DWARFSection &S) { | ||
| NumErrors += verifyUnitSection(S); | ||
| }); | ||
| DObj.forEachInfoSections( | ||
| [&](const DWARFSection &S) { NumErrors += verifyUnitSection(S); }); | ||
|
|
||
| OS << "Verifying .debug_types Unit Header Chain...\n"; | ||
| DObj.forEachTypesSections([&](const DWARFSection &S) { | ||
| NumErrors += verifyUnitSection(S); | ||
| }); | ||
| DObj.forEachTypesSections( | ||
| [&](const DWARFSection &S) { NumErrors += verifyUnitSection(S); }); | ||
|
|
||
| OS << "Verifying non-dwo Units...\n"; | ||
| NumErrors += verifyUnits(DCtx.getNormalUnitsVector()); | ||
|
|
@@ -622,14 +627,17 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, | |
| } | ||
|
|
||
| // Verify that children don't intersect. | ||
| const auto IntersectingChild = ParentRI.insert(RI); | ||
| bool AllowDuplicates = Die.getTag() == DW_TAG_subprogram; | ||
|
||
| const auto IntersectingChild = ParentRI.insert(RI, AllowDuplicates); | ||
| if (IntersectingChild != ParentRI.Children.end()) { | ||
| ++NumErrors; | ||
| ErrorCategory.Report("DIEs have overlapping address ranges", [&]() { | ||
| error() << "DIEs have overlapping address ranges:"; | ||
| dump(Die); | ||
| dump(IntersectingChild->Die) << '\n'; | ||
| }); | ||
| if (IntersectingChild->Ranges != ParentRI.Children.end()->Ranges) { | ||
| ++NumErrors; | ||
| ErrorCategory.Report("DIEs have overlapping address ranges", [&]() { | ||
| error() << "DIEs have overlapping address ranges:"; | ||
| dump(Die); | ||
| dump(IntersectingChild->Die) << '\n'; | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| // Verify that ranges are contained within their parent. | ||
|
|
@@ -914,8 +922,7 @@ unsigned DWARFVerifier::verifyDebugInfoReferences( | |
| return DWARFDie(); | ||
| }; | ||
| unsigned NumErrors = 0; | ||
| for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair : | ||
| References) { | ||
| for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair : References) { | ||
| if (GetDIEForOffset(Pair.first)) | ||
| continue; | ||
| ++NumErrors; | ||
|
|
@@ -2117,7 +2124,8 @@ bool DWARFVerifier::verifyDebugStrOffsets( | |
| }); | ||
| Success = false; | ||
| } | ||
| for (uint64_t Index = 0; C && C.tell() + OffsetByteSize <= NextUnit; ++Index) { | ||
| for (uint64_t Index = 0; C && C.tell() + OffsetByteSize <= NextUnit; | ||
| ++Index) { | ||
| uint64_t OffOff = C.tell(); | ||
| uint64_t StrOff = DA.getAddress(C); | ||
| // check StrOff refers to the start of a string | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| //--- comments.txt | ||
|
|
||
| # This test verifies several scenarios with DW_TAG_subprogram address ranges: | ||
| # 1. Two subprograms can have identical ranges (shown with foo2 and foo3 having same low_pc/high_pc) | ||
| # This is valid and can happen when ICF (Identical Code Folding) merges functions. | ||
| # 2. Two subprograms can have overlapping ranges when using DW_AT_ranges | ||
| # (shown with func1_with_ranges and func2_with_ranges sharing range 0x5000-0x6000) | ||
| # This is also valid and can occur with -fbasic-block-sections=all | ||
| # 3. The test also verifies that non-identical overlapping ranges are correctly flagged as errors: | ||
| # - When modifying just the first range's high offset from 0x6000 to 0x5999, it creates an invalid subrange overlap | ||
| # - When modifying just the first instance of DW_AT_high_pc 0x77 to 0x66, it creates an invalid function overlap | ||
| # The test ensures llvm-dwarfdump --verify correctly validates these cases by: | ||
| # a) Accepting valid identical overlapping ranges | ||
| # b) Rejecting invalid non-identical overlapping ranges | ||
|
|
||
| # Need to use split-file in order for `sed` calls below to work correctly | ||
| # RUN: split-file %s %t | ||
| # RUN: yaml2obj %t/test.yaml | llvm-dwarfdump --error-display=details --verify - | FileCheck %s | ||
| # CHECK: No errors. | ||
|
|
||
| # RUN: sed '0,/HighOffset: 0x6000/{s//HighOffset: 0x5999/}' %t/test.yaml | yaml2obj | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --check-prefix=CHECK-RANGES | ||
| # CHECK-RANGES: error: DIEs have overlapping address ranges | ||
|
|
||
| # RUN: sed '0,/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 | ||
| # CHECK-HIGH-PC: error: DIEs have overlapping address ranges | ||
|
|
||
| //--- test.yaml | ||
| --- !ELF | ||
| FileHeader: | ||
| Class: ELFCLASS64 | ||
| Data: ELFDATA2LSB | ||
| Type: ET_REL | ||
| Machine: EM_X86_64 | ||
| DWARF: | ||
| debug_abbrev: | ||
| - Table: | ||
| - Tag: DW_TAG_compile_unit | ||
| Children: DW_CHILDREN_yes | ||
| Attributes: | ||
| - Attribute: DW_AT_producer | ||
| Form: DW_FORM_string | ||
| - Attribute: DW_AT_language | ||
| Form: DW_FORM_data2 | ||
| - Attribute: DW_AT_name | ||
| Form: DW_FORM_string | ||
| - Attribute: DW_AT_low_pc | ||
| Form: DW_FORM_addr | ||
| - Attribute: DW_AT_high_pc | ||
| Form: DW_FORM_data8 | ||
| - Tag: DW_TAG_subprogram | ||
| Children: DW_CHILDREN_no | ||
| Attributes: | ||
| - Attribute: DW_AT_name | ||
| Form: DW_FORM_string | ||
| - Attribute: DW_AT_low_pc | ||
| Form: DW_FORM_addr | ||
| - Attribute: DW_AT_high_pc | ||
| Form: DW_FORM_data8 | ||
| - Tag: DW_TAG_subprogram | ||
| Children: DW_CHILDREN_no | ||
| Attributes: | ||
| - Attribute: DW_AT_name | ||
| Form: DW_FORM_string | ||
| - Attribute: DW_AT_ranges | ||
| Form: DW_FORM_sec_offset | ||
| - Tag: DW_TAG_base_type | ||
| Children: DW_CHILDREN_no | ||
| Attributes: | ||
| - Attribute: DW_AT_name | ||
| Form: DW_FORM_string | ||
| debug_ranges: | ||
| - Offset: 0x0 | ||
| AddrSize: 0x8 | ||
| Entries: | ||
| - LowOffset: 0x1000 | ||
| HighOffset: 0x2000 | ||
| - LowOffset: 0x3000 | ||
| HighOffset: 0x4000 | ||
| - LowOffset: 0x5000 # Overlaps with 2nd range below | ||
| HighOffset: 0x6000 | ||
| - LowOffset: 0x0 | ||
| HighOffset: 0x0 | ||
| - Offset: 0x50 | ||
| AddrSize: 0x8 | ||
| Entries: | ||
| - LowOffset: 0x2500 | ||
| HighOffset: 0x2800 | ||
| - LowOffset: 0x5000 # Overlaps with 3rd range above | ||
| HighOffset: 0x6000 | ||
| - LowOffset: 0x7000 | ||
| HighOffset: 0x8000 | ||
| - LowOffset: 0x0 | ||
| HighOffset: 0x0 | ||
| debug_info: | ||
| - Version: 4 | ||
| Entries: | ||
| - AbbrCode: 1 | ||
| Values: | ||
| - CStr: by_hand | ||
| - Value: 0x04 | ||
| - CStr: CU1 | ||
| - Value: 0x1000 | ||
| - Value: 0x100 | ||
| - AbbrCode: 4 | ||
| Values: | ||
| - CStr: int | ||
| - AbbrCode: 2 | ||
| Values: | ||
| - CStr: foo1 | ||
| - Value: 0x1000 | ||
| - Value: 0x10 | ||
| - AbbrCode: 2 | ||
| Values: | ||
| - CStr: foo2 | ||
| - Value: 0x0 # Overlaps with 'foo3' below | ||
| - Value: 0x77 | ||
| - AbbrCode: 2 | ||
| Values: | ||
| - CStr: foo3 | ||
| - Value: 0x0 # Overlaps with 'foo2' above | ||
| - Value: 0x77 | ||
| - AbbrCode: 3 | ||
| Values: | ||
| - CStr: func1_with_ranges | ||
| - Value: 0x0 | ||
| - AbbrCode: 3 | ||
| Values: | ||
| - CStr: func2_with_ranges | ||
| - Value: 0x50 | ||
| - AbbrCode: 0 | ||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -150,7 +150,7 @@ DWARF: | |
| Values: | ||
| - CStr: foo3 | ||
| - Value: 0x0 | ||
| - Value: 0x100 | ||
| - Value: 0x80 | ||
| - Value: 0x00000040 | ||
| - AbbrCode: 0 | ||
| ... | ||
Uh oh!
There was an error while loading. Please reload this page.