1 //=== DebugInfoLinker.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DebugInfoLinker.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/DWARFLinker/DWARFLinker.h"
13 #include "llvm/DWARFLinker/DWARFStreamer.h"
14 #include "llvm/DWARFLinkerParallel/DWARFLinker.h"
15 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
16 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
17 #include "llvm/Object/ObjectFile.h"
24 // ObjFileAddressMap allows to check whether specified DIE referencing
25 // dead addresses. It uses tombstone values to determine dead addresses.
26 // The concrete values of tombstone constants were discussed in
27 // https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.
28 // So we use following values as indicators of dead addresses:
30 // bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less))
31 // or ([LowPC, HighPC] is not inside address ranges of .text sections).
33 // maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less))
34 // That value is assumed to be compatible with
35 // http://www.dwarfstd.org/ShowIssue.php?issue=200609.1
37 // exec: [LowPC, HighPC] is not inside address ranges of .text sections
39 // universal: maxpc and bfd
40 template <typename AddressMapBase
>
41 class ObjFileAddressMap
: public AddressMapBase
{
43 ObjFileAddressMap(DWARFContext
&Context
, const Options
&Options
,
44 object::ObjectFile
&ObjFile
)
46 // Remember addresses of existing text sections.
47 for (const object::SectionRef
&Sect
: ObjFile
.sections()) {
50 const uint64_t Size
= Sect
.getSize();
53 const uint64_t StartAddr
= Sect
.getAddress();
54 TextAddressRanges
.insert({StartAddr
, StartAddr
+ Size
});
57 // Check CU address ranges for tombstone value.
58 for (std::unique_ptr
<DWARFUnit
> &CU
: Context
.compile_units()) {
59 Expected
<llvm::DWARFAddressRangesVector
> ARanges
=
60 CU
->getUnitDIE().getAddressRanges();
62 llvm::consumeError(ARanges
.takeError());
66 for (auto &Range
: *ARanges
) {
67 if (!isDeadAddressRange(Range
.LowPC
, Range
.HighPC
, CU
->getVersion(),
68 Options
.Tombstone
, CU
->getAddressByteSize())) {
69 HasValidAddressRanges
= true;
74 if (HasValidAddressRanges
)
79 // should be renamed into has valid address ranges
80 bool hasValidRelocs() override
{ return HasValidAddressRanges
; }
82 std::optional
<int64_t>
83 getSubprogramRelocAdjustment(const DWARFDie
&DIE
) override
{
84 assert((DIE
.getTag() == dwarf::DW_TAG_subprogram
||
85 DIE
.getTag() == dwarf::DW_TAG_label
) &&
86 "Wrong type of input die");
88 if (std::optional
<uint64_t> LowPC
=
89 dwarf::toAddress(DIE
.find(dwarf::DW_AT_low_pc
))) {
90 if (!isDeadAddress(*LowPC
, DIE
.getDwarfUnit()->getVersion(),
92 DIE
.getDwarfUnit()->getAddressByteSize()))
93 // Relocation value for the linked binary is 0.
100 std::optional
<int64_t>
101 getExprOpAddressRelocAdjustment(DWARFUnit
&U
,
102 const DWARFExpression::Operation
&Op
,
103 uint64_t, uint64_t) override
{
104 switch (Op
.getCode()) {
106 assert(false && "Specified operation does not have address operand");
108 case dwarf::DW_OP_const2u
:
109 case dwarf::DW_OP_const4u
:
110 case dwarf::DW_OP_const8u
:
111 case dwarf::DW_OP_const2s
:
112 case dwarf::DW_OP_const4s
:
113 case dwarf::DW_OP_const8s
:
114 case dwarf::DW_OP_addr
: {
115 if (!isDeadAddress(Op
.getRawOperand(0), U
.getVersion(), Opts
.Tombstone
,
116 U
.getAddressByteSize()))
117 // Relocation value for the linked binary is 0.
120 case dwarf::DW_OP_constx
:
121 case dwarf::DW_OP_addrx
: {
122 if (std::optional
<object::SectionedAddress
> Address
=
123 U
.getAddrOffsetSectionItem(Op
.getRawOperand(0))) {
124 if (!isDeadAddress(Address
->Address
, U
.getVersion(), Opts
.Tombstone
,
125 U
.getAddressByteSize()))
126 // Relocation value for the linked binary is 0.
135 std::optional
<StringRef
> getLibraryInstallName() override
{
139 bool applyValidRelocs(MutableArrayRef
<char>, uint64_t, bool) override
{
140 // no need to apply relocations to the linked binary.
144 bool needToSaveValidRelocs() override
{ return false; }
146 void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
147 uint64_t) override
{}
149 void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset
,
150 uint64_t OutputUnitOffset
) override
{}
152 void clear() override
{}
155 // returns true if specified address range is inside address ranges
156 // of executable sections.
157 bool isInsideExecutableSectionsAddressRange(uint64_t LowPC
,
158 std::optional
<uint64_t> HighPC
) {
159 std::optional
<AddressRange
> Range
=
160 TextAddressRanges
.getRangeThatContains(LowPC
);
163 return Range
.has_value() && Range
->end() >= *HighPC
;
165 return Range
.has_value();
168 uint64_t isBFDDeadAddressRange(uint64_t LowPC
, std::optional
<uint64_t> HighPC
,
173 if ((Version
<= 4) && HighPC
&& (LowPC
== 1 && *HighPC
== 1))
176 return !isInsideExecutableSectionsAddressRange(LowPC
, HighPC
);
179 uint64_t isMAXPCDeadAddressRange(uint64_t LowPC
,
180 std::optional
<uint64_t> HighPC
,
181 uint16_t Version
, uint8_t AddressByteSize
) {
182 if (Version
<= 4 && HighPC
) {
183 if (LowPC
== (dwarf::computeTombstoneAddress(AddressByteSize
) - 1))
185 } else if (LowPC
== dwarf::computeTombstoneAddress(AddressByteSize
))
188 if (!isInsideExecutableSectionsAddressRange(LowPC
, HighPC
))
189 warning("Address referencing invalid text section is not marked with "
195 bool isDeadAddressRange(uint64_t LowPC
, std::optional
<uint64_t> HighPC
,
196 uint16_t Version
, TombstoneKind Tombstone
,
197 uint8_t AddressByteSize
) {
199 case TombstoneKind::BFD
:
200 return isBFDDeadAddressRange(LowPC
, HighPC
, Version
);
201 case TombstoneKind::MaxPC
:
202 return isMAXPCDeadAddressRange(LowPC
, HighPC
, Version
, AddressByteSize
);
203 case TombstoneKind::Universal
:
204 return isBFDDeadAddressRange(LowPC
, HighPC
, Version
) ||
205 isMAXPCDeadAddressRange(LowPC
, HighPC
, Version
, AddressByteSize
);
206 case TombstoneKind::Exec
:
207 return !isInsideExecutableSectionsAddressRange(LowPC
, HighPC
);
210 llvm_unreachable("Unknown tombstone value");
213 bool isDeadAddress(uint64_t LowPC
, uint16_t Version
, TombstoneKind Tombstone
,
214 uint8_t AddressByteSize
) {
215 return isDeadAddressRange(LowPC
, std::nullopt
, Version
, Tombstone
,
220 AddressRanges TextAddressRanges
;
222 bool HasValidAddressRanges
= false;
225 static bool knownByDWARFUtil(StringRef SecName
) {
226 return llvm::StringSwitch
<bool>(SecName
)
227 .Case(".debug_info", true)
228 .Case(".debug_types", true)
229 .Case(".debug_abbrev", true)
230 .Case(".debug_loc", true)
231 .Case(".debug_loclists", true)
232 .Case(".debug_frame", true)
233 .Case(".debug_aranges", true)
234 .Case(".debug_ranges", true)
235 .Case(".debug_rnglists", true)
236 .Case(".debug_line", true)
237 .Case(".debug_line_str", true)
238 .Case(".debug_addr", true)
239 .Case(".debug_macro", true)
240 .Case(".debug_macinfo", true)
241 .Case(".debug_str", true)
242 .Case(".debug_str_offsets", true)
243 .Case(".debug_pubnames", true)
244 .Case(".debug_pubtypes", true)
245 .Case(".debug_names", true)
249 template <typename AccelTableKind
>
250 static std::optional
<AccelTableKind
>
251 getAcceleratorTableKind(StringRef SecName
) {
252 return llvm::StringSwitch
<std::optional
<AccelTableKind
>>(SecName
)
253 .Case(".debug_pubnames", AccelTableKind::Pub
)
254 .Case(".debug_pubtypes", AccelTableKind::Pub
)
255 .Case(".debug_names", AccelTableKind::DebugNames
)
256 .Default(std::nullopt
);
259 static std::string
getMessageForReplacedAcceleratorTables(
260 SmallVector
<StringRef
> &AccelTableNamesToReplace
,
261 DwarfUtilAccelKind TargetTable
) {
265 for (StringRef Name
: AccelTableNamesToReplace
) {
266 if (Message
.size() > 1)
271 Message
+= "' will be replaced with requested ";
273 switch (TargetTable
) {
274 case DwarfUtilAccelKind::DWARF
:
275 Message
+= ".debug_names table";
285 static std::string
getMessageForDeletedAcceleratorTables(
286 SmallVector
<StringRef
> &AccelTableNamesToReplace
) {
290 for (StringRef Name
: AccelTableNamesToReplace
) {
291 if (Message
.size() > 1)
296 Message
+= "' will be deleted as no accelerator tables are requested";
301 template <typename Linker
, typename OutDwarfFile
, typename AddressMapBase
>
302 Error
linkDebugInfoImpl(object::ObjectFile
&File
, const Options
&Options
,
303 raw_pwrite_stream
&OutStream
) {
304 std::mutex ErrorHandlerMutex
;
306 auto ReportWarn
= [&](const Twine
&Message
, StringRef Context
,
307 const DWARFDie
*Die
) {
308 // FIXME: implement warning logging which does not block other threads.
309 if (!ErrorHandlerMutex
.try_lock())
312 warning(Message
, Context
);
313 if (Options
.Verbose
&& Die
) {
314 DIDumpOptions DumpOpts
;
315 DumpOpts
.ChildRecurseDepth
= 0;
316 DumpOpts
.Verbose
= Options
.Verbose
;
318 WithColor::note() << " in DIE:\n";
319 Die
->dump(errs(), /*Indent=*/6, DumpOpts
);
321 ErrorHandlerMutex
.unlock();
323 auto ReportErr
= [&](const Twine
&Message
, StringRef Context
,
325 // FIXME: implement error logging which does not block other threads.
326 if (!ErrorHandlerMutex
.try_lock())
329 WithColor::error(errs(), Context
) << Message
<< '\n';
330 ErrorHandlerMutex
.unlock();
333 // Create DWARF linker.
334 std::unique_ptr
<Linker
> DebugInfoLinker
=
335 Linker::createLinker(ReportErr
, ReportWarn
);
337 Triple TargetTriple
= File
.makeTriple();
338 if (Error Err
= DebugInfoLinker
->createEmitter(
339 TargetTriple
, Linker::OutputFileType::Object
, OutStream
))
342 DebugInfoLinker
->setEstimatedObjfilesAmount(1);
343 DebugInfoLinker
->setNumThreads(Options
.NumThreads
);
344 DebugInfoLinker
->setNoODR(!Options
.DoODRDeduplication
);
345 DebugInfoLinker
->setVerbosity(Options
.Verbose
);
346 DebugInfoLinker
->setUpdateIndexTablesOnly(!Options
.DoGarbageCollection
);
348 std::vector
<std::unique_ptr
<OutDwarfFile
>> ObjectsForLinking(1);
350 // Add object files to the DWARFLinker.
351 std::unique_ptr
<DWARFContext
> Context
= DWARFContext::create(
352 File
, DWARFContext::ProcessDebugRelocations::Process
, nullptr, "",
354 handleAllErrors(std::move(Err
), [&](ErrorInfoBase
&Info
) {
355 ReportErr(Info
.message(), "", nullptr);
359 handleAllErrors(std::move(Warning
), [&](ErrorInfoBase
&Info
) {
360 ReportWarn(Info
.message(), "", nullptr);
363 std::unique_ptr
<ObjFileAddressMap
<AddressMapBase
>> AddressesMap(
364 std::make_unique
<ObjFileAddressMap
<AddressMapBase
>>(*Context
, Options
,
367 ObjectsForLinking
[0] = std::make_unique
<OutDwarfFile
>(
368 File
.getFileName(), std::move(Context
), std::move(AddressesMap
));
370 uint16_t MaxDWARFVersion
= 0;
371 std::function
<void(const DWARFUnit
&Unit
)> OnCUDieLoaded
=
372 [&MaxDWARFVersion
](const DWARFUnit
&Unit
) {
373 MaxDWARFVersion
= std::max(Unit
.getVersion(), MaxDWARFVersion
);
376 for (size_t I
= 0; I
< ObjectsForLinking
.size(); I
++)
377 DebugInfoLinker
->addObjectFile(*ObjectsForLinking
[I
], nullptr,
380 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
381 if (MaxDWARFVersion
== 0)
384 if (Error Err
= DebugInfoLinker
->setTargetDWARFVersion(MaxDWARFVersion
))
387 SmallVector
<typename
Linker::AccelTableKind
> AccelTables
;
389 switch (Options
.AccelTableKind
) {
390 case DwarfUtilAccelKind::None
:
393 case DwarfUtilAccelKind::DWARF
:
394 // use .debug_names for all DWARF versions.
395 AccelTables
.push_back(Linker::AccelTableKind::DebugNames
);
399 // Add accelerator tables to DWARFLinker.
400 for (typename
Linker::AccelTableKind Table
: AccelTables
)
401 DebugInfoLinker
->addAccelTableKind(Table
);
403 for (std::unique_ptr
<OutDwarfFile
> &CurFile
: ObjectsForLinking
) {
404 SmallVector
<StringRef
> AccelTableNamesToReplace
;
405 SmallVector
<StringRef
> AccelTableNamesToDelete
;
407 // Unknown debug sections or non-requested accelerator sections would be
408 // removed. Display warning for such sections.
409 for (SectionName Sec
: CurFile
->Dwarf
->getDWARFObj().getSectionNames()) {
410 if (isDebugSection(Sec
.Name
)) {
411 std::optional
<typename
Linker::AccelTableKind
> SrcAccelTableKind
=
412 getAcceleratorTableKind
<typename
Linker::AccelTableKind
>(Sec
.Name
);
414 if (SrcAccelTableKind
) {
415 assert(knownByDWARFUtil(Sec
.Name
));
417 if (Options
.AccelTableKind
== DwarfUtilAccelKind::None
)
418 AccelTableNamesToDelete
.push_back(Sec
.Name
);
419 else if (!llvm::is_contained(AccelTables
, *SrcAccelTableKind
))
420 AccelTableNamesToReplace
.push_back(Sec
.Name
);
421 } else if (!knownByDWARFUtil(Sec
.Name
)) {
422 assert(!SrcAccelTableKind
);
425 "'{0}' is not currently supported: section will be skipped",
427 Options
.InputFileName
);
432 // Display message for the replaced accelerator tables.
433 if (!AccelTableNamesToReplace
.empty())
434 warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace
,
435 Options
.AccelTableKind
),
436 Options
.InputFileName
);
438 // Display message for the removed accelerator tables.
439 if (!AccelTableNamesToDelete
.empty())
440 warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete
),
441 Options
.InputFileName
);
445 if (Error Err
= DebugInfoLinker
->link())
448 DebugInfoLinker
->getEmitter()->finish();
449 return Error::success();
452 Error
linkDebugInfo(object::ObjectFile
&File
, const Options
&Options
,
453 raw_pwrite_stream
&OutStream
) {
454 if (Options
.UseLLVMDWARFLinker
)
455 return linkDebugInfoImpl
<dwarflinker_parallel::DWARFLinker
,
456 dwarflinker_parallel::DWARFFile
,
457 dwarflinker_parallel::AddressesMap
>(File
, Options
,
460 return linkDebugInfoImpl
<DWARFLinker
, DWARFFile
, AddressesMap
>(
461 File
, Options
, OutStream
);
464 } // end of namespace dwarfutil
465 } // end of namespace llvm