Skip to content

Commit 0156b6e

Browse files
authored
Modify llvm-gsymutil to ignore invalid file indexes (#71431)
DWARF produced by LTO and BOLT can sometimes be broken where file indexes are beyond the end of the line table's file list in the prologue. This patch allows llvm-gsymutil to convert this DWARF without crashing, and emits errors when: line table contains entries with an invalid file index (line entry will be removed) inline functions that have invalid DW_AT_call_file file indexes when there are no line table entries for a function and we fall back to making a single line table entry from the functions DW_AT_decl_file/DW_AT_decl_line attributes, we make sure the DW_AT_decl_file attribute is valid before emitting it.
1 parent e15fcd7 commit 0156b6e

File tree

2 files changed

+405
-14
lines changed

2 files changed

+405
-14
lines changed

llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp

+49-14
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ struct llvm::gsym::CUInfo {
6565
/// the first client that asks for a compile unit file index will end up
6666
/// doing the conversion, and subsequent clients will get the cached GSYM
6767
/// index.
68-
uint32_t DWARFToGSYMFileIndex(GsymCreator &Gsym, uint32_t DwarfFileIdx) {
69-
if (!LineTable)
70-
return 0;
71-
assert(DwarfFileIdx < FileCache.size());
68+
std::optional<uint32_t> DWARFToGSYMFileIndex(GsymCreator &Gsym,
69+
uint32_t DwarfFileIdx) {
70+
if (!LineTable || DwarfFileIdx >= FileCache.size())
71+
return std::nullopt;
7272
uint32_t &GsymFileIdx = FileCache[DwarfFileIdx];
7373
if (GsymFileIdx != UINT32_MAX)
7474
return GsymFileIdx;
@@ -272,14 +272,24 @@ static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI,
272272

273273
if (auto NameIndex = getQualifiedNameIndex(Die, CUI.Language, Gsym))
274274
II.Name = *NameIndex;
275-
II.CallFile = CUI.DWARFToGSYMFileIndex(
276-
Gsym, dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_file), 0));
277-
II.CallLine = dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_line), 0);
278-
// parse all children and append to parent
279-
for (DWARFDie ChildDie : Die.children())
280-
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, II,
281-
AllInlineRanges, WarnIfEmpty);
282-
Parent.Children.emplace_back(std::move(II));
275+
const uint64_t DwarfFileIdx = dwarf::toUnsigned(
276+
Die.findRecursively(dwarf::DW_AT_call_file), UINT32_MAX);
277+
std::optional<uint32_t> OptGSymFileIdx =
278+
CUI.DWARFToGSYMFileIndex(Gsym, DwarfFileIdx);
279+
if (OptGSymFileIdx) {
280+
II.CallFile = OptGSymFileIdx.value();
281+
II.CallLine = dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_line), 0);
282+
// parse all children and append to parent
283+
for (DWARFDie ChildDie : Die.children())
284+
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, II,
285+
AllInlineRanges, WarnIfEmpty);
286+
Parent.Children.emplace_back(std::move(II));
287+
} else if (Log) {
288+
*Log << "error: inlined function DIE at " << HEX32(Die.getOffset())
289+
<< " has an invalid file index " << DwarfFileIdx
290+
<< " in its DW_AT_call_file attribute, this inline entry and all "
291+
<< "children will be removed.\n";
292+
}
283293
return;
284294
}
285295
if (Tag == dwarf::DW_TAG_subprogram || Tag == dwarf::DW_TAG_lexical_block) {
@@ -306,8 +316,20 @@ static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
306316
// the DW_AT_decl_file an d DW_AT_decl_line if we have both attributes.
307317
std::string FilePath = Die.getDeclFile(
308318
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
309-
if (FilePath.empty())
319+
if (FilePath.empty()) {
320+
// If we had a DW_AT_decl_file, but got no file then we need to emit a
321+
// warning.
322+
if (Log) {
323+
const uint64_t DwarfFileIdx = dwarf::toUnsigned(
324+
Die.findRecursively(dwarf::DW_AT_decl_file), UINT32_MAX);
325+
*Log << "error: function DIE at " << HEX32(Die.getOffset())
326+
<< " has an invalid file index " << DwarfFileIdx
327+
<< " in its DW_AT_decl_file attribute, unable to create a single "
328+
<< "line entry from the DW_AT_decl_file/DW_AT_decl_line "
329+
<< "attributes.\n";
330+
}
310331
return;
332+
}
311333
if (auto Line =
312334
dwarf::toUnsigned(Die.findRecursively({dwarf::DW_AT_decl_line}))) {
313335
LineEntry LE(StartAddress, Gsym.insertFile(FilePath), *Line);
@@ -322,7 +344,20 @@ static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
322344
for (uint32_t RowIndex : RowVector) {
323345
// Take file number and line/column from the row.
324346
const DWARFDebugLine::Row &Row = CUI.LineTable->Rows[RowIndex];
325-
const uint32_t FileIdx = CUI.DWARFToGSYMFileIndex(Gsym, Row.File);
347+
std::optional<uint32_t> OptFileIdx =
348+
CUI.DWARFToGSYMFileIndex(Gsym, Row.File);
349+
if (!OptFileIdx) {
350+
if (Log) {
351+
*Log << "error: function DIE at " << HEX32(Die.getOffset()) << " has "
352+
<< "a line entry with invalid DWARF file index, this entry will "
353+
<< "be removed:\n";
354+
Row.dumpTableHeader(*Log, /*Indent=*/0);
355+
Row.dump(*Log);
356+
*Log << "\n";
357+
}
358+
continue;
359+
}
360+
const uint32_t FileIdx = OptFileIdx.value();
326361
uint64_t RowAddress = Row.Address.Address;
327362
// Watch out for a RowAddress that is in the middle of a line table entry
328363
// in the DWARF. If we pass an address in between two line table entries

0 commit comments

Comments
 (0)