[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / tools / llvm-dwarfutil / DebugInfoLinker.cpp
blob02a94596ec7644d67cd30c1a7f6946777c815ebf
1 //=== DebugInfoLinker.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 //===----------------------------------------------------------------------===//
9 #include "DebugInfoLinker.h"
10 #include "Error.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"
18 #include <memory>
19 #include <vector>
21 namespace llvm {
22 namespace dwarfutil {
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 {
42 public:
43 ObjFileAddressMap(DWARFContext &Context, const Options &Options,
44 object::ObjectFile &ObjFile)
45 : Opts(Options) {
46 // Remember addresses of existing text sections.
47 for (const object::SectionRef &Sect : ObjFile.sections()) {
48 if (!Sect.isText())
49 continue;
50 const uint64_t Size = Sect.getSize();
51 if (Size == 0)
52 continue;
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();
61 if (!ARanges) {
62 llvm::consumeError(ARanges.takeError());
63 continue;
66 for (auto &Range : *ARanges) {
67 if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
68 Options.Tombstone, CU->getAddressByteSize())) {
69 HasValidAddressRanges = true;
70 break;
74 if (HasValidAddressRanges)
75 break;
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(),
91 Opts.Tombstone,
92 DIE.getDwarfUnit()->getAddressByteSize()))
93 // Relocation value for the linked binary is 0.
94 return 0;
97 return std::nullopt;
100 std::optional<int64_t>
101 getExprOpAddressRelocAdjustment(DWARFUnit &U,
102 const DWARFExpression::Operation &Op,
103 uint64_t, uint64_t) override {
104 switch (Op.getCode()) {
105 default: {
106 assert(false && "Specified operation does not have address operand");
107 } break;
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.
118 return 0;
119 } break;
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.
127 return 0;
129 } break;
132 return std::nullopt;
135 std::optional<StringRef> getLibraryInstallName() override {
136 return std::nullopt;
139 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
140 // no need to apply relocations to the linked binary.
141 return false;
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 {}
154 protected:
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);
162 if (HighPC)
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,
169 uint16_t Version) {
170 if (LowPC == 0)
171 return true;
173 if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
174 return true;
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))
184 return true;
185 } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
186 return true;
188 if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
189 warning("Address referencing invalid text section is not marked with "
190 "tombstone value");
192 return false;
195 bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
196 uint16_t Version, TombstoneKind Tombstone,
197 uint8_t AddressByteSize) {
198 switch (Tombstone) {
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,
216 AddressByteSize);
219 private:
220 AddressRanges TextAddressRanges;
221 const Options &Opts;
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)
246 .Default(false);
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) {
262 std::string Message;
264 Message += "'";
265 for (StringRef Name : AccelTableNamesToReplace) {
266 if (Message.size() > 1)
267 Message += ", ";
268 Message += Name;
271 Message += "' will be replaced with requested ";
273 switch (TargetTable) {
274 case DwarfUtilAccelKind::DWARF:
275 Message += ".debug_names table";
276 break;
278 default:
279 assert(false);
282 return Message;
285 static std::string getMessageForDeletedAcceleratorTables(
286 SmallVector<StringRef> &AccelTableNamesToReplace) {
287 std::string Message;
289 Message += "'";
290 for (StringRef Name : AccelTableNamesToReplace) {
291 if (Message.size() > 1)
292 Message += ", ";
293 Message += Name;
296 Message += "' will be deleted as no accelerator tables are requested";
298 return Message;
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())
310 return;
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,
324 const DWARFDie *) {
325 // FIXME: implement error logging which does not block other threads.
326 if (!ErrorHandlerMutex.try_lock())
327 return;
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))
340 return Err;
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, "",
353 [&](Error Err) {
354 handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
355 ReportErr(Info.message(), "", nullptr);
358 [&](Error Warning) {
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,
365 File));
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,
378 OnCUDieLoaded);
380 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
381 if (MaxDWARFVersion == 0)
382 MaxDWARFVersion = 3;
384 if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
385 return Err;
387 SmallVector<typename Linker::AccelTableKind> AccelTables;
389 switch (Options.AccelTableKind) {
390 case DwarfUtilAccelKind::None:
391 // Nothing to do.
392 break;
393 case DwarfUtilAccelKind::DWARF:
394 // use .debug_names for all DWARF versions.
395 AccelTables.push_back(Linker::AccelTableKind::DebugNames);
396 break;
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);
423 warning(
424 formatv(
425 "'{0}' is not currently supported: section will be skipped",
426 Sec.Name),
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);
444 // Link debug info.
445 if (Error Err = DebugInfoLinker->link())
446 return Err;
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,
458 OutStream);
459 else
460 return linkDebugInfoImpl<DWARFLinker, DWARFFile, AddressesMap>(
461 File, Options, OutStream);
464 } // end of namespace dwarfutil
465 } // end of namespace llvm