Skip to content

Commit 62886c9

Browse files
committed
Modify llvm-gsymutil to ignore invalid file indexes
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 62886c9

File tree

2 files changed

+405
-14
lines changed

2 files changed

+405
-14
lines changed

llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp

Lines changed: 49 additions & 14 deletions
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)