@@ -1447,6 +1447,18 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
14471447        ->sizeOf (Unit.getOrigUnit ().getFormParams ());
14481448  }
14491449
1450+   if  (AttrSpec.Attr  == dwarf::DW_AT_LLVM_stmt_sequence) {
1451+     //  If needed, we'll patch this sec_offset later with the correct offset.
1452+     auto  Patch = Die.addValue (DIEAlloc, dwarf::Attribute (AttrSpec.Attr ),
1453+                               dwarf::DW_FORM_sec_offset,
1454+                               DIEInteger (*Val.getAsSectionOffset ()));
1455+ 
1456+     //  Record this patch location so that it can be fixed up later.
1457+     Unit.noteStmtSeqListAttribute (Patch);
1458+ 
1459+     return  Unit.getOrigUnit ().getFormParams ().getDwarfOffsetByteSize ();
1460+   }
1461+ 
14501462  if  (LLVM_UNLIKELY (Linker.Options .Update )) {
14511463    if  (auto  OptionalValue = Val.getAsUnsignedConstant ())
14521464      Value = *OptionalValue;
@@ -2081,29 +2093,43 @@ void DWARFLinker::DIECloner::emitDebugAddrSection(
20812093  Emitter->emitDwarfDebugAddrsFooter (Unit, EndLabel);
20822094}
20832095
2096+ // / A helper struct to help keep track of the association between the input and
2097+ // / output rows during line table rewriting. This is used to patch
2098+ // / DW_AT_LLVM_stmt_sequence attributes, which reference a particular line table
2099+ // / row.
2100+ struct  TrackedRow  {
2101+   DWARFDebugLine::Row Row;
2102+   size_t  OriginalRowIndex;
2103+   bool  isStartSeqInOutput;
2104+ };
2105+ 
20842106// / Insert the new line info sequence \p Seq into the current
20852107// / set of already linked line info \p Rows.
2086- static  void  insertLineSequence (std::vector<DWARFDebugLine::Row > &Seq,
2087-                                std::vector<DWARFDebugLine::Row > &Rows) {
2108+ static  void  insertLineSequence (std::vector<TrackedRow > &Seq,
2109+                                std::vector<TrackedRow > &Rows) {
20882110  if  (Seq.empty ())
20892111    return ;
20902112
2091-   if  (!Rows.empty () && Rows.back ().Address  < Seq.front ().Address ) {
2113+   //  Mark the first row in Seq to indicate it is the start of a sequence
2114+   //  in the output line table.
2115+   Seq.front ().isStartSeqInOutput  = true ;
2116+ 
2117+   if  (!Rows.empty () && Rows.back ().Row .Address  < Seq.front ().Row .Address ) {
20922118    llvm::append_range (Rows, Seq);
20932119    Seq.clear ();
20942120    return ;
20952121  }
20962122
2097-   object::SectionedAddress Front = Seq.front ().Address ;
2123+   object::SectionedAddress Front = Seq.front ().Row . Address ;
20982124  auto  InsertPoint = partition_point (
2099-       Rows, [=](const  DWARFDebugLine::Row  &O) { return  O.Address  < Front; });
2125+       Rows, [=](const  TrackedRow  &O) { return  O. Row .Address  < Front; });
21002126
21012127  //  FIXME: this only removes the unneeded end_sequence if the
21022128  //  sequences have been inserted in order. Using a global sort like
2103-   //  described in generateLineTableForUnit() and delaying the end_sequene 
2129+   //  described in generateLineTableForUnit() and delaying the end_sequence 
21042130  //  elimination to emitLineTableForUnit() we can get rid of all of them.
2105-   if  (InsertPoint != Rows.end () && InsertPoint->Address  == Front &&
2106-       InsertPoint->EndSequence ) {
2131+   if  (InsertPoint != Rows.end () && InsertPoint->Row . Address  == Front &&
2132+       InsertPoint->Row . EndSequence ) {
21072133    *InsertPoint = Seq.front ();
21082134    Rows.insert (InsertPoint + 1 , Seq.begin () + 1 , Seq.end ());
21092135  } else  {
@@ -2171,75 +2197,144 @@ void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
21712197        LineTable.Rows .clear ();
21722198
21732199      LineTable.Sequences  = LT->Sequences ;
2200+ 
2201+       Emitter->emitLineTableForUnit (LineTable, Unit, DebugStrPool,
2202+                                     DebugLineStrPool);
21742203    } else  {
2175-       //  This vector is the output line table.
2176-       std::vector<DWARFDebugLine::Row> NewRows;
2177-       NewRows.reserve (LT->Rows .size ());
2204+       //  Create TrackedRow objects for all input rows.
2205+       std::vector<TrackedRow> InputRows;
2206+       InputRows.reserve (LT->Rows .size ());
2207+       for  (size_t  i = 0 ; i < LT->Rows .size (); i++)
2208+         InputRows.emplace_back (TrackedRow{LT->Rows [i], i, false });
2209+ 
2210+       //  This vector is the output line table (still in TrackedRow form).
2211+       std::vector<TrackedRow> OutputRows;
2212+       OutputRows.reserve (InputRows.size ());
21782213
21792214      //  Current sequence of rows being extracted, before being inserted
2180-       //  in NewRows.
2181-       std::vector<DWARFDebugLine::Row> Seq;
2215+       //  in OutputRows.
2216+       std::vector<TrackedRow> Seq;
2217+       Seq.reserve (InputRows.size ());
21822218
21832219      const  auto  &FunctionRanges = Unit.getFunctionRanges ();
21842220      std::optional<AddressRangeValuePair> CurrRange;
21852221
21862222      //  FIXME: This logic is meant to generate exactly the same output as
21872223      //  Darwin's classic dsymutil. There is a nicer way to implement this
2188-       //  by simply putting all the relocated line info in NewRows  and simply
2189-       //  sorting NewRows  before passing it to emitLineTableForUnit. This
2224+       //  by simply putting all the relocated line info in OutputRows  and simply
2225+       //  sorting OutputRows  before passing it to emitLineTableForUnit. This
21902226      //  should be correct as sequences for a function should stay
21912227      //  together in the sorted output. There are a few corner cases that
21922228      //  look suspicious though, and that required to implement the logic
21932229      //  this way. Revisit that once initial validation is finished.
21942230
21952231      //  Iterate over the object file line info and extract the sequences
21962232      //  that correspond to linked functions.
2197-       for  (DWARFDebugLine::Row Row : LT->Rows ) {
2233+       for  (size_t  i = 0 ; i < InputRows.size (); i++) {
2234+         TrackedRow TR = InputRows[i];
2235+ 
21982236        //  Check whether we stepped out of the range. The range is
2199-         //  half-open, but consider accept  the end address of the range if
2237+         //  half-open, but consider accepting  the end address of the range if
22002238        //  it is marked as end_sequence in the input (because in that
22012239        //  case, the relocation offset is accurate and that entry won't
22022240        //  serve as the start of another function).
2203-         if  (!CurrRange || !CurrRange->Range .contains (Row.Address .Address )) {
2204-           //  We just stepped out of a known range. Insert a  end_sequence
2241+         if  (!CurrRange || !CurrRange->Range .contains (TR. Row .Address .Address )) {
2242+           //  We just stepped out of a known range. Insert an  end_sequence
22052243          //  corresponding to the end of the range.
22062244          uint64_t  StopAddress =
22072245              CurrRange ? CurrRange->Range .end () + CurrRange->Value  : -1ULL ;
2208-           CurrRange = FunctionRanges.getRangeThatContains (Row.Address .Address );
2246+           CurrRange =
2247+               FunctionRanges.getRangeThatContains (TR.Row .Address .Address );
22092248          if  (StopAddress != -1ULL  && !Seq.empty ()) {
22102249            //  Insert end sequence row with the computed end address, but
22112250            //  the same line as the previous one.
22122251            auto  NextLine = Seq.back ();
2213-             NextLine.Address .Address  = StopAddress;
2214-             NextLine.EndSequence  = 1 ;
2215-             NextLine.PrologueEnd  = 0 ;
2216-             NextLine.BasicBlock  = 0 ;
2217-             NextLine.EpilogueBegin  = 0 ;
2252+             NextLine.Row . Address .Address  = StopAddress;
2253+             NextLine.Row . EndSequence  = 1 ;
2254+             NextLine.Row . PrologueEnd  = 0 ;
2255+             NextLine.Row . BasicBlock  = 0 ;
2256+             NextLine.Row . EpilogueBegin  = 0 ;
22182257            Seq.push_back (NextLine);
2219-             insertLineSequence (Seq, NewRows );
2258+             insertLineSequence (Seq, OutputRows );
22202259          }
22212260
22222261          if  (!CurrRange)
22232262            continue ;
22242263        }
22252264
22262265        //  Ignore empty sequences.
2227-         if  (Row.EndSequence  && Seq.empty ())
2266+         if  (TR. Row .EndSequence  && Seq.empty ())
22282267          continue ;
22292268
22302269        //  Relocate row address and add it to the current sequence.
2231-         Row.Address .Address  += CurrRange->Value ;
2232-         Seq.emplace_back (Row );
2270+         TR. Row .Address .Address  += CurrRange->Value ;
2271+         Seq.push_back (TR );
22332272
2234-         if  (Row.EndSequence )
2235-           insertLineSequence (Seq, NewRows );
2273+         if  (TR. Row .EndSequence )
2274+           insertLineSequence (Seq, OutputRows );
22362275      }
22372276
2238-       LineTable.Rows  = std::move (NewRows);
2277+       //  Materialize the tracked rows into final DWARFDebugLine::Row objects.
2278+       LineTable.Rows .clear ();
2279+       LineTable.Rows .reserve (OutputRows.size ());
2280+       for  (auto  &TR : OutputRows)
2281+         LineTable.Rows .push_back (TR.Row );
2282+ 
2283+       //  Use OutputRowOffsets to store the offsets of each line table row in the
2284+       //  output .debug_line section.
2285+       std::vector<uint64_t > OutputRowOffsets;
2286+ 
2287+       //  The unit might not have any DW_AT_LLVM_stmt_sequence attributes, so use
2288+       //  hasStmtSeq to skip the patching logic.
2289+       bool  hasStmtSeq = Unit.getStmtSeqListAttributes ().size () > 0 ;
2290+       Emitter->emitLineTableForUnit (LineTable, Unit, DebugStrPool,
2291+                                     DebugLineStrPool,
2292+                                     hasStmtSeq ? &OutputRowOffsets : nullptr );
2293+ 
2294+       if  (hasStmtSeq) {
2295+         assert (OutputRowOffsets.size () == OutputRows.size () &&
2296+                " must have an offset for each row" 
2297+ 
2298+         //  Create a map of stmt sequence offsets to original row indices.
2299+         DenseMap<uint64_t , unsigned > SeqOffToOrigRow;
2300+         for  (const  DWARFDebugLine::Sequence &Seq : LT->Sequences )
2301+           SeqOffToOrigRow[Seq.StmtSeqOffset ] = Seq.FirstRowIndex ;
2302+ 
2303+         //  Create a map of original row indices to new row indices.
2304+         DenseMap<size_t , size_t > OrigRowToNewRow;
2305+         for  (size_t  i = 0 ; i < OutputRows.size (); ++i)
2306+           OrigRowToNewRow[OutputRows[i].OriginalRowIndex ] = i;
2307+ 
2308+         //  Patch DW_AT_LLVM_stmt_sequence attributes in the compile unit DIE
2309+         //  with the correct offset into the .debug_line section.
2310+         for  (const  auto  &StmtSeq : Unit.getStmtSeqListAttributes ()) {
2311+           uint64_t  OrigStmtSeq = StmtSeq.get ();
2312+           //  1. Get the original row index from the stmt list offset.
2313+           auto  OrigRowIter = SeqOffToOrigRow.find (OrigStmtSeq);
2314+           assert (OrigRowIter != SeqOffToOrigRow.end () &&
2315+                  " Stmt list offset not found in sequence offsets map" 
2316+           size_t  OrigRowIndex = OrigRowIter->second ;
2317+ 
2318+           //  2. Get the new row index from the original row index.
2319+           auto  NewRowIter = OrigRowToNewRow.find (OrigRowIndex);
2320+           if  (NewRowIter == OrigRowToNewRow.end ()) {
2321+             //  If the original row index is not found in the map, update the
2322+             //  stmt_sequence attribute to the 'invalid offset' magic value.
2323+             StmtSeq.set (UINT64_MAX);
2324+             continue ;
2325+           }
2326+ 
2327+           //  3. Get the offset of the new row in the output .debug_line section.
2328+           assert (NewRowIter->second  < OutputRowOffsets.size () &&
2329+                  " New row index out of bounds" 
2330+           uint64_t  NewStmtSeqOffset = OutputRowOffsets[NewRowIter->second ];
2331+ 
2332+           //  4. Patch the stmt_list attribute with the new offset.
2333+           StmtSeq.set (NewStmtSeqOffset);
2334+         }
2335+       }
22392336    }
22402337
2241-     Emitter->emitLineTableForUnit (LineTable, Unit, DebugStrPool,
2242-                                   DebugLineStrPool);
22432338  } else 
22442339    Linker.reportWarning (" Cann't load line table." 
22452340}
0 commit comments