1//=== DIEAttributeCloner.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DIEAttributeCloner.h"
10#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
11
12using namespace llvm;
13using namespace dwarf_linker;
14using namespace dwarf_linker::parallel;
15
16void DIEAttributeCloner::clone() {
17 // Extract and clone every attribute.
18 DWARFDataExtractor Data = InUnit.getOrigUnit().getDebugInfoExtractor();
19
20 uint64_t Offset = InputDieEntry->getOffset();
21 // Point to the next DIE (generally there is always at least a NULL
22 // entry after the current one). If this is a lone
23 // DW_TAG_compile_unit without any children, point to the next unit.
24 uint64_t NextOffset = (InputDIEIdx + 1 < InUnit.getOrigUnit().getNumDIEs())
25 ? InUnit.getDIEAtIndex(Index: InputDIEIdx + 1).getOffset()
26 : InUnit.getOrigUnit().getNextUnitOffset();
27
28 // We could copy the data only if we need to apply a relocation to it. After
29 // testing, it seems there is no performance downside to doing the copy
30 // unconditionally, and it makes the code simpler.
31 SmallString<40> DIECopy(Data.getData().substr(Start: Offset, N: NextOffset - Offset));
32 Data =
33 DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
34
35 // Modify the copy with relocated addresses.
36 InUnit.getContainingFile().Addresses->applyValidRelocs(Data: DIECopy, BaseOffset: Offset,
37 IsLittleEndian: Data.isLittleEndian());
38
39 // Reset the Offset to 0 as we will be working on the local copy of
40 // the data.
41 Offset = 0;
42
43 const auto *Abbrev = InputDieEntry->getAbbreviationDeclarationPtr();
44 Offset += getULEB128Size(Value: Abbrev->getCode());
45
46 // Set current output offset.
47 AttrOutOffset = OutUnit.isCompileUnit() ? OutDIE->getOffset() : 0;
48 for (const auto &AttrSpec : Abbrev->attributes()) {
49 // Check whether current attribute should be skipped.
50 if (shouldSkipAttribute(AttrSpec)) {
51 DWARFFormValue::skipValue(Form: AttrSpec.Form, DebugInfoData: Data, OffsetPtr: &Offset,
52 FormParams: InUnit.getFormParams());
53 continue;
54 }
55
56 DWARFFormValue Val = AttrSpec.getFormValue();
57 Val.extractValue(Data, OffsetPtr: &Offset, FormParams: InUnit.getFormParams(),
58 U: &InUnit.getOrigUnit());
59
60 // Clone current attribute.
61 switch (AttrSpec.Form) {
62 case dwarf::DW_FORM_strp:
63 case dwarf::DW_FORM_line_strp:
64 case dwarf::DW_FORM_string:
65 case dwarf::DW_FORM_strx:
66 case dwarf::DW_FORM_strx1:
67 case dwarf::DW_FORM_strx2:
68 case dwarf::DW_FORM_strx3:
69 case dwarf::DW_FORM_strx4:
70 AttrOutOffset += cloneStringAttr(Val, AttrSpec);
71 break;
72 case dwarf::DW_FORM_ref_addr:
73 case dwarf::DW_FORM_ref1:
74 case dwarf::DW_FORM_ref2:
75 case dwarf::DW_FORM_ref4:
76 case dwarf::DW_FORM_ref8:
77 case dwarf::DW_FORM_ref_udata:
78 AttrOutOffset += cloneDieRefAttr(Val, AttrSpec);
79 break;
80 case dwarf::DW_FORM_data1:
81 case dwarf::DW_FORM_data2:
82 case dwarf::DW_FORM_data4:
83 case dwarf::DW_FORM_data8:
84 case dwarf::DW_FORM_udata:
85 case dwarf::DW_FORM_sdata:
86 case dwarf::DW_FORM_sec_offset:
87 case dwarf::DW_FORM_flag:
88 case dwarf::DW_FORM_flag_present:
89 case dwarf::DW_FORM_rnglistx:
90 case dwarf::DW_FORM_loclistx:
91 case dwarf::DW_FORM_implicit_const:
92 AttrOutOffset += cloneScalarAttr(Val, AttrSpec);
93 break;
94 case dwarf::DW_FORM_block:
95 case dwarf::DW_FORM_block1:
96 case dwarf::DW_FORM_block2:
97 case dwarf::DW_FORM_block4:
98 case dwarf::DW_FORM_exprloc:
99 AttrOutOffset += cloneBlockAttr(Val, AttrSpec);
100 break;
101 case dwarf::DW_FORM_addr:
102 case dwarf::DW_FORM_addrx:
103 case dwarf::DW_FORM_addrx1:
104 case dwarf::DW_FORM_addrx2:
105 case dwarf::DW_FORM_addrx3:
106 case dwarf::DW_FORM_addrx4:
107 AttrOutOffset += cloneAddressAttr(Val, AttrSpec);
108 break;
109 default:
110 InUnit.warn(Warning: "unsupported attribute form " +
111 dwarf::FormEncodingString(Encoding: AttrSpec.Form) +
112 " in DieAttributeCloner::clone(). Dropping.",
113 DieEntry: InputDieEntry);
114 }
115 }
116
117 // We convert source strings into the indexed form for DWARFv5.
118 // Check if original unit already has DW_AT_str_offsets_base
119 // attribute.
120 if (InputDIEIdx == 0 && InUnit.getVersion() >= 5 &&
121 !AttrInfo.HasStringOffsetBaseAttr && OutUnit.isCompileUnit()) {
122 DebugInfoOutputSection.notePatchWithOffsetUpdate(
123 Patch: DebugOffsetPatch{AttrOutOffset,
124 &OutUnit->getOrCreateSectionDescriptor(
125 SectionKind: DebugSectionKind::DebugStrOffsets),
126 true},
127 PatchesOffsetsList&: PatchesOffsets);
128
129 AttrOutOffset +=
130 Generator
131 .addScalarAttribute(Attr: dwarf::DW_AT_str_offsets_base,
132 AttrForm: dwarf::DW_FORM_sec_offset,
133 Value: OutUnit->getDebugStrOffsetsHeaderSize())
134 .second;
135 }
136
137 // No DW_AT_addr_base: add one for the addrx-indexed entries. Except in
138 // update mode, where HasAddrBaseAttr is never set.
139 if (InputDIEIdx == 0 && InUnit.getVersion() >= 5 &&
140 !AttrInfo.HasAddrBaseAttr &&
141 !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) {
142 DebugInfoOutputSection.notePatchWithOffsetUpdate(
143 Patch: DebugOffsetPatch{
144 AttrOutOffset,
145 &OutUnit->getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugAddr),
146 true},
147 PatchesOffsetsList&: PatchesOffsets);
148
149 AttrOutOffset += Generator
150 .addScalarAttribute(Attr: dwarf::DW_AT_addr_base,
151 AttrForm: dwarf::DW_FORM_sec_offset,
152 Value: OutUnit->getDebugAddrHeaderSize())
153 .second;
154 }
155}
156
157bool DIEAttributeCloner::shouldSkipAttribute(
158 DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) {
159 switch (AttrSpec.Attr) {
160 default:
161 return false;
162 case dwarf::DW_AT_low_pc:
163 case dwarf::DW_AT_high_pc:
164 case dwarf::DW_AT_ranges:
165 if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
166 return false;
167
168 // Skip address attribute if we are in function scope and function does not
169 // reference live address.
170 return InUnit.getDIEInfo(Idx: InputDIEIdx).getIsInFunctionScope() &&
171 !FuncAddressAdjustment.has_value();
172 case dwarf::DW_AT_rnglists_base:
173 // In case !Update the .debug_addr table is not generated/preserved.
174 // Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used.
175 // Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the
176 // DW_AT_rnglists_base is removed.
177 return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
178 case dwarf::DW_AT_loclists_base:
179 // In case !Update the .debug_addr table is not generated/preserved.
180 // Thus instead of DW_FORM_loclistx the DW_FORM_sec_offset is used.
181 // Since DW_AT_loclists_base is used for only DW_FORM_loclistx the
182 // DW_AT_loclists_base is removed.
183 return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
184 case dwarf::DW_AT_location:
185 case dwarf::DW_AT_frame_base:
186 if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
187 return false;
188
189 // When location expression contains an address: skip this attribute
190 // if it does not reference live address.
191 if (HasLocationExpressionAddress)
192 return !VarAddressAdjustment.has_value();
193
194 // Skip location attribute if we are in function scope and function does not
195 // reference live address.
196 return InUnit.getDIEInfo(Idx: InputDIEIdx).getIsInFunctionScope() &&
197 !FuncAddressAdjustment.has_value();
198 }
199}
200
201size_t DIEAttributeCloner::cloneStringAttr(
202 const DWARFFormValue &Val,
203 const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
204 std::optional<const char *> String = dwarf::toString(V: Val);
205 if (!String) {
206 InUnit.warn(Warning: "cann't read string attribute.");
207 return 0;
208 }
209
210 StringEntry *StringInPool =
211 InUnit.getGlobalData().getStringPool().insert(NewValue: *String).first;
212
213 // Update attributes info.
214 if (AttrSpec.Attr == dwarf::DW_AT_name)
215 AttrInfo.Name = StringInPool;
216 else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
217 AttrSpec.Attr == dwarf::DW_AT_linkage_name)
218 AttrInfo.MangledName = StringInPool;
219
220 if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
221 if (OutUnit.isTypeUnit()) {
222 DebugInfoOutputSection.notePatch(Patch: DebugTypeLineStrPatch{
223 AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(Idx: InputDIEIdx),
224 StringInPool});
225 } else {
226 DebugInfoOutputSection.notePatchWithOffsetUpdate(
227 Patch: DebugLineStrPatch{{.PatchOffset: AttrOutOffset}, .String: StringInPool}, PatchesOffsetsList&: PatchesOffsets);
228 }
229 return Generator
230 .addStringPlaceholderAttribute(Attr: AttrSpec.Attr, AttrForm: dwarf::DW_FORM_line_strp)
231 .second;
232 }
233
234 if (Use_DW_FORM_strp) {
235 if (OutUnit.isTypeUnit()) {
236 DebugInfoOutputSection.notePatch(
237 Patch: DebugTypeStrPatch{AttrOutOffset, OutDIE,
238 InUnit.getDieTypeEntry(Idx: InputDIEIdx), StringInPool});
239 } else {
240 DebugInfoOutputSection.notePatchWithOffsetUpdate(
241 Patch: DebugStrPatch{{.PatchOffset: AttrOutOffset}, .String: StringInPool}, PatchesOffsetsList&: PatchesOffsets);
242 }
243
244 return Generator
245 .addStringPlaceholderAttribute(Attr: AttrSpec.Attr, AttrForm: dwarf::DW_FORM_strp)
246 .second;
247 }
248
249 return Generator
250 .addIndexedStringAttribute(Attr: AttrSpec.Attr, AttrForm: dwarf::DW_FORM_strx,
251 Idx: OutUnit->getDebugStrIndex(String: StringInPool))
252 .second;
253}
254
255size_t DIEAttributeCloner::cloneDieRefAttr(
256 const DWARFFormValue &Val,
257 const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
258 if (AttrSpec.Attr == dwarf::DW_AT_sibling)
259 return 0;
260
261 std::optional<UnitEntryPairTy> RefDiePair =
262 InUnit.resolveDIEReference(RefValue: Val, CanResolveInterCUReferences: ResolveInterCUReferencesMode::Resolve);
263 if (!RefDiePair || !RefDiePair->DieEntry) {
264 // If the referenced DIE is not found, drop the attribute.
265 InUnit.warn(Warning: "could not find referenced DIE", DieEntry: InputDieEntry);
266 return 0;
267 }
268
269 TypeEntry *RefTypeName = nullptr;
270 const CompileUnit::DIEInfo &RefDIEInfo =
271 RefDiePair->CU->getDIEInfo(Entry: RefDiePair->DieEntry);
272 if (RefDIEInfo.needToPlaceInTypeTable())
273 RefTypeName = RefDiePair->CU->getDieTypeEntry(InputDieEntry: RefDiePair->DieEntry);
274
275 // The importing unit's DW_TAG_module skeleton can have a different
276 // DW_AT_LLVM_include_path than the unit built from the .pcm and the import
277 // must use the latter. The type pool already merges copies, so a reference
278 // with a type entry resolves correctly. Without one, the module's anchor is
279 // the only link between the two, and it is not known until the unit
280 // describing the module has been emitted.
281 if (RefDiePair->DieEntry->getTag() == dwarf::DW_TAG_module &&
282 AttrSpec.Attr == dwarf::DW_AT_import && !OutUnit.isTypeUnit() &&
283 !RefTypeName) {
284 SmallString<128> Path;
285 if (RefDiePair->CU->getModulePath(DieEntry: RefDiePair->DieEntry, Path)) {
286 ModuleAnchor *Anchor =
287 InUnit.getGlobalData().getModulePool().getOrCreate(Path);
288
289 DebugInfoOutputSection.notePatchWithOffsetUpdate(
290 Patch: DebugDieModuleRefPatch{
291 AttrOutOffset, RefDiePair->CU,
292 RefDiePair->CU->getDIEIndex(Die: RefDiePair->DieEntry), Anchor},
293 PatchesOffsetsList&: PatchesOffsets);
294 return Generator
295 .addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: dwarf::DW_FORM_ref_addr, Value: 0xBADDEF)
296 .second;
297 }
298 }
299
300 if (OutUnit.isTypeUnit()) {
301 assert(RefTypeName && "Type name for referenced DIE is not set");
302 assert(InUnit.getDieTypeEntry(InputDIEIdx) &&
303 "Type name for DIE is not set");
304
305 DebugInfoOutputSection.notePatch(Patch: DebugType2TypeDieRefPatch{
306 AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(Idx: InputDIEIdx),
307 RefTypeName});
308
309 return Generator
310 .addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: dwarf::DW_FORM_ref4, Value: 0xBADDEF)
311 .second;
312 }
313
314 if (RefTypeName) {
315 DebugInfoOutputSection.notePatchWithOffsetUpdate(
316 Patch: DebugDieTypeRefPatch{AttrOutOffset, RefTypeName}, PatchesOffsetsList&: PatchesOffsets);
317
318 return Generator
319 .addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: dwarf::DW_FORM_ref_addr, Value: 0xBADDEF)
320 .second;
321 }
322
323 // Get output offset for referenced DIE.
324 uint64_t OutDieOffset = RefDiePair->CU->getDieOutOffset(InputDieEntry: RefDiePair->DieEntry);
325
326 // Examine whether referenced DIE is in current compile unit.
327 bool IsLocal = OutUnit->getUniqueID() == RefDiePair->CU->getUniqueID();
328
329 // Set attribute form basing on the kind of referenced DIE(local or not?).
330 dwarf::Form NewForm = IsLocal ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref_addr;
331
332 // Check whether current attribute references already cloned DIE inside
333 // the same compilation unit. If true - write the already known offset value.
334 if (IsLocal && (OutDieOffset != 0))
335 return Generator.addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: NewForm, Value: OutDieOffset)
336 .second;
337
338 // If offset value is not known at this point then create patch for the
339 // reference value and write dummy value into the attribute.
340 DebugInfoOutputSection.notePatchWithOffsetUpdate(
341 Patch: DebugDieRefPatch{AttrOutOffset, OutUnit.getAsCompileUnit(),
342 RefDiePair->CU,
343 RefDiePair->CU->getDIEIndex(Die: RefDiePair->DieEntry)},
344 PatchesOffsetsList&: PatchesOffsets);
345 return Generator.addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: NewForm, Value: 0xBADDEF).second;
346}
347
348size_t DIEAttributeCloner::cloneScalarAttr(
349 const DWARFFormValue &Val,
350 const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
351
352 // Create patches for attribute referencing other non invariant section.
353 // Invariant section could not be updated here as this section and
354 // reference to it do not change value in case --update.
355 switch (AttrSpec.Attr) {
356 case dwarf::DW_AT_macro_info: {
357 if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
358 const DWARFDebugMacro *Macro =
359 InUnit.getContainingFile().Dwarf->getDebugMacinfo();
360 if (Macro == nullptr || !Macro->hasEntryForOffset(Offset: *Offset))
361 return 0;
362
363 DebugInfoOutputSection.notePatchWithOffsetUpdate(
364 Patch: DebugOffsetPatch{AttrOutOffset,
365 &OutUnit->getOrCreateSectionDescriptor(
366 SectionKind: DebugSectionKind::DebugMacinfo)},
367 PatchesOffsetsList&: PatchesOffsets);
368 }
369 } break;
370 case dwarf::DW_AT_macros: {
371 if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
372 const DWARFDebugMacro *Macro =
373 InUnit.getContainingFile().Dwarf->getDebugMacro();
374 if (Macro == nullptr || !Macro->hasEntryForOffset(Offset: *Offset))
375 return 0;
376
377 DebugInfoOutputSection.notePatchWithOffsetUpdate(
378 Patch: DebugOffsetPatch{AttrOutOffset,
379 &OutUnit->getOrCreateSectionDescriptor(
380 SectionKind: DebugSectionKind::DebugMacro)},
381 PatchesOffsetsList&: PatchesOffsets);
382 }
383 } break;
384 case dwarf::DW_AT_stmt_list: {
385 DebugInfoOutputSection.notePatchWithOffsetUpdate(
386 Patch: DebugOffsetPatch{AttrOutOffset, &OutUnit->getOrCreateSectionDescriptor(
387 SectionKind: DebugSectionKind::DebugLine)},
388 PatchesOffsetsList&: PatchesOffsets);
389 } break;
390 case dwarf::DW_AT_str_offsets_base: {
391 DebugInfoOutputSection.notePatchWithOffsetUpdate(
392 Patch: DebugOffsetPatch{AttrOutOffset,
393 &OutUnit->getOrCreateSectionDescriptor(
394 SectionKind: DebugSectionKind::DebugStrOffsets),
395 true},
396 PatchesOffsetsList&: PatchesOffsets);
397
398 // Use size of .debug_str_offsets header as attribute value. The offset
399 // to .debug_str_offsets would be added later while patching.
400 AttrInfo.HasStringOffsetBaseAttr = true;
401 return Generator
402 .addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: AttrSpec.Form,
403 Value: OutUnit->getDebugStrOffsetsHeaderSize())
404 .second;
405 } break;
406 case dwarf::DW_AT_decl_file: {
407 // Value of DW_AT_decl_file may exceed original form. Longer
408 // form can affect offsets to the following attributes. To not
409 // update offsets of the following attributes we always remove
410 // original DW_AT_decl_file and attach it to the last position
411 // later.
412 if (OutUnit.isTypeUnit()) {
413 if (std::optional<std::pair<StringRef, StringRef>> DirAndFilename =
414 InUnit.getDirAndFilenameFromLineTable(FileIdxValue: Val))
415 DebugInfoOutputSection.notePatch(Patch: DebugTypeDeclFilePatch{
416 OutDIE,
417 InUnit.getDieTypeEntry(Idx: InputDIEIdx),
418 OutUnit->getGlobalData()
419 .getStringPool()
420 .insert(NewValue: DirAndFilename->first)
421 .first,
422 OutUnit->getGlobalData()
423 .getStringPool()
424 .insert(NewValue: DirAndFilename->second)
425 .first,
426 });
427 return 0;
428 }
429 } break;
430 default: {
431 } break;
432 };
433
434 uint64_t Value;
435 if (AttrSpec.Attr == dwarf::DW_AT_const_value &&
436 (InputDieEntry->getTag() == dwarf::DW_TAG_variable ||
437 InputDieEntry->getTag() == dwarf::DW_TAG_constant))
438 AttrInfo.HasLiveAddress = true;
439
440 if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) {
441 if (auto OptionalValue = Val.getAsUnsignedConstant())
442 Value = *OptionalValue;
443 else if (auto OptionalValue = Val.getAsSignedConstant())
444 Value = *OptionalValue;
445 else if (auto OptionalValue = Val.getAsSectionOffset())
446 Value = *OptionalValue;
447 else {
448 InUnit.warn(Warning: "unsupported scalar attribute form. Dropping attribute.",
449 DieEntry: InputDieEntry);
450 return 0;
451 }
452
453 if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
454 AttrInfo.IsDeclaration = true;
455
456 if (AttrSpec.Form == dwarf::DW_FORM_loclistx)
457 return Generator.addLocListAttribute(Attr: AttrSpec.Attr, AttrForm: AttrSpec.Form, Value)
458 .second;
459
460 return Generator.addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: AttrSpec.Form, Value)
461 .second;
462 }
463
464 dwarf::Form ResultingForm = AttrSpec.Form;
465 if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) {
466 // DWARFLinker does not generate .debug_addr table. Thus we need to change
467 // all "addrx" related forms to "addr" version. Change DW_FORM_rnglistx
468 // to DW_FORM_sec_offset here.
469 std::optional<uint64_t> Index = Val.getAsSectionOffset();
470 if (!Index) {
471 InUnit.warn(Warning: "cann't read the attribute. Dropping.", DieEntry: InputDieEntry);
472 return 0;
473 }
474 std::optional<uint64_t> Offset =
475 InUnit.getOrigUnit().getRnglistOffset(Index: *Index);
476 if (!Offset) {
477 InUnit.warn(Warning: "cann't read the attribute. Dropping.", DieEntry: InputDieEntry);
478 return 0;
479 }
480
481 Value = *Offset;
482 ResultingForm = dwarf::DW_FORM_sec_offset;
483 } else if (AttrSpec.Form == dwarf::DW_FORM_loclistx) {
484 // DWARFLinker does not generate .debug_addr table. Thus we need to change
485 // all "addrx" related forms to "addr" version. Change DW_FORM_loclistx
486 // to DW_FORM_sec_offset here.
487 std::optional<uint64_t> Index = Val.getAsSectionOffset();
488 if (!Index) {
489 InUnit.warn(Warning: "cann't read the attribute. Dropping.", DieEntry: InputDieEntry);
490 return 0;
491 }
492 std::optional<uint64_t> Offset =
493 InUnit.getOrigUnit().getLoclistOffset(Index: *Index);
494 if (!Offset) {
495 InUnit.warn(Warning: "cann't read the attribute. Dropping.", DieEntry: InputDieEntry);
496 return 0;
497 }
498
499 Value = *Offset;
500 ResultingForm = dwarf::DW_FORM_sec_offset;
501 } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
502 InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
503 if (!OutUnit.isCompileUnit())
504 return 0;
505
506 std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc();
507 if (!LowPC)
508 return 0;
509 // Dwarf >= 4 high_pc is an size, not an address.
510 Value = OutUnit.getAsCompileUnit()->getHighPc() - *LowPC;
511 } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
512 Value = *Val.getAsSectionOffset();
513 else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
514 Value = *Val.getAsSignedConstant();
515 else if (auto OptionalValue = Val.getAsUnsignedConstant())
516 Value = *OptionalValue;
517 else {
518 InUnit.warn(Warning: "unsupported scalar attribute form. Dropping attribute.",
519 DieEntry: InputDieEntry);
520 return 0;
521 }
522
523 if (AttrSpec.Attr == dwarf::DW_AT_ranges ||
524 AttrSpec.Attr == dwarf::DW_AT_start_scope) {
525 // Create patch for the range offset value.
526 DebugInfoOutputSection.notePatchWithOffsetUpdate(
527 Patch: DebugRangePatch{{.PatchOffset: AttrOutOffset},
528 .IsCompileUnitRanges: InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit},
529 PatchesOffsetsList&: PatchesOffsets);
530 AttrInfo.HasRanges = true;
531 } else if (DWARFAttribute::mayHaveLocationList(Attr: AttrSpec.Attr) &&
532 dwarf::doesFormBelongToClass(Form: AttrSpec.Form,
533 FC: DWARFFormValue::FC_SectionOffset,
534 DwarfVersion: InUnit.getOrigUnit().getVersion())) {
535 int64_t AddrAdjustmentValue = 0;
536 if (VarAddressAdjustment)
537 AddrAdjustmentValue = *VarAddressAdjustment;
538 else if (FuncAddressAdjustment)
539 AddrAdjustmentValue = *FuncAddressAdjustment;
540
541 // Create patch for the location offset value.
542 DebugInfoOutputSection.notePatchWithOffsetUpdate(
543 Patch: DebugLocPatch{{.PatchOffset: AttrOutOffset}, .AddrAdjustmentValue: AddrAdjustmentValue}, PatchesOffsetsList&: PatchesOffsets);
544 } else if (AttrSpec.Attr == dwarf::DW_AT_addr_base) {
545 DebugInfoOutputSection.notePatchWithOffsetUpdate(
546 Patch: DebugOffsetPatch{
547 AttrOutOffset,
548 &OutUnit->getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugAddr),
549 true},
550 PatchesOffsetsList&: PatchesOffsets);
551
552 // Use size of .debug_addr header as attribute value. The offset to
553 // .debug_addr would be added later while patching.
554 AttrInfo.HasAddrBaseAttr = true;
555 return Generator
556 .addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: AttrSpec.Form,
557 Value: OutUnit->getDebugAddrHeaderSize())
558 .second;
559 } else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
560 AttrInfo.IsDeclaration = true;
561
562 // DW_AT_LLVM_stmt_sequence refers to line info in this unit's
563 // .debug_line contribution, which only exists for compile units.
564 // DependencyTracker can route a module-scope subprogram to a type
565 // unit when ODR deduplication applies (see
566 // DependencyTracker.cpp: DW_TAG_subprogram case), so drop the
567 // attribute on that path — mirroring how cloneBlockAttr handles
568 // type-unit placement.
569 if (AttrSpec.Attr == dwarf::DW_AT_LLVM_stmt_sequence &&
570 !OutUnit.isCompileUnit())
571 return 0;
572
573 // A compile unit's high_pc comes from the unit's own linked range and spans
574 // every symbol in it.
575 if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
576 InputDieEntry->getTag() != dwarf::DW_TAG_compile_unit)
577 Value = constrainHighPC(HighPC: Value, /*IsLength=*/true);
578
579 auto Result =
580 Generator.addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: ResultingForm, Value);
581 // Record DW_AT_LLVM_stmt_sequence so the attribute value can be
582 // rewritten with the correct .debug_line offset after the line table
583 // for this CU has been emitted. We also register a DebugOffsetPatch so
584 // that the final-section offset of .debug_line gets added when the
585 // section is placed in the combined output.
586 if (AttrSpec.Attr == dwarf::DW_AT_LLVM_stmt_sequence) {
587 // Record the attribute's raw input stmt-sequence offset. Resolution
588 // to a first-row index — including the boundary-walk fallback for
589 // sequences the DWARF parser may not have registered — happens in
590 // a post-cloning pass (buildStmtSeqOffsetToFirstRowIndex), so that
591 // matches the classic linker's behaviour.
592 OutUnit.getAsCompileUnit()->noteStmtSeqListAttribute(V: &Result.first, InputStmtSeqOffset: Value);
593 DebugInfoOutputSection.notePatchWithOffsetUpdate(
594 Patch: DebugOffsetPatch{
595 AttrOutOffset,
596 &OutUnit->getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLine),
597 /*AddLocalValue=*/true},
598 PatchesOffsetsList&: PatchesOffsets);
599 }
600 return Result.second;
601}
602
603static bool expressionDependsOnOriginUnit(const DWARFExpression &Expr) {
604 using Encoding = DWARFExpression::Operation::Encoding;
605
606 for (const DWARFExpression::Operation &Op : Expr) {
607 switch (Op.getCode()) {
608 case dwarf::DW_OP_addr:
609 case dwarf::DW_OP_addrx:
610 case dwarf::DW_OP_constx:
611 return true;
612 default:
613 break;
614 }
615
616 if (llvm::is_contained(Range: Op.getDescription().Op, Element: Encoding::BaseTypeRef))
617 return true;
618 }
619
620 return false;
621}
622
623size_t DIEAttributeCloner::cloneBlockAttr(
624 const DWARFFormValue &Val,
625 const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
626
627 size_t NumberOfPatchesAtStart = PatchesOffsets.size();
628
629 // If the block is a DWARF Expression, clone it into the temporary
630 // buffer using cloneExpression(), otherwise copy the data directly.
631 SmallVector<uint8_t, 32> Buffer;
632 ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
633 if (DWARFAttribute::mayHaveLocationExpr(Attr: AttrSpec.Attr) &&
634 (Val.isFormClass(FC: DWARFFormValue::FC_Block) ||
635 Val.isFormClass(FC: DWARFFormValue::FC_Exprloc))) {
636 DataExtractor Data(Bytes, InUnit.getOrigUnit().isLittleEndian());
637 DWARFExpression Expr(Data, InUnit.getOrigUnit().getAddressByteSize(),
638 InUnit.getFormParams().Format);
639
640 // A type unit is shared by every compile unit that references the type, so
641 // an expression resolving against one origin unit has no single correct
642 // value there.
643 if (OutUnit.isTypeUnit() && expressionDependsOnOriginUnit(Expr))
644 return 0;
645
646 InUnit.cloneDieAttrExpression(InputExpression: Expr, OutputExpression&: Buffer, Section&: DebugInfoOutputSection,
647 VarAddressAdjustment, PatchesOffsets);
648 Bytes = Buffer;
649 }
650
651 // The expression location data might be updated and exceed the original size.
652 // Check whether the new data fits into the original form.
653 dwarf::Form ResultForm = AttrSpec.Form;
654 if ((ResultForm == dwarf::DW_FORM_block1 && Bytes.size() > UINT8_MAX) ||
655 (ResultForm == dwarf::DW_FORM_block2 && Bytes.size() > UINT16_MAX) ||
656 (ResultForm == dwarf::DW_FORM_block4 && Bytes.size() > UINT32_MAX))
657 ResultForm = dwarf::DW_FORM_block;
658
659 size_t FinalAttributeSize;
660 if (AttrSpec.Form == dwarf::DW_FORM_exprloc)
661 FinalAttributeSize =
662 Generator.addLocationAttribute(Attr: AttrSpec.Attr, AttrForm: ResultForm, Bytes).second;
663 else
664 FinalAttributeSize =
665 Generator.addBlockAttribute(Attr: AttrSpec.Attr, AttrForm: ResultForm, Bytes).second;
666
667 // Update patches offsets with the size of length field for Bytes.
668 for (size_t Idx = NumberOfPatchesAtStart; Idx < PatchesOffsets.size();
669 Idx++) {
670 assert(FinalAttributeSize > Bytes.size());
671 *PatchesOffsets[Idx] +=
672 (AttrOutOffset + (FinalAttributeSize - Bytes.size()));
673 }
674
675 if (HasLocationExpressionAddress)
676 AttrInfo.HasLiveAddress =
677 VarAddressAdjustment.has_value() ||
678 InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
679
680 return FinalAttributeSize;
681}
682
683size_t DIEAttributeCloner::cloneAddressAttr(
684 const DWARFFormValue &Val,
685 const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
686 if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
687 AttrInfo.HasLiveAddress = true;
688
689 if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
690 return Generator
691 .addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: AttrSpec.Form, Value: Val.getRawUValue())
692 .second;
693
694 if (OutUnit.isTypeUnit())
695 return 0;
696
697 // Cloned Die may have address attributes relocated to a
698 // totally unrelated value. This can happen:
699 // - If high_pc is an address (Dwarf version == 2), then it might have been
700 // relocated to a totally unrelated value (because the end address in the
701 // object file might be start address of another function which got moved
702 // independently by the linker).
703 // - If address relocated in an inline_subprogram that happens at the
704 // beginning of its inlining function.
705 // To avoid above cases and to not apply relocation twice (in
706 // applyValidRelocs and here), read address attribute from InputDIE and apply
707 // Info.PCOffset here.
708
709 std::optional<DWARFFormValue> AddrAttribute =
710 InUnit.find(Die: InputDieEntry, Attrs: AttrSpec.Attr);
711 if (!AddrAttribute)
712 llvm_unreachable("Cann't find attribute");
713
714 std::optional<uint64_t> Addr = AddrAttribute->getAsAddress();
715 if (!Addr) {
716 InUnit.warn(Warning: "cann't read address attribute value.");
717 return 0;
718 }
719
720 if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
721 AttrSpec.Attr == dwarf::DW_AT_low_pc) {
722 if (std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc())
723 Addr = *LowPC;
724 else
725 return 0;
726 } else if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
727 AttrSpec.Attr == dwarf::DW_AT_high_pc) {
728 if (uint64_t HighPc = OutUnit.getAsCompileUnit()->getHighPc())
729 Addr = HighPc;
730 else
731 return 0;
732 } else {
733 if (AttrSpec.Attr == dwarf::DW_AT_high_pc)
734 Addr = constrainHighPC(HighPC: *Addr, /*IsLength=*/false);
735 if (VarAddressAdjustment)
736 *Addr += *VarAddressAdjustment;
737 else if (FuncAddressAdjustment)
738 *Addr += *FuncAddressAdjustment;
739 }
740
741 if (AttrSpec.Form == dwarf::DW_FORM_addr) {
742 return Generator.addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: AttrSpec.Form, Value: *Addr)
743 .second;
744 }
745
746 return Generator
747 .addScalarAttribute(Attr: AttrSpec.Attr, AttrForm: dwarf::Form::DW_FORM_addrx,
748 Value: OutUnit.getAsCompileUnit()->getDebugAddrIndex(Addr: *Addr))
749 .second;
750}
751
752uint64_t DIEAttributeCloner::constrainHighPC(uint64_t HighPC, bool IsLength) {
753 if (!FuncAddressAdjustment)
754 return HighPC;
755 std::optional<uint64_t> LowPC =
756 dwarf::toAddress(V: InUnit.find(Die: InputDieEntry, Attrs: dwarf::DW_AT_low_pc));
757 if (!LowPC)
758 return HighPC;
759 uint64_t Constrained =
760 InUnit.getContainingFile().Addresses->constrainCodeRangeHighPC(
761 LowPC: *LowPC, HighPC: IsLength ? *LowPC + HighPC : HighPC, Adjustment: *FuncAddressAdjustment);
762 return IsLength ? Constrained - *LowPC : Constrained;
763}
764
765unsigned DIEAttributeCloner::finalizeAbbreviations(bool HasChildrenToClone) {
766 // Add the size of the abbreviation number to the output offset.
767 AttrOutOffset +=
768 Generator.finalizeAbbreviations(CHILDREN_yes: HasChildrenToClone, OffsetsList: &PatchesOffsets);
769
770 return AttrOutOffset;
771}
772