Skip to content

Commit 75f770a

Browse files
committed
[BOLT][DWARF] Update handling of size 1 ranges and fix sub-programs with ranges
When output range is only one entry, and input is low_pc/high_pc do not convert to ranges. This helps with size of .debug_ranges/.debug_rnglists. It also helps when either low_pc/high_pc is 0. We not generating potentially invalid ranges that result in LLDB error. Also fixed handling of DW_AT_subprogram with ranges. This can be created with -fbasic-block-sections=all. Reviewed By: maksfb Differential Revision: https://reviews.llvm.org/D156374
1 parent 09b6765 commit 75f770a

File tree

53 files changed

+4344
-110
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+4344
-110
lines changed

bolt/include/bolt/Core/DIEBuilder.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ class DIEBuilder {
359359
return Die->replaceValue(getState().DIEAlloc, Attribute, Form, NewValue);
360360
}
361361

362-
template <class T>
363362
bool deleteValue(DIEValueList *Die, dwarf::Attribute Attribute) {
364363
return Die->deleteValue(Attribute);
365364
}

bolt/include/bolt/Rewrite/DWARFRewriter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ class DWARFRewriter {
125125
/// attribute.
126126
void updateDWARFObjectAddressRanges(
127127
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
128-
uint64_t DebugRangesOffset, uint64_t LowPCToUse,
128+
uint64_t DebugRangesOffset,
129129
std::optional<uint64_t> RangesBase = std::nullopt);
130130

131131
std::unique_ptr<DebugBufferVector>
@@ -173,7 +173,7 @@ class DWARFRewriter {
173173
void convertToRangesPatchDebugInfo(
174174
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
175175
uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo,
176-
DIEValue &HighPCAttrInfo, uint64_t LowPCToUse,
176+
DIEValue &HighPCAttrInfo,
177177
std::optional<uint64_t> RangesBase = std::nullopt);
178178

179179
/// Adds a \p Str to .debug_str section.

bolt/lib/Rewrite/DWARFRewriter.cpp

Lines changed: 99 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,12 @@ static cl::opt<unsigned> BatchSize(
246246
"Specifies the size of batches for processing CUs. Higher number has "
247247
"better performance, but more memory usage. Default value is 1."),
248248
cl::Hidden, cl::init(1), cl::cat(BoltCategory));
249+
250+
static cl::opt<bool> AlwaysConvertToRanges(
251+
"always-convert-to-ranges",
252+
cl::desc("This option is for testing purposes only. It forces BOLT to "
253+
"convert low_pc/high_pc to ranges always."),
254+
cl::ReallyHidden, cl::init(false), cl::cat(BoltCategory));
249255
} // namespace opts
250256

251257
static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU,
@@ -693,6 +699,45 @@ void DWARFRewriter::updateUnitDebugInfo(
693699
const std::vector<std::unique_ptr<DIEBuilder::DIEInfo>> &DIs =
694700
DIEBldr.getDIEsByUnit(Unit);
695701

702+
// Either updates or normalizes DW_AT_range to DW_AT_low_pc and DW_AT_high_pc.
703+
auto updateLowPCHighPC = [&](DIE *Die, const DIEValue &LowPCVal,
704+
const DIEValue &HighPCVal, uint64_t LowPC,
705+
const uint64_t HighPC) {
706+
dwarf::Attribute AttrLowPC = dwarf::DW_AT_low_pc;
707+
dwarf::Form FormLowPC = dwarf::DW_FORM_addr;
708+
dwarf::Attribute AttrHighPC = dwarf::DW_AT_high_pc;
709+
dwarf::Form FormHighPC = dwarf::DW_FORM_data4;
710+
const uint32_t Size = HighPC - LowPC;
711+
// Whatever was generated is not low_pc/high_pc, so will reset to
712+
// default for size 1.
713+
if (!LowPCVal || !HighPCVal) {
714+
if (Unit.getVersion() >= 5)
715+
FormLowPC = dwarf::DW_FORM_addrx;
716+
else if (Unit.isDWOUnit())
717+
FormLowPC = dwarf::DW_FORM_GNU_addr_index;
718+
} else {
719+
AttrLowPC = LowPCVal.getAttribute();
720+
FormLowPC = LowPCVal.getForm();
721+
AttrHighPC = HighPCVal.getAttribute();
722+
FormHighPC = HighPCVal.getForm();
723+
}
724+
725+
if (FormLowPC == dwarf::DW_FORM_addrx ||
726+
FormLowPC == dwarf::DW_FORM_GNU_addr_index)
727+
LowPC = AddrWriter->getIndexFromAddress(LowPC, Unit);
728+
729+
if (LowPCVal)
730+
DIEBldr.replaceValue(Die, AttrLowPC, FormLowPC, DIEInteger(LowPC));
731+
else
732+
DIEBldr.addValue(Die, AttrLowPC, FormLowPC, DIEInteger(LowPC));
733+
if (HighPCVal) {
734+
DIEBldr.replaceValue(Die, AttrHighPC, FormHighPC, DIEInteger(Size));
735+
} else {
736+
DIEBldr.deleteValue(Die, dwarf::DW_AT_ranges);
737+
DIEBldr.addValue(Die, AttrHighPC, FormHighPC, DIEInteger(Size));
738+
}
739+
};
740+
696741
for (const std::unique_ptr<DIEBuilder::DIEInfo> &DI : DIs) {
697742
DIE *Die = DI->Die;
698743
switch (Die->getTag()) {
@@ -726,7 +771,7 @@ void DWARFRewriter::updateUnitDebugInfo(
726771
ARangesSectionWriter->addCURanges(Unit.getOffset(),
727772
std::move(OutputRanges));
728773
updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset,
729-
0, RangesBase);
774+
RangesBase);
730775
DIEValue StmtListAttrVal = Die->findAttribute(dwarf::DW_AT_stmt_list);
731776
if (LineTablePatchMap.count(&Unit))
732777
DIEBldr.replaceValue(Die, dwarf::DW_AT_stmt_list,
@@ -737,8 +782,9 @@ void DWARFRewriter::updateUnitDebugInfo(
737782

738783
case dwarf::DW_TAG_subprogram: {
739784
// Get function address either from ranges or [LowPC, HighPC) pair.
740-
uint64_t Address;
785+
uint64_t Address = UINT64_MAX;
741786
uint64_t SectionIndex, HighPC;
787+
DebugAddressRangesVector FunctionRanges;
742788
if (!getLowAndHighPC(*Die, Unit, Address, HighPC, SectionIndex)) {
743789
Expected<DWARFAddressRangesVector> RangesOrError =
744790
getDIEAddressRanges(*Die, Unit);
@@ -751,23 +797,41 @@ void DWARFRewriter::updateUnitDebugInfo(
751797
if (Ranges.empty())
752798
break;
753799

754-
Address = Ranges.front().LowPC;
800+
for (const DWARFAddressRange &Range : Ranges) {
801+
if (const BinaryFunction *Function =
802+
BC.getBinaryFunctionAtAddress(Range.LowPC))
803+
FunctionRanges.append(Function->getOutputAddressRanges());
804+
}
805+
} else {
806+
if (const BinaryFunction *Function =
807+
BC.getBinaryFunctionAtAddress(Address))
808+
FunctionRanges = Function->getOutputAddressRanges();
755809
}
756810

757811
// Clear cached ranges as the new function will have its own set.
758812
CachedRanges.clear();
813+
DIEValue LowPCVal = Die->findAttribute(dwarf::DW_AT_low_pc);
814+
DIEValue HighPCVal = Die->findAttribute(dwarf::DW_AT_high_pc);
815+
if (FunctionRanges.empty()) {
816+
if (LowPCVal && HighPCVal) {
817+
FunctionRanges.push_back({0, HighPCVal.getDIEInteger().getValue()});
818+
} else {
819+
// I haven't seen this case, but who knows what other compilers
820+
// generate.
821+
FunctionRanges.push_back({0, 1});
822+
errs() << "BOLT-WARNING: [internal-dwarf-error]: subprogram got GCed "
823+
"by the linker, DW_AT_ranges is used\n";
824+
}
825+
}
759826

760-
DebugAddressRangesVector FunctionRanges;
761-
if (const BinaryFunction *Function =
762-
BC.getBinaryFunctionAtAddress(Address))
763-
FunctionRanges = Function->getOutputAddressRanges();
764-
765-
if (FunctionRanges.empty())
766-
FunctionRanges.push_back({0, 0});
827+
if (FunctionRanges.size() == 1 && !opts::AlwaysConvertToRanges) {
828+
updateLowPCHighPC(Die, LowPCVal, HighPCVal, FunctionRanges.back().LowPC,
829+
FunctionRanges.back().HighPC);
830+
break;
831+
}
767832

768833
updateDWARFObjectAddressRanges(
769-
Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges),
770-
0);
834+
Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges));
771835

772836
break;
773837
}
@@ -783,37 +847,33 @@ void DWARFRewriter::updateUnitDebugInfo(
783847
? BC.getBinaryFunctionContainingAddress(
784848
RangesOrError->front().LowPC)
785849
: nullptr;
786-
bool ErrorState = false;
787-
std::optional<uint64_t> NewLowPC;
850+
DebugAddressRangesVector OutputRanges;
788851
if (Function) {
789-
DebugAddressRangesVector OutputRanges =
790-
Function->translateInputToOutputRanges(*RangesOrError);
852+
OutputRanges = Function->translateInputToOutputRanges(*RangesOrError);
791853
LLVM_DEBUG(if (OutputRanges.empty() != RangesOrError->empty()) {
792854
dbgs() << "BOLT-DEBUG: problem with DIE at 0x"
793855
<< Twine::utohexstr(Die->getOffset()) << " in CU at 0x"
794856
<< Twine::utohexstr(Unit.getOffset()) << '\n';
795857
});
796-
if (!OutputRanges.empty())
797-
NewLowPC = OutputRanges.front().LowPC;
798-
RangesSectionOffset = RangesSectionWriter.addRanges(
799-
std::move(OutputRanges), CachedRanges);
858+
if (opts::AlwaysConvertToRanges || OutputRanges.size() > 1) {
859+
RangesSectionOffset = RangesSectionWriter.addRanges(
860+
std::move(OutputRanges), CachedRanges);
861+
OutputRanges.clear();
862+
} else if (OutputRanges.empty()) {
863+
OutputRanges.push_back({RangesOrError.get().front().LowPC,
864+
RangesOrError.get().front().HighPC});
865+
}
800866
} else if (!RangesOrError) {
801-
ErrorState = true;
802867
consumeError(RangesOrError.takeError());
803868
}
804-
805-
uint64_t LowPCToUse = 0;
806-
if (!ErrorState && RangesOrError.get().size() == 1 &&
807-
RangesOrError.get().begin()->LowPC ==
808-
RangesOrError.get().begin()->HighPC) {
809-
if (NewLowPC)
810-
LowPCToUse = NewLowPC.value();
811-
else
812-
LowPCToUse = RangesOrError.get().begin()->LowPC;
869+
DIEValue LowPCVal = Die->findAttribute(dwarf::DW_AT_low_pc);
870+
DIEValue HighPCVal = Die->findAttribute(dwarf::DW_AT_high_pc);
871+
if (OutputRanges.size() == 1) {
872+
updateLowPCHighPC(Die, LowPCVal, HighPCVal, OutputRanges.back().LowPC,
873+
OutputRanges.back().HighPC);
874+
break;
813875
}
814-
815-
updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset,
816-
LowPCToUse);
876+
updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset);
817877
break;
818878
}
819879
case dwarf::DW_TAG_call_site: {
@@ -1147,7 +1207,7 @@ void DWARFRewriter::updateUnitDebugInfo(
11471207

11481208
void DWARFRewriter::updateDWARFObjectAddressRanges(
11491209
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, uint64_t DebugRangesOffset,
1150-
uint64_t LowPCToUse, std::optional<uint64_t> RangesBase) {
1210+
std::optional<uint64_t> RangesBase) {
11511211

11521212
if (RangesBase) {
11531213
// If DW_AT_GNU_ranges_base is present, update it. No further modifications
@@ -1195,7 +1255,7 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
11951255
LowPCAttrInfo.getForm() != dwarf::DW_FORM_GNU_addr_index &&
11961256
LowPCAttrInfo.getForm() != dwarf::DW_FORM_addrx)
11971257
DIEBldr.replaceValue(&Die, dwarf::DW_AT_low_pc, LowPCAttrInfo.getForm(),
1198-
DIEInteger(LowPCToUse));
1258+
DIEInteger(0));
11991259
return;
12001260
}
12011261

@@ -1223,8 +1283,7 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
12231283
if (LowPCAttrInfo && HighPCAttrInfo) {
12241284

12251285
convertToRangesPatchDebugInfo(Unit, DIEBldr, Die, DebugRangesOffset,
1226-
LowPCAttrInfo, HighPCAttrInfo, LowPCToUse,
1227-
RangesBase);
1286+
LowPCAttrInfo, HighPCAttrInfo, RangesBase);
12281287
} else if (!(Unit.isDWOUnit() &&
12291288
Die.getTag() == dwarf::DW_TAG_compile_unit)) {
12301289
if (opts::Verbosity >= 1)
@@ -2086,8 +2145,7 @@ DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) {
20862145
void DWARFRewriter::convertToRangesPatchDebugInfo(
20872146
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
20882147
uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo,
2089-
DIEValue &HighPCAttrInfo, uint64_t LowPCToUse,
2090-
std::optional<uint64_t> RangesBase) {
2148+
DIEValue &HighPCAttrInfo, std::optional<uint64_t> RangesBase) {
20912149
uint32_t BaseOffset = 0;
20922150
dwarf::Form LowForm = LowPCAttrInfo.getForm();
20932151
dwarf::Attribute RangeBaseAttribute = dwarf::DW_AT_GNU_ranges_base;
@@ -2120,12 +2178,12 @@ void DWARFRewriter::convertToRangesPatchDebugInfo(
21202178
// DW_FORM_addrx. Former is when DW_AT_rnglists_base is present. Latter is
21212179
// when it's absent.
21222180
if (LowForm == dwarf::DW_FORM_addrx) {
2123-
const uint32_t Index = AddrWriter->getIndexFromAddress(LowPCToUse, Unit);
2181+
const uint32_t Index = AddrWriter->getIndexFromAddress(0, Unit);
21242182
DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(),
21252183
LowPCAttrInfo.getForm(), DIEInteger(Index));
21262184
} else
21272185
DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(),
2128-
LowPCAttrInfo.getForm(), DIEInteger(LowPCToUse));
2186+
LowPCAttrInfo.getForm(), DIEInteger(0));
21292187

21302188
// Original CU didn't have DW_AT_*_base. We converted it's children (or
21312189
// dwo), so need to insert it into CU.

bolt/test/AArch64/go_dwarf.test

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,5 @@ CHECK-NEXT: DW_AT_decl_file
4949
CHECK-NEXT: DW_AT_decl_line (1)
5050
CHECK-NEXT: DW_AT_decl_column (0x05)
5151
CHECK-NEXT: DW_AT_type
52-
CHECK-NEXT: DW_AT_low_pc (0x0000000000000000)
53-
CHECK-NEXT: DW_AT_ranges (0x00000030
54-
CHECK-NEXT: [0x0000000000000660, 0x0000000000000684))
52+
CHECK-NEXT: DW_AT_low_pc (0x0000000000000660)
53+
CHECK-NEXT: DW_AT_high_pc (0x0000000000000024)

0 commit comments

Comments
 (0)