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