@@ -413,6 +413,116 @@ static bool isTlsAddressCode(uint8_t DW_OP_Code) {
413413 DW_OP_Code == dwarf::DW_OP_GNU_push_tls_address;
414414}
415415
416+ static void constructSeqOffsettoOrigRowMapping (
417+ CompileUnit &Unit, const DWARFDebugLine::LineTable <,
418+ DenseMap<size_t , unsigned > &SeqOffToOrigRow) {
419+
420+ // Use std::map for ordered iteration.
421+ std::map<uint64_t , unsigned > LineTableMapping;
422+
423+ // First, trust the sequences that the DWARF parser did identify.
424+ for (const DWARFDebugLine::Sequence &Seq : LT.Sequences )
425+ LineTableMapping[Seq.StmtSeqOffset ] = Seq.FirstRowIndex ;
426+
427+ // Second, manually find sequence boundaries and match them to the
428+ // sorted attributes to handle sequences the parser might have missed.
429+ auto StmtAttrs = Unit.getStmtSeqListAttributes ();
430+ llvm::sort (StmtAttrs, [](const PatchLocation &A, const PatchLocation &B) {
431+ return A.get () < B.get ();
432+ });
433+
434+ std::vector<size_t > SeqStartRows;
435+ SeqStartRows.push_back (0 );
436+ for (auto [I, Row] : llvm::enumerate (ArrayRef (LT.Rows ).drop_back ()))
437+ if (Row.EndSequence )
438+ SeqStartRows.push_back (I + 1 );
439+
440+ // While SeqOffToOrigRow parsed from CU could be the ground truth,
441+ // e.g.
442+ //
443+ // SeqOff Row
444+ // 0x08 9
445+ // 0x14 15
446+ //
447+ // The StmtAttrs and SeqStartRows may not match perfectly, e.g.
448+ //
449+ // StmtAttrs SeqStartRows
450+ // 0x04 3
451+ // 0x08 5
452+ // 0x10 9
453+ // 0x12 11
454+ // 0x14 15
455+ //
456+ // In this case, we don't want to assign 5 to 0x08, since we know 0x08
457+ // maps to 9. If we do a dummy 1:1 mapping 0x10 will be mapped to 9
458+ // which is incorrect. The expected behavior is ignore 5, realign the
459+ // table based on the result from the line table:
460+ //
461+ // StmtAttrs SeqStartRows
462+ // 0x04 3
463+ // -- 5
464+ // 0x08 9 <- LineTableMapping ground truth
465+ // 0x10 11
466+ // 0x12 --
467+ // 0x14 15 <- LineTableMapping ground truth
468+
469+ ArrayRef StmtAttrsRef (StmtAttrs);
470+ ArrayRef SeqStartRowsRef (SeqStartRows);
471+
472+ // Dummy last element to make sure StmtAttrsRef and SeqStartRowsRef always
473+ // run out first.
474+ constexpr size_t DummyKey = UINT64_MAX;
475+ constexpr unsigned DummyVal = UINT32_MAX;
476+ LineTableMapping[DummyKey] = DummyVal;
477+
478+ for (auto [NextSeqOff, NextRow] : LineTableMapping) {
479+ auto StmtAttrSmallerThanNext = [NextSeqOff](const PatchLocation &SA) {
480+ return SA.get () < NextSeqOff;
481+ };
482+ auto SeqStartSmallerThanNext = [NextRow](const size_t &Row) {
483+ return Row < NextRow;
484+ };
485+
486+ // If both StmtAttrs and SeqStartRows points to value not in
487+ // the LineTableMapping yet, we do a dummy one to one mapping and
488+ // move the pointer.
489+ while (!StmtAttrsRef.empty () && !SeqStartRowsRef.empty () &&
490+ StmtAttrSmallerThanNext (StmtAttrsRef.front ()) &&
491+ SeqStartSmallerThanNext (SeqStartRowsRef.front ())) {
492+ SeqOffToOrigRow[StmtAttrsRef.consume_front ().get ()] =
493+ SeqStartRowsRef.consume_front ();
494+ }
495+ // One of the pointer points to the value at or past Next in the
496+ // LineTableMapping, We move the pointer to re-align with the
497+ // LineTableMapping
498+ StmtAttrsRef = StmtAttrsRef.drop_while (StmtAttrSmallerThanNext);
499+ SeqStartRowsRef = SeqStartRowsRef.drop_while (SeqStartSmallerThanNext);
500+ // Use the LineTableMapping's result as the ground truth and move
501+ // on.
502+ if (NextSeqOff != DummyKey) {
503+ SeqOffToOrigRow[NextSeqOff] = NextRow;
504+ }
505+ // Move the pointers if they are pointed at Next.
506+ // It is possible that they point to later entries in LineTableMapping.
507+ // Therefore we only increment the pointers after we validate they are
508+ // pointing to the `Next` entry. e.g.
509+ //
510+ // LineTableMapping
511+ // SeqOff Row
512+ // 0x08 9 <- NextSeqOff/NextRow
513+ // 0x14 15
514+ //
515+ // StmtAttrs SeqStartRows
516+ // 0x14 13 <- StmtAttrsRef.front() / SeqStartRowsRef.front()
517+ // 0x16 15
518+ // -- 17
519+ if (!StmtAttrsRef.empty () && StmtAttrsRef.front ().get () == NextSeqOff)
520+ StmtAttrsRef.consume_front ();
521+ if (!SeqStartRowsRef.empty () && SeqStartRowsRef.front () == NextRow)
522+ SeqStartRowsRef.consume_front ();
523+ }
524+ }
525+
416526std::pair<bool , std::optional<int64_t >>
417527DWARFLinker::getVariableRelocAdjustment (AddressesMap &RelocMgr,
418528 const DWARFDie &DIE) {
@@ -2297,8 +2407,12 @@ void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
22972407
22982408 // Create a map of stmt sequence offsets to original row indices.
22992409 DenseMap<uint64_t , unsigned > SeqOffToOrigRow;
2300- for (const DWARFDebugLine::Sequence &Seq : LT->Sequences )
2301- SeqOffToOrigRow[Seq.StmtSeqOffset ] = Seq.FirstRowIndex ;
2410+ // The DWARF parser's discovery of sequences can be incomplete. To
2411+ // ensure all DW_AT_LLVM_stmt_sequence attributes can be patched, we
2412+ // build a map from both the parser's results and a manual
2413+ // reconstruction.
2414+ if (!LT->Rows .empty ())
2415+ constructSeqOffsettoOrigRowMapping (Unit, *LT, SeqOffToOrigRow);
23022416
23032417 // Create a map of original row indices to new row indices.
23042418 DenseMap<size_t , size_t > OrigRowToNewRow;
0 commit comments