Skip to content

Commit 1f7d034

Browse files
committed
Fix spurious errors that would be emitted when DW_TAG_subprogram DIEs had mutliple ranges in DW_AT_ranges.
llvm-gsymutil would emit errors about address ranges for DW_TAG_inlined_subroutine DIEs whose address range didn't exist in the parent inline information. When a DW_TAG_subprogram DIE has more than one address range with a DW_AT_ranges attribute, we emit multiple FunctionInfo objets, one for each range of a function. When we parsed the inline information, it might have inline contribution that appear in any of the function's ranges, and if we were parsing the first range of a function, all inline entries that appeared in other valid ranges of the functions would end up emitting error messages. This patch fixes this by always passing down the full list of ranges, even if they aren't being used in the parse of the information. This eliminates reporting of errors when we shouldn't have been emitting error messages. Added a test to track this and ensure this doesn't regress. Also we don't warn if we end up with empty inline information if the only top level inline function have been elided where the high and low PC values are the same which indicates that the inline function was elided. Differential Revision: https://reviews.llvm.org/D157669
1 parent 2991c39 commit 1f7d034

File tree

2 files changed

+538
-20
lines changed

2 files changed

+538
-20
lines changed

llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -205,36 +205,67 @@ static bool hasInlineInfo(DWARFDie Die, uint32_t Depth) {
205205
return false;
206206
}
207207

208+
static AddressRanges
209+
ConvertDWARFRanges(const DWARFAddressRangesVector &DwarfRanges) {
210+
AddressRanges Ranges;
211+
for (const DWARFAddressRange &DwarfRange : DwarfRanges) {
212+
if (DwarfRange.LowPC < DwarfRange.HighPC)
213+
Ranges.insert({DwarfRange.LowPC, DwarfRange.HighPC});
214+
}
215+
return Ranges;
216+
}
217+
208218
static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI,
209219
DWARFDie Die, uint32_t Depth, FunctionInfo &FI,
210-
InlineInfo &parent) {
220+
InlineInfo &Parent,
221+
const AddressRanges &AllParentRanges,
222+
bool &WarnIfEmpty) {
211223
if (!hasInlineInfo(Die, Depth))
212224
return;
213225

214226
dwarf::Tag Tag = Die.getTag();
215227
if (Tag == dwarf::DW_TAG_inlined_subroutine) {
216228
// create new InlineInfo and append to parent.children
217229
InlineInfo II;
230+
AddressRanges AllInlineRanges;
218231
Expected<DWARFAddressRangesVector> RangesOrError = Die.getAddressRanges();
219232
if (RangesOrError) {
220-
for (const DWARFAddressRange &Range : RangesOrError.get()) {
221-
// Check that the inlined function is within the any of the range the
222-
// parent InlineInfo. If it isn't remove it!
223-
AddressRange InlineRange(Range.LowPC, Range.HighPC);
233+
AllInlineRanges = ConvertDWARFRanges(RangesOrError.get());
234+
uint32_t EmptyCount = 0;
235+
for (const AddressRange &InlineRange : AllInlineRanges) {
224236
// Check for empty inline range in case inline function was outlined
225237
// or has not code
226-
if (!InlineRange.empty()) {
227-
if (parent.Ranges.contains(InlineRange)) {
238+
if (InlineRange.empty()) {
239+
++EmptyCount;
240+
} else {
241+
if (Parent.Ranges.contains(InlineRange)) {
228242
II.Ranges.insert(InlineRange);
229-
} else if (Log) {
230-
*Log << "error: inlined function DIE at " << HEX32(Die.getOffset())
231-
<< " has a range [" << HEX64(Range.LowPC) << " - "
232-
<< HEX64(Range.HighPC) << ") that isn't contained in any "
233-
<< "parent address ranges, this inline range will be "
234-
"removed.\n";
243+
} else {
244+
// Only warn if the current inline range is not within any of all
245+
// of the parent ranges. If we have a DW_TAG_subpgram with multiple
246+
// ranges we will emit a FunctionInfo for each range of that
247+
// function that only emits information within the current range,
248+
// so we only want to emit an error if the DWARF has issues, not
249+
// when a range currently just isn't in the range we are currently
250+
// parsing for.
251+
if (AllParentRanges.contains(InlineRange)) {
252+
WarnIfEmpty = false;
253+
} else if (Log) {
254+
*Log << "error: inlined function DIE at "
255+
<< HEX32(Die.getOffset()) << " has a range ["
256+
<< HEX64(InlineRange.start()) << " - "
257+
<< HEX64(InlineRange.end()) << ") that isn't contained in "
258+
<< "any parent address ranges, this inline range will be "
259+
"removed.\n";
260+
}
235261
}
236262
}
237263
}
264+
// If we have all empty ranges for the inlines, then don't warn if we
265+
// have an empty InlineInfo at the top level as all inline functions
266+
// were elided.
267+
if (EmptyCount == AllInlineRanges.size())
268+
WarnIfEmpty = false;
238269
}
239270
if (II.Ranges.empty())
240271
return;
@@ -246,14 +277,16 @@ static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI,
246277
II.CallLine = dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_line), 0);
247278
// parse all children and append to parent
248279
for (DWARFDie ChildDie : Die.children())
249-
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, II);
250-
parent.Children.emplace_back(std::move(II));
280+
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, II,
281+
AllInlineRanges, WarnIfEmpty);
282+
Parent.Children.emplace_back(std::move(II));
251283
return;
252284
}
253285
if (Tag == dwarf::DW_TAG_subprogram || Tag == dwarf::DW_TAG_lexical_block) {
254286
// skip this Die and just recurse down
255287
for (DWARFDie ChildDie : Die.children())
256-
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, parent);
288+
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, Parent,
289+
AllParentRanges, WarnIfEmpty);
257290
}
258291
}
259292

@@ -381,6 +414,13 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
381414
}
382415
break;
383416
}
417+
// All ranges for the subprogram DIE in case it has multiple. We need to
418+
// pass this down into parseInlineInfo so we don't warn about inline
419+
// ranges that are not in the current subrange of a function when they
420+
// actually are in another subgrange. We do this because when a function
421+
// has discontiguos ranges, we create multiple function entries with only
422+
// the info for that range contained inside of it.
423+
AddressRanges AllSubprogramRanges = ConvertDWARFRanges(Ranges);
384424

385425
// Create a function_info for each range
386426
for (const DWARFAddressRange &Range : Ranges) {
@@ -422,14 +462,16 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
422462
FunctionInfo FI;
423463
FI.Range = {Range.LowPC, Range.HighPC};
424464
FI.Name = *NameIndex;
425-
if (CUI.LineTable) {
465+
if (CUI.LineTable)
426466
convertFunctionLineTable(OS, CUI, Die, Gsym, FI);
427-
}
467+
428468
if (hasInlineInfo(Die, 0)) {
429469
FI.Inline = InlineInfo();
430470
FI.Inline->Name = *NameIndex;
431471
FI.Inline->Ranges.insert(FI.Range);
432-
parseInlineInfo(Gsym, OS, CUI, Die, 0, FI, *FI.Inline);
472+
bool WarnIfEmpty = true;
473+
parseInlineInfo(Gsym, OS, CUI, Die, 0, FI, *FI.Inline,
474+
AllSubprogramRanges, WarnIfEmpty);
433475
// Make sure we at least got some valid inline info other than just
434476
// the top level function. If we didn't then remove the inline info
435477
// from the function info. We have seen cases where LTO tries to modify
@@ -440,7 +482,7 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
440482
// information object, we will know if we got anything valid from the
441483
// debug info.
442484
if (FI.Inline->Children.empty()) {
443-
if (OS && !Gsym.isQuiet()) {
485+
if (WarnIfEmpty && OS && !Gsym.isQuiet()) {
444486
*OS << "warning: DIE contains inline function information that has "
445487
"no valid ranges, removing inline information:\n";
446488
Die.dump(*OS, 0, DIDumpOptions::getForSingleDIE());

0 commit comments

Comments
 (0)