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/Classic/DWARFLinker.h"
13 #include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
14 #include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
15 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
16 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
17 #include "llvm/Object/ObjectFile.h"
22 using namespace dwarf_linker
;
26 // ObjFileAddressMap allows to check whether specified DIE referencing
27 // dead addresses. It uses tombstone values to determine dead addresses.
28 // The concrete values of tombstone constants were discussed in
29 // https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.
30 // So we use following values as indicators of dead addresses:
32 // bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less))
33 // or ([LowPC, HighPC] is not inside address ranges of .text sections).
35 // maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less))
36 // That value is assumed to be compatible with
37 // http://www.dwarfstd.org/ShowIssue.php?issue=200609.1
39 // exec: [LowPC, HighPC] is not inside address ranges of .text sections
41 // universal: maxpc and bfd
42 class ObjFileAddressMap
: public AddressesMap
{
44 ObjFileAddressMap(DWARFContext
&Context
, const Options
&Options
,
45 object::ObjectFile
&ObjFile
)
47 // Remember addresses of existing text sections.
48 for (const object::SectionRef
&Sect
: ObjFile
.sections()) {
51 const uint64_t Size
= Sect
.getSize();
54 const uint64_t StartAddr
= Sect
.getAddress();
55 TextAddressRanges
.insert({StartAddr
, StartAddr
+ Size
});
58 // Check CU address ranges for tombstone value.
59 for (std::unique_ptr
<DWARFUnit
> &CU
: Context
.compile_units()) {
60 Expected
<llvm::DWARFAddressRangesVector
> ARanges
=
61 CU
->getUnitDIE().getAddressRanges();
63 llvm::consumeError(ARanges
.takeError());
67 for (auto &Range
: *ARanges
) {
68 if (!isDeadAddressRange(Range
.LowPC
, Range
.HighPC
, CU
->getVersion(),
69 Options
.Tombstone
, CU
->getAddressByteSize())) {
70 HasValidAddressRanges
= true;
75 if (HasValidAddressRanges
)
80 // should be renamed into has valid address ranges
81 bool hasValidRelocs() override
{ return HasValidAddressRanges
; }
83 std::optional
<int64_t>
84 getSubprogramRelocAdjustment(const DWARFDie
&DIE
) override
{
85 assert((DIE
.getTag() == dwarf::DW_TAG_subprogram
||
86 DIE
.getTag() == dwarf::DW_TAG_label
) &&
87 "Wrong type of input die");
89 if (std::optional
<uint64_t> LowPC
=
90 dwarf::toAddress(DIE
.find(dwarf::DW_AT_low_pc
))) {
91 if (!isDeadAddress(*LowPC
, DIE
.getDwarfUnit()->getVersion(),
93 DIE
.getDwarfUnit()->getAddressByteSize()))
94 // Relocation value for the linked binary is 0.
101 std::optional
<int64_t>
102 getExprOpAddressRelocAdjustment(DWARFUnit
&U
,
103 const DWARFExpression::Operation
&Op
,
104 uint64_t, uint64_t) override
{
105 switch (Op
.getCode()) {
107 assert(false && "Specified operation does not have address operand");
109 case dwarf::DW_OP_const2u
:
110 case dwarf::DW_OP_const4u
:
111 case dwarf::DW_OP_const8u
:
112 case dwarf::DW_OP_const2s
:
113 case dwarf::DW_OP_const4s
:
114 case dwarf::DW_OP_const8s
:
115 case dwarf::DW_OP_addr
: {
116 if (!isDeadAddress(Op
.getRawOperand(0), U
.getVersion(), Opts
.Tombstone
,
117 U
.getAddressByteSize()))
118 // Relocation value for the linked binary is 0.
121 case dwarf::DW_OP_constx
:
122 case dwarf::DW_OP_addrx
: {
123 if (std::optional
<object::SectionedAddress
> Address
=
124 U
.getAddrOffsetSectionItem(Op
.getRawOperand(0))) {
125 if (!isDeadAddress(Address
->Address
, U
.getVersion(), Opts
.Tombstone
,
126 U
.getAddressByteSize()))
127 // Relocation value for the linked binary is 0.
136 std::optional
<StringRef
> getLibraryInstallName() override
{
140 bool applyValidRelocs(MutableArrayRef
<char>, uint64_t, bool) override
{
141 // no need to apply relocations to the linked binary.
145 bool needToSaveValidRelocs() override
{ return false; }
147 void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
148 uint64_t) override
{}
150 void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset
,
151 uint64_t OutputUnitOffset
) override
{}
153 void clear() override
{}
156 // returns true if specified address range is inside address ranges
157 // of executable sections.
158 bool isInsideExecutableSectionsAddressRange(uint64_t LowPC
,
159 std::optional
<uint64_t> HighPC
) {
160 std::optional
<AddressRange
> Range
=
161 TextAddressRanges
.getRangeThatContains(LowPC
);
164 return Range
.has_value() && Range
->end() >= *HighPC
;
166 return Range
.has_value();
169 uint64_t isBFDDeadAddressRange(uint64_t LowPC
, std::optional
<uint64_t> HighPC
,
174 if ((Version
<= 4) && HighPC
&& (LowPC
== 1 && *HighPC
== 1))
177 return !isInsideExecutableSectionsAddressRange(LowPC
, HighPC
);
180 uint64_t isMAXPCDeadAddressRange(uint64_t LowPC
,
181 std::optional
<uint64_t> HighPC
,
182 uint16_t Version
, uint8_t AddressByteSize
) {
183 if (Version
<= 4 && HighPC
) {
184 if (LowPC
== (dwarf::computeTombstoneAddress(AddressByteSize
) - 1))
186 } else if (LowPC
== dwarf::computeTombstoneAddress(AddressByteSize
))
189 if (!isInsideExecutableSectionsAddressRange(LowPC
, HighPC
))
190 warning("Address referencing invalid text section is not marked with "
196 bool isDeadAddressRange(uint64_t LowPC
, std::optional
<uint64_t> HighPC
,
197 uint16_t Version
, TombstoneKind Tombstone
,
198 uint8_t AddressByteSize
) {
200 case TombstoneKind::BFD
:
201 return isBFDDeadAddressRange(LowPC
, HighPC
, Version
);
202 case TombstoneKind::MaxPC
:
203 return isMAXPCDeadAddressRange(LowPC
, HighPC
, Version
, AddressByteSize
);
204 case TombstoneKind::Universal
:
205 return isBFDDeadAddressRange(LowPC
, HighPC
, Version
) ||
206 isMAXPCDeadAddressRange(LowPC
, HighPC
, Version
, AddressByteSize
);
207 case TombstoneKind::Exec
:
208 return !isInsideExecutableSectionsAddressRange(LowPC
, HighPC
);
211 llvm_unreachable("Unknown tombstone value");
214 bool isDeadAddress(uint64_t LowPC
, uint16_t Version
, TombstoneKind Tombstone
,
215 uint8_t AddressByteSize
) {
216 return isDeadAddressRange(LowPC
, std::nullopt
, Version
, Tombstone
,
221 AddressRanges TextAddressRanges
;
223 bool HasValidAddressRanges
= false;
226 static bool knownByDWARFUtil(StringRef SecName
) {
227 return llvm::StringSwitch
<bool>(SecName
)
228 .Case(".debug_info", true)
229 .Case(".debug_types", true)
230 .Case(".debug_abbrev", true)
231 .Case(".debug_loc", true)
232 .Case(".debug_loclists", true)
233 .Case(".debug_frame", true)
234 .Case(".debug_aranges", true)
235 .Case(".debug_ranges", true)
236 .Case(".debug_rnglists", true)
237 .Case(".debug_line", true)
238 .Case(".debug_line_str", true)
239 .Case(".debug_addr", true)
240 .Case(".debug_macro", true)
241 .Case(".debug_macinfo", true)
242 .Case(".debug_str", true)
243 .Case(".debug_str_offsets", true)
244 .Case(".debug_pubnames", true)
245 .Case(".debug_pubtypes", true)
246 .Case(".debug_names", true)
250 template <typename AccelTableKind
>
251 static std::optional
<AccelTableKind
>
252 getAcceleratorTableKind(StringRef SecName
) {
253 return llvm::StringSwitch
<std::optional
<AccelTableKind
>>(SecName
)
254 .Case(".debug_pubnames", AccelTableKind::Pub
)
255 .Case(".debug_pubtypes", AccelTableKind::Pub
)
256 .Case(".debug_names", AccelTableKind::DebugNames
)
257 .Default(std::nullopt
);
260 static std::string
getMessageForReplacedAcceleratorTables(
261 SmallVector
<StringRef
> &AccelTableNamesToReplace
,
262 DwarfUtilAccelKind TargetTable
) {
266 for (StringRef Name
: AccelTableNamesToReplace
) {
267 if (Message
.size() > 1)
272 Message
+= "' will be replaced with requested ";
274 switch (TargetTable
) {
275 case DwarfUtilAccelKind::DWARF
:
276 Message
+= ".debug_names table";
286 static std::string
getMessageForDeletedAcceleratorTables(
287 SmallVector
<StringRef
> &AccelTableNamesToReplace
) {
291 for (StringRef Name
: AccelTableNamesToReplace
) {
292 if (Message
.size() > 1)
297 Message
+= "' will be deleted as no accelerator tables are requested";
302 template <typename Linker
>
303 Error
linkDebugInfoImpl(object::ObjectFile
&File
, const Options
&Options
,
304 raw_pwrite_stream
&OutStream
) {
305 std::mutex ErrorHandlerMutex
;
307 auto ReportWarn
= [&](const Twine
&Message
, StringRef Context
,
308 const DWARFDie
*Die
) {
309 // FIXME: implement warning logging which does not block other threads.
310 if (!ErrorHandlerMutex
.try_lock())
313 warning(Message
, Context
);
314 if (Options
.Verbose
&& Die
) {
315 DIDumpOptions DumpOpts
;
316 DumpOpts
.ChildRecurseDepth
= 0;
317 DumpOpts
.Verbose
= Options
.Verbose
;
319 WithColor::note() << " in DIE:\n";
320 Die
->dump(errs(), /*Indent=*/6, DumpOpts
);
322 ErrorHandlerMutex
.unlock();
324 auto ReportErr
= [&](const Twine
&Message
, StringRef Context
,
326 // FIXME: implement error logging which does not block other threads.
327 if (!ErrorHandlerMutex
.try_lock())
330 WithColor::error(errs(), Context
) << Message
<< '\n';
331 ErrorHandlerMutex
.unlock();
334 // Create DWARF linker.
335 std::unique_ptr
<Linker
> DebugInfoLinker
=
336 Linker::createLinker(ReportErr
, ReportWarn
);
338 Triple TargetTriple
= File
.makeTriple();
339 if (Error Err
= DebugInfoLinker
->createEmitter(
340 TargetTriple
, Linker::OutputFileType::Object
, OutStream
))
343 DebugInfoLinker
->setEstimatedObjfilesAmount(1);
344 DebugInfoLinker
->setNumThreads(Options
.NumThreads
);
345 DebugInfoLinker
->setNoODR(!Options
.DoODRDeduplication
);
346 DebugInfoLinker
->setVerbosity(Options
.Verbose
);
347 DebugInfoLinker
->setUpdateIndexTablesOnly(!Options
.DoGarbageCollection
);
349 std::vector
<std::unique_ptr
<DWARFFile
>> ObjectsForLinking(1);
351 // Add object files to the DWARFLinker.
352 std::unique_ptr
<DWARFContext
> Context
= DWARFContext::create(
353 File
, DWARFContext::ProcessDebugRelocations::Process
, nullptr, "",
355 handleAllErrors(std::move(Err
), [&](ErrorInfoBase
&Info
) {
356 ReportErr(Info
.message(), "", nullptr);
360 handleAllErrors(std::move(Warning
), [&](ErrorInfoBase
&Info
) {
361 ReportWarn(Info
.message(), "", nullptr);
364 std::unique_ptr
<ObjFileAddressMap
> AddressesMap(
365 std::make_unique
<ObjFileAddressMap
>(*Context
, Options
, File
));
367 ObjectsForLinking
[0] = std::make_unique
<DWARFFile
>(
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
<DWARFFile
> &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
.UseDWARFLinkerParallel
)
455 return linkDebugInfoImpl
<parallel::DWARFLinker
>(File
, Options
, OutStream
);
457 return linkDebugInfoImpl
<classic::DWARFLinker
>(File
, Options
, OutStream
);
460 } // end of namespace dwarfutil
461 } // end of namespace llvm