@@ -1447,6 +1447,18 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
1447
1447
->sizeOf (Unit.getOrigUnit ().getFormParams ());
1448
1448
}
1449
1449
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
+
1450
1462
if (LLVM_UNLIKELY (Linker.Options .Update )) {
1451
1463
if (auto OptionalValue = Val.getAsUnsignedConstant ())
1452
1464
Value = *OptionalValue;
@@ -2081,29 +2093,43 @@ void DWARFLinker::DIECloner::emitDebugAddrSection(
2081
2093
Emitter->emitDwarfDebugAddrsFooter (Unit, EndLabel);
2082
2094
}
2083
2095
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
+
2084
2106
// / Insert the new line info sequence \p Seq into the current
2085
2107
// / 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) {
2088
2110
if (Seq.empty ())
2089
2111
return ;
2090
2112
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 ) {
2092
2118
llvm::append_range (Rows, Seq);
2093
2119
Seq.clear ();
2094
2120
return ;
2095
2121
}
2096
2122
2097
- object::SectionedAddress Front = Seq.front ().Address ;
2123
+ object::SectionedAddress Front = Seq.front ().Row . Address ;
2098
2124
auto InsertPoint = partition_point (
2099
- Rows, [=](const DWARFDebugLine::Row &O) { return O.Address < Front; });
2125
+ Rows, [=](const TrackedRow &O) { return O. Row .Address < Front; });
2100
2126
2101
2127
// FIXME: this only removes the unneeded end_sequence if the
2102
2128
// 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
2104
2130
// 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 ) {
2107
2133
*InsertPoint = Seq.front ();
2108
2134
Rows.insert (InsertPoint + 1 , Seq.begin () + 1 , Seq.end ());
2109
2135
} else {
@@ -2171,75 +2197,144 @@ void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
2171
2197
LineTable.Rows .clear ();
2172
2198
2173
2199
LineTable.Sequences = LT->Sequences ;
2200
+
2201
+ Emitter->emitLineTableForUnit (LineTable, Unit, DebugStrPool,
2202
+ DebugLineStrPool);
2174
2203
} 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 ());
2178
2213
2179
2214
// 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 ());
2182
2218
2183
2219
const auto &FunctionRanges = Unit.getFunctionRanges ();
2184
2220
std::optional<AddressRangeValuePair> CurrRange;
2185
2221
2186
2222
// FIXME: This logic is meant to generate exactly the same output as
2187
2223
// 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
2190
2226
// should be correct as sequences for a function should stay
2191
2227
// together in the sorted output. There are a few corner cases that
2192
2228
// look suspicious though, and that required to implement the logic
2193
2229
// this way. Revisit that once initial validation is finished.
2194
2230
2195
2231
// Iterate over the object file line info and extract the sequences
2196
2232
// 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
+
2198
2236
// 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
2200
2238
// it is marked as end_sequence in the input (because in that
2201
2239
// case, the relocation offset is accurate and that entry won't
2202
2240
// 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
2205
2243
// corresponding to the end of the range.
2206
2244
uint64_t StopAddress =
2207
2245
CurrRange ? CurrRange->Range .end () + CurrRange->Value : -1ULL ;
2208
- CurrRange = FunctionRanges.getRangeThatContains (Row.Address .Address );
2246
+ CurrRange =
2247
+ FunctionRanges.getRangeThatContains (TR.Row .Address .Address );
2209
2248
if (StopAddress != -1ULL && !Seq.empty ()) {
2210
2249
// Insert end sequence row with the computed end address, but
2211
2250
// the same line as the previous one.
2212
2251
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 ;
2218
2257
Seq.push_back (NextLine);
2219
- insertLineSequence (Seq, NewRows );
2258
+ insertLineSequence (Seq, OutputRows );
2220
2259
}
2221
2260
2222
2261
if (!CurrRange)
2223
2262
continue ;
2224
2263
}
2225
2264
2226
2265
// Ignore empty sequences.
2227
- if (Row.EndSequence && Seq.empty ())
2266
+ if (TR. Row .EndSequence && Seq.empty ())
2228
2267
continue ;
2229
2268
2230
2269
// 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 );
2233
2272
2234
- if (Row.EndSequence )
2235
- insertLineSequence (Seq, NewRows );
2273
+ if (TR. Row .EndSequence )
2274
+ insertLineSequence (Seq, OutputRows );
2236
2275
}
2237
2276
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
+ }
2239
2336
}
2240
2337
2241
- Emitter->emitLineTableForUnit (LineTable, Unit, DebugStrPool,
2242
- DebugLineStrPool);
2243
2338
} else
2244
2339
Linker.reportWarning (" Cann't load line table." , ObjFile);
2245
2340
}
0 commit comments