1 | //=== DWARFLinkerImpl.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 "DWARFLinkerImpl.h" |
10 | #include "DIEGenerator.h" |
11 | #include "DependencyTracker.h" |
12 | #include "llvm/DWARFLinker/Utils.h" |
13 | #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" |
14 | #include "llvm/Support/FormatVariadic.h" |
15 | #include "llvm/Support/Parallel.h" |
16 | #include "llvm/Support/ThreadPool.h" |
17 | |
18 | using namespace llvm; |
19 | using namespace dwarf_linker; |
20 | using namespace dwarf_linker::parallel; |
21 | |
22 | DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler, |
23 | MessageHandlerTy WarningHandler) |
24 | : UniqueUnitID(0), DebugStrStrings(GlobalData), |
25 | DebugLineStrStrings(GlobalData), CommonSections(GlobalData) { |
26 | GlobalData.setErrorHandler(ErrorHandler); |
27 | GlobalData.setWarningHandler(WarningHandler); |
28 | } |
29 | |
30 | DWARFLinkerImpl::LinkContext::LinkContext(LinkingGlobalData &GlobalData, |
31 | DWARFFile &File, |
32 | StringMap<uint64_t> &ClangModules, |
33 | std::atomic<size_t> &UniqueUnitID) |
34 | : OutputSections(GlobalData), InputDWARFFile(File), |
35 | ClangModules(ClangModules), UniqueUnitID(UniqueUnitID) { |
36 | |
37 | if (File.Dwarf) { |
38 | if (!File.Dwarf->compile_units().empty()) |
39 | CompileUnits.reserve(N: File.Dwarf->getNumCompileUnits()); |
40 | |
41 | // Set context format&endianness based on the input file. |
42 | Format.Version = File.Dwarf->getMaxVersion(); |
43 | Format.AddrSize = File.Dwarf->getCUAddrSize(); |
44 | Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little |
45 | : llvm::endianness::big; |
46 | } |
47 | } |
48 | |
49 | DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( |
50 | DWARFFile &File, std::unique_ptr<CompileUnit> Unit) |
51 | : File(File), Unit(std::move(Unit)) {} |
52 | |
53 | DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( |
54 | LinkContext::RefModuleUnit &&Other) |
55 | : File(Other.File), Unit(std::move(Other.Unit)) {} |
56 | |
57 | void DWARFLinkerImpl::LinkContext::addModulesCompileUnit( |
58 | LinkContext::RefModuleUnit &&Unit) { |
59 | ModulesCompileUnits.emplace_back(Args: std::move(Unit)); |
60 | } |
61 | |
62 | void DWARFLinkerImpl::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader, |
63 | CompileUnitHandlerTy OnCUDieLoaded) { |
64 | ObjectContexts.emplace_back(Args: std::make_unique<LinkContext>( |
65 | args&: GlobalData, args&: File, args&: ClangModules, args&: UniqueUnitID)); |
66 | |
67 | if (ObjectContexts.back()->InputDWARFFile.Dwarf) { |
68 | for (const std::unique_ptr<DWARFUnit> &CU : |
69 | ObjectContexts.back()->InputDWARFFile.Dwarf->compile_units()) { |
70 | DWARFDie CUDie = CU->getUnitDIE(); |
71 | OverallNumberOfCU++; |
72 | |
73 | if (!CUDie) |
74 | continue; |
75 | |
76 | OnCUDieLoaded(*CU); |
77 | |
78 | // Register mofule reference. |
79 | if (!GlobalData.getOptions().UpdateIndexTablesOnly) |
80 | ObjectContexts.back()->registerModuleReference(CUDie, Loader, |
81 | OnCUDieLoaded); |
82 | } |
83 | } |
84 | } |
85 | |
86 | void DWARFLinkerImpl::setEstimatedObjfilesAmount(unsigned ObjFilesNum) { |
87 | ObjectContexts.reserve(N: ObjFilesNum); |
88 | } |
89 | |
90 | Error DWARFLinkerImpl::link() { |
91 | // reset compile unit unique ID counter. |
92 | UniqueUnitID = 0; |
93 | |
94 | if (Error Err = validateAndUpdateOptions()) |
95 | return Err; |
96 | |
97 | dwarf::FormParams GlobalFormat = {.Version: GlobalData.getOptions().TargetDWARFVersion, |
98 | .AddrSize: 0, .Format: dwarf::DwarfFormat::DWARF32}; |
99 | llvm::endianness GlobalEndianness = llvm::endianness::native; |
100 | |
101 | if (std::optional<std::reference_wrapper<const Triple>> CurTriple = |
102 | GlobalData.getTargetTriple()) { |
103 | GlobalEndianness = (*CurTriple).get().isLittleEndian() |
104 | ? llvm::endianness::little |
105 | : llvm::endianness::big; |
106 | } |
107 | std::optional<uint16_t> Language; |
108 | |
109 | for (std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
110 | if (Context->InputDWARFFile.Dwarf == nullptr) { |
111 | Context->setOutputFormat(Format: Context->getFormParams(), Endianness: GlobalEndianness); |
112 | continue; |
113 | } |
114 | |
115 | if (GlobalData.getOptions().Verbose) { |
116 | outs() << "DEBUG MAP OBJECT: " << Context->InputDWARFFile.FileName |
117 | << "\n" ; |
118 | |
119 | for (const std::unique_ptr<DWARFUnit> &OrigCU : |
120 | Context->InputDWARFFile.Dwarf->compile_units()) { |
121 | outs() << "Input compilation unit:" ; |
122 | DIDumpOptions DumpOpts; |
123 | DumpOpts.ChildRecurseDepth = 0; |
124 | DumpOpts.Verbose = GlobalData.getOptions().Verbose; |
125 | OrigCU->getUnitDIE().dump(OS&: outs(), indent: 0, DumpOpts); |
126 | } |
127 | } |
128 | |
129 | // Verify input DWARF if requested. |
130 | if (GlobalData.getOptions().VerifyInputDWARF) |
131 | verifyInput(File: Context->InputDWARFFile); |
132 | |
133 | if (!GlobalData.getTargetTriple()) |
134 | GlobalEndianness = Context->getEndianness(); |
135 | GlobalFormat.AddrSize = |
136 | std::max(a: GlobalFormat.AddrSize, b: Context->getFormParams().AddrSize); |
137 | |
138 | Context->setOutputFormat(Format: Context->getFormParams(), Endianness: GlobalEndianness); |
139 | |
140 | // FIXME: move creation of CompileUnits into the addObjectFile. |
141 | // This would allow to not scan for context Language and Modules state |
142 | // twice. And then following handling might be removed. |
143 | for (const std::unique_ptr<DWARFUnit> &OrigCU : |
144 | Context->InputDWARFFile.Dwarf->compile_units()) { |
145 | DWARFDie UnitDie = OrigCU->getUnitDIE(); |
146 | |
147 | if (!Language) { |
148 | if (std::optional<DWARFFormValue> Val = |
149 | UnitDie.find(Attr: dwarf::DW_AT_language)) { |
150 | uint16_t LangVal = dwarf::toUnsigned(V: Val, Default: 0); |
151 | if (isODRLanguage(Language: LangVal)) |
152 | Language = LangVal; |
153 | } |
154 | } |
155 | } |
156 | } |
157 | |
158 | if (GlobalFormat.AddrSize == 0) { |
159 | if (std::optional<std::reference_wrapper<const Triple>> TargetTriple = |
160 | GlobalData.getTargetTriple()) |
161 | GlobalFormat.AddrSize = (*TargetTriple).get().isArch32Bit() ? 4 : 8; |
162 | else |
163 | GlobalFormat.AddrSize = 8; |
164 | } |
165 | |
166 | CommonSections.setOutputFormat(Format: GlobalFormat, Endianness: GlobalEndianness); |
167 | |
168 | if (!GlobalData.Options.NoODR && Language.has_value()) { |
169 | llvm::parallel::TaskGroup TGroup; |
170 | TGroup.spawn(f: [&]() { |
171 | ArtificialTypeUnit = std::make_unique<TypeUnit>( |
172 | args&: GlobalData, args: UniqueUnitID++, args&: Language, args&: GlobalFormat, args&: GlobalEndianness); |
173 | }); |
174 | } |
175 | |
176 | // Set parallel options. |
177 | if (GlobalData.getOptions().Threads == 0) |
178 | llvm::parallel::strategy = optimal_concurrency(TaskCount: OverallNumberOfCU); |
179 | else |
180 | llvm::parallel::strategy = |
181 | hardware_concurrency(ThreadCount: GlobalData.getOptions().Threads); |
182 | |
183 | // Link object files. |
184 | if (GlobalData.getOptions().Threads == 1) { |
185 | for (std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
186 | // Link object file. |
187 | if (Error Err = Context->link(ArtificialTypeUnit: ArtificialTypeUnit.get())) |
188 | GlobalData.error(Err: std::move(Err), Context: Context->InputDWARFFile.FileName); |
189 | |
190 | Context->InputDWARFFile.unload(); |
191 | } |
192 | } else { |
193 | DefaultThreadPool Pool(llvm::parallel::strategy); |
194 | for (std::unique_ptr<LinkContext> &Context : ObjectContexts) |
195 | Pool.async(F: [&]() { |
196 | // Link object file. |
197 | if (Error Err = Context->link(ArtificialTypeUnit: ArtificialTypeUnit.get())) |
198 | GlobalData.error(Err: std::move(Err), Context: Context->InputDWARFFile.FileName); |
199 | |
200 | Context->InputDWARFFile.unload(); |
201 | }); |
202 | |
203 | Pool.wait(); |
204 | } |
205 | |
206 | if (ArtificialTypeUnit != nullptr && !ArtificialTypeUnit->getTypePool() |
207 | .getRoot() |
208 | ->getValue() |
209 | .load() |
210 | ->Children.empty()) { |
211 | if (GlobalData.getTargetTriple().has_value()) |
212 | if (Error Err = ArtificialTypeUnit->finishCloningAndEmit( |
213 | TargetTriple: (*GlobalData.getTargetTriple()).get())) |
214 | return Err; |
215 | } |
216 | |
217 | // At this stage each compile units are cloned to their own set of debug |
218 | // sections. Now, update patches, assign offsets and assemble final file |
219 | // glueing debug tables from each compile unit. |
220 | glueCompileUnitsAndWriteToTheOutput(); |
221 | |
222 | return Error::success(); |
223 | } |
224 | |
225 | void DWARFLinkerImpl::verifyInput(const DWARFFile &File) { |
226 | assert(File.Dwarf); |
227 | |
228 | std::string Buffer; |
229 | raw_string_ostream OS(Buffer); |
230 | DIDumpOptions DumpOpts; |
231 | if (!File.Dwarf->verify(OS, DumpOpts: DumpOpts.noImplicitRecursion())) { |
232 | if (GlobalData.getOptions().InputVerificationHandler) |
233 | GlobalData.getOptions().InputVerificationHandler(File, OS.str()); |
234 | } |
235 | } |
236 | |
237 | Error DWARFLinkerImpl::validateAndUpdateOptions() { |
238 | if (GlobalData.getOptions().TargetDWARFVersion == 0) |
239 | return createStringError(EC: std::errc::invalid_argument, |
240 | Fmt: "target DWARF version is not set" ); |
241 | |
242 | if (GlobalData.getOptions().Verbose && GlobalData.getOptions().Threads != 1) { |
243 | GlobalData.Options.Threads = 1; |
244 | GlobalData.warn( |
245 | Warning: "set number of threads to 1 to make --verbose to work properly." , Context: "" ); |
246 | } |
247 | |
248 | // Do not do types deduplication in case --update. |
249 | if (GlobalData.getOptions().UpdateIndexTablesOnly && |
250 | !GlobalData.Options.NoODR) |
251 | GlobalData.Options.NoODR = true; |
252 | |
253 | return Error::success(); |
254 | } |
255 | |
256 | /// Resolve the relative path to a build artifact referenced by DWARF by |
257 | /// applying DW_AT_comp_dir. |
258 | static void resolveRelativeObjectPath(SmallVectorImpl<char> &Buf, DWARFDie CU) { |
259 | sys::path::append(path&: Buf, a: dwarf::toString(V: CU.find(Attr: dwarf::DW_AT_comp_dir), Default: "" )); |
260 | } |
261 | |
262 | static uint64_t getDwoId(const DWARFDie &CUDie) { |
263 | auto DwoId = dwarf::toUnsigned( |
264 | V: CUDie.find(Attrs: {dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id})); |
265 | if (DwoId) |
266 | return *DwoId; |
267 | return 0; |
268 | } |
269 | |
270 | static std::string |
271 | remapPath(StringRef Path, |
272 | const DWARFLinker::ObjectPrefixMapTy &ObjectPrefixMap) { |
273 | if (ObjectPrefixMap.empty()) |
274 | return Path.str(); |
275 | |
276 | SmallString<256> p = Path; |
277 | for (const auto &Entry : ObjectPrefixMap) |
278 | if (llvm::sys::path::replace_path_prefix(Path&: p, OldPrefix: Entry.first, NewPrefix: Entry.second)) |
279 | break; |
280 | return p.str().str(); |
281 | } |
282 | |
283 | static std::string getPCMFile(const DWARFDie &CUDie, |
284 | DWARFLinker::ObjectPrefixMapTy *ObjectPrefixMap) { |
285 | std::string PCMFile = dwarf::toString( |
286 | V: CUDie.find(Attrs: {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), Default: "" ); |
287 | |
288 | if (PCMFile.empty()) |
289 | return PCMFile; |
290 | |
291 | if (ObjectPrefixMap) |
292 | PCMFile = remapPath(Path: PCMFile, ObjectPrefixMap: *ObjectPrefixMap); |
293 | |
294 | return PCMFile; |
295 | } |
296 | |
297 | std::pair<bool, bool> DWARFLinkerImpl::LinkContext::isClangModuleRef( |
298 | const DWARFDie &CUDie, std::string &PCMFile, unsigned Indent, bool Quiet) { |
299 | if (PCMFile.empty()) |
300 | return std::make_pair(x: false, y: false); |
301 | |
302 | // Clang module DWARF skeleton CUs abuse this for the path to the module. |
303 | uint64_t DwoId = getDwoId(CUDie); |
304 | |
305 | std::string Name = dwarf::toString(V: CUDie.find(Attr: dwarf::DW_AT_name), Default: "" ); |
306 | if (Name.empty()) { |
307 | if (!Quiet) |
308 | GlobalData.warn(Warning: "anonymous module skeleton CU for " + PCMFile + "." , |
309 | Context: InputDWARFFile.FileName); |
310 | return std::make_pair(x: true, y: true); |
311 | } |
312 | |
313 | if (!Quiet && GlobalData.getOptions().Verbose) { |
314 | outs().indent(NumSpaces: Indent); |
315 | outs() << "Found clang module reference " << PCMFile; |
316 | } |
317 | |
318 | auto Cached = ClangModules.find(Key: PCMFile); |
319 | if (Cached != ClangModules.end()) { |
320 | // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is |
321 | // fixed in clang, only warn about DWO_id mismatches in verbose mode. |
322 | // ASTFileSignatures will change randomly when a module is rebuilt. |
323 | if (!Quiet && GlobalData.getOptions().Verbose && (Cached->second != DwoId)) |
324 | GlobalData.warn( |
325 | Warning: Twine("hash mismatch: this object file was built against a " |
326 | "different version of the module " ) + |
327 | PCMFile + "." , |
328 | Context: InputDWARFFile.FileName); |
329 | if (!Quiet && GlobalData.getOptions().Verbose) |
330 | outs() << " [cached].\n" ; |
331 | return std::make_pair(x: true, y: true); |
332 | } |
333 | |
334 | return std::make_pair(x: true, y: false); |
335 | } |
336 | |
337 | /// If this compile unit is really a skeleton CU that points to a |
338 | /// clang module, register it in ClangModules and return true. |
339 | /// |
340 | /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name |
341 | /// pointing to the module, and a DW_AT_gnu_dwo_id with the module |
342 | /// hash. |
343 | bool DWARFLinkerImpl::LinkContext::registerModuleReference( |
344 | const DWARFDie &CUDie, ObjFileLoaderTy Loader, |
345 | CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) { |
346 | std::string PCMFile = |
347 | getPCMFile(CUDie, ObjectPrefixMap: GlobalData.getOptions().ObjectPrefixMap); |
348 | std::pair<bool, bool> IsClangModuleRef = |
349 | isClangModuleRef(CUDie, PCMFile, Indent, Quiet: false); |
350 | |
351 | if (!IsClangModuleRef.first) |
352 | return false; |
353 | |
354 | if (IsClangModuleRef.second) |
355 | return true; |
356 | |
357 | if (GlobalData.getOptions().Verbose) |
358 | outs() << " ...\n" ; |
359 | |
360 | // Cyclic dependencies are disallowed by Clang, but we still |
361 | // shouldn't run into an infinite loop, so mark it as processed now. |
362 | ClangModules.insert(KV: {PCMFile, getDwoId(CUDie)}); |
363 | |
364 | if (Error E = |
365 | loadClangModule(Loader, CUDie, PCMFile, OnCUDieLoaded, Indent: Indent + 2)) { |
366 | consumeError(Err: std::move(E)); |
367 | return false; |
368 | } |
369 | return true; |
370 | } |
371 | |
372 | Error DWARFLinkerImpl::LinkContext::loadClangModule( |
373 | ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile, |
374 | CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) { |
375 | |
376 | uint64_t DwoId = getDwoId(CUDie); |
377 | std::string ModuleName = dwarf::toString(V: CUDie.find(Attr: dwarf::DW_AT_name), Default: "" ); |
378 | |
379 | /// Using a SmallString<0> because loadClangModule() is recursive. |
380 | SmallString<0> Path(GlobalData.getOptions().PrependPath); |
381 | if (sys::path::is_relative(path: PCMFile)) |
382 | resolveRelativeObjectPath(Buf&: Path, CU: CUDie); |
383 | sys::path::append(path&: Path, a: PCMFile); |
384 | // Don't use the cached binary holder because we have no thread-safety |
385 | // guarantee and the lifetime is limited. |
386 | |
387 | if (Loader == nullptr) { |
388 | GlobalData.error(Err: "cann't load clang module: loader is not specified." , |
389 | Context: InputDWARFFile.FileName); |
390 | return Error::success(); |
391 | } |
392 | |
393 | auto ErrOrObj = Loader(InputDWARFFile.FileName, Path); |
394 | if (!ErrOrObj) |
395 | return Error::success(); |
396 | |
397 | std::unique_ptr<CompileUnit> Unit; |
398 | for (const auto &CU : ErrOrObj->Dwarf->compile_units()) { |
399 | OnCUDieLoaded(*CU); |
400 | // Recursively get all modules imported by this one. |
401 | auto ChildCUDie = CU->getUnitDIE(); |
402 | if (!ChildCUDie) |
403 | continue; |
404 | if (!registerModuleReference(CUDie: ChildCUDie, Loader, OnCUDieLoaded, Indent)) { |
405 | if (Unit) { |
406 | std::string Err = |
407 | (PCMFile + |
408 | ": Clang modules are expected to have exactly 1 compile unit.\n" ); |
409 | GlobalData.error(Err, Context: InputDWARFFile.FileName); |
410 | return make_error<StringError>(Args&: Err, Args: inconvertibleErrorCode()); |
411 | } |
412 | // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is |
413 | // fixed in clang, only warn about DWO_id mismatches in verbose mode. |
414 | // ASTFileSignatures will change randomly when a module is rebuilt. |
415 | uint64_t PCMDwoId = getDwoId(CUDie: ChildCUDie); |
416 | if (PCMDwoId != DwoId) { |
417 | if (GlobalData.getOptions().Verbose) |
418 | GlobalData.warn( |
419 | Warning: Twine("hash mismatch: this object file was built against a " |
420 | "different version of the module " ) + |
421 | PCMFile + "." , |
422 | Context: InputDWARFFile.FileName); |
423 | // Update the cache entry with the DwoId of the module loaded from disk. |
424 | ClangModules[PCMFile] = PCMDwoId; |
425 | } |
426 | |
427 | // Empty modules units should not be cloned. |
428 | if (!ChildCUDie.hasChildren()) |
429 | continue; |
430 | |
431 | // Add this module. |
432 | Unit = std::make_unique<CompileUnit>( |
433 | args&: GlobalData, args&: *CU, args: UniqueUnitID.fetch_add(i: 1), args&: ModuleName, args&: *ErrOrObj, |
434 | args&: getUnitForOffset, args: CU->getFormParams(), args: getEndianness()); |
435 | } |
436 | } |
437 | |
438 | if (Unit) { |
439 | ModulesCompileUnits.emplace_back(Args: RefModuleUnit{*ErrOrObj, std::move(Unit)}); |
440 | // Preload line table, as it can't be loaded asynchronously. |
441 | ModulesCompileUnits.back().Unit->loadLineTable(); |
442 | } |
443 | |
444 | return Error::success(); |
445 | } |
446 | |
447 | Error DWARFLinkerImpl::LinkContext::link(TypeUnit *ArtificialTypeUnit) { |
448 | InterCUProcessingStarted = false; |
449 | if (!InputDWARFFile.Dwarf) |
450 | return Error::success(); |
451 | |
452 | // Preload macro tables, as they can't be loaded asynchronously. |
453 | InputDWARFFile.Dwarf->getDebugMacinfo(); |
454 | InputDWARFFile.Dwarf->getDebugMacro(); |
455 | |
456 | // Link modules compile units first. |
457 | parallelForEach(R&: ModulesCompileUnits, Fn: [&](RefModuleUnit &RefModule) { |
458 | linkSingleCompileUnit(CU&: *RefModule.Unit, ArtificialTypeUnit); |
459 | }); |
460 | |
461 | // Check for live relocations. If there is no any live relocation then we |
462 | // can skip entire object file. |
463 | if (!GlobalData.getOptions().UpdateIndexTablesOnly && |
464 | !InputDWARFFile.Addresses->hasValidRelocs()) { |
465 | if (GlobalData.getOptions().Verbose) |
466 | outs() << "No valid relocations found. Skipping.\n" ; |
467 | return Error::success(); |
468 | } |
469 | |
470 | OriginalDebugInfoSize = getInputDebugInfoSize(); |
471 | |
472 | // Create CompileUnit structures to keep information about source |
473 | // DWARFUnit`s, load line tables. |
474 | for (const auto &OrigCU : InputDWARFFile.Dwarf->compile_units()) { |
475 | // Load only unit DIE at this stage. |
476 | auto CUDie = OrigCU->getUnitDIE(); |
477 | std::string PCMFile = |
478 | getPCMFile(CUDie, ObjectPrefixMap: GlobalData.getOptions().ObjectPrefixMap); |
479 | |
480 | // The !isClangModuleRef condition effectively skips over fully resolved |
481 | // skeleton units. |
482 | if (!CUDie || GlobalData.getOptions().UpdateIndexTablesOnly || |
483 | !isClangModuleRef(CUDie, PCMFile, Indent: 0, Quiet: true).first) { |
484 | CompileUnits.emplace_back(Args: std::make_unique<CompileUnit>( |
485 | args&: GlobalData, args&: *OrigCU, args: UniqueUnitID.fetch_add(i: 1), args: "" , args&: InputDWARFFile, |
486 | args&: getUnitForOffset, args: OrigCU->getFormParams(), args: getEndianness())); |
487 | |
488 | // Preload line table, as it can't be loaded asynchronously. |
489 | CompileUnits.back()->loadLineTable(); |
490 | } |
491 | }; |
492 | |
493 | HasNewInterconnectedCUs = false; |
494 | |
495 | // Link self-sufficient compile units and discover inter-connected compile |
496 | // units. |
497 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
498 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit); |
499 | }); |
500 | |
501 | // Link all inter-connected units. |
502 | if (HasNewInterconnectedCUs) { |
503 | InterCUProcessingStarted = true; |
504 | |
505 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
506 | HasNewInterconnectedCUs = false; |
507 | |
508 | // Load inter-connected units. |
509 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
510 | if (CU->isInterconnectedCU()) { |
511 | CU->maybeResetToLoadedStage(); |
512 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
513 | DoUntilStage: CompileUnit::Stage::Loaded); |
514 | } |
515 | }); |
516 | |
517 | // Do liveness analysis for inter-connected units. |
518 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
519 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
520 | DoUntilStage: CompileUnit::Stage::LivenessAnalysisDone); |
521 | }); |
522 | |
523 | return HasNewInterconnectedCUs.load(); |
524 | })) |
525 | return Err; |
526 | |
527 | // Update dependencies. |
528 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
529 | HasNewGlobalDependency = false; |
530 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
531 | linkSingleCompileUnit( |
532 | CU&: *CU, ArtificialTypeUnit, |
533 | DoUntilStage: CompileUnit::Stage::UpdateDependenciesCompleteness); |
534 | }); |
535 | return HasNewGlobalDependency.load(); |
536 | })) |
537 | return Err; |
538 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
539 | if (CU->isInterconnectedCU() && |
540 | CU->getStage() == CompileUnit::Stage::LivenessAnalysisDone) |
541 | CU->setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); |
542 | }); |
543 | |
544 | // Assign type names. |
545 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
546 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
547 | DoUntilStage: CompileUnit::Stage::TypeNamesAssigned); |
548 | }); |
549 | |
550 | // Clone inter-connected units. |
551 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
552 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
553 | DoUntilStage: CompileUnit::Stage::Cloned); |
554 | }); |
555 | |
556 | // Update patches for inter-connected units. |
557 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
558 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
559 | DoUntilStage: CompileUnit::Stage::PatchesUpdated); |
560 | }); |
561 | |
562 | // Release data. |
563 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
564 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
565 | DoUntilStage: CompileUnit::Stage::Cleaned); |
566 | }); |
567 | } |
568 | |
569 | if (GlobalData.getOptions().UpdateIndexTablesOnly) { |
570 | // Emit Invariant sections. |
571 | |
572 | if (Error Err = emitInvariantSections()) |
573 | return Err; |
574 | } else if (!CompileUnits.empty()) { |
575 | // Emit .debug_frame section. |
576 | |
577 | Error ResultErr = Error::success(); |
578 | llvm::parallel::TaskGroup TGroup; |
579 | // We use task group here as PerThreadBumpPtrAllocator should be called from |
580 | // the threads created by ThreadPoolExecutor. |
581 | TGroup.spawn(f: [&]() { |
582 | if (Error Err = cloneAndEmitDebugFrame()) |
583 | ResultErr = std::move(Err); |
584 | }); |
585 | return ResultErr; |
586 | } |
587 | |
588 | return Error::success(); |
589 | } |
590 | |
591 | void DWARFLinkerImpl::LinkContext::linkSingleCompileUnit( |
592 | CompileUnit &CU, TypeUnit *ArtificialTypeUnit, |
593 | enum CompileUnit::Stage DoUntilStage) { |
594 | if (InterCUProcessingStarted != CU.isInterconnectedCU()) |
595 | return; |
596 | |
597 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
598 | if (CU.getStage() >= DoUntilStage) |
599 | return false; |
600 | |
601 | switch (CU.getStage()) { |
602 | case CompileUnit::Stage::CreatedNotLoaded: { |
603 | // Load input compilation unit DIEs. |
604 | // Analyze properties of DIEs. |
605 | if (!CU.loadInputDIEs()) { |
606 | // We do not need to do liveness analysis for invalid compilation |
607 | // unit. |
608 | CU.setStage(CompileUnit::Stage::Skipped); |
609 | } else { |
610 | CU.analyzeDWARFStructure(); |
611 | |
612 | // The registerModuleReference() condition effectively skips |
613 | // over fully resolved skeleton units. This second pass of |
614 | // registerModuleReferences doesn't do any new work, but it |
615 | // will collect top-level errors, which are suppressed. Module |
616 | // warnings were already displayed in the first iteration. |
617 | if (registerModuleReference( |
618 | CUDie: CU.getOrigUnit().getUnitDIE(), Loader: nullptr, |
619 | OnCUDieLoaded: [](const DWARFUnit &) {}, Indent: 0)) |
620 | CU.setStage(CompileUnit::Stage::PatchesUpdated); |
621 | else |
622 | CU.setStage(CompileUnit::Stage::Loaded); |
623 | } |
624 | } break; |
625 | |
626 | case CompileUnit::Stage::Loaded: { |
627 | // Mark all the DIEs that need to be present in the generated output. |
628 | // If ODR requested, build type names. |
629 | if (!CU.resolveDependenciesAndMarkLiveness(InterCUProcessingStarted, |
630 | HasNewInterconnectedCUs)) { |
631 | assert(HasNewInterconnectedCUs && |
632 | "Flag indicating new inter-connections is not set" ); |
633 | return false; |
634 | } |
635 | |
636 | CU.setStage(CompileUnit::Stage::LivenessAnalysisDone); |
637 | } break; |
638 | |
639 | case CompileUnit::Stage::LivenessAnalysisDone: { |
640 | if (InterCUProcessingStarted) { |
641 | if (CU.updateDependenciesCompleteness()) |
642 | HasNewGlobalDependency = true; |
643 | return false; |
644 | } else { |
645 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
646 | return CU.updateDependenciesCompleteness(); |
647 | })) |
648 | return std::move(Err); |
649 | |
650 | CU.setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); |
651 | } |
652 | } break; |
653 | |
654 | case CompileUnit::Stage::UpdateDependenciesCompleteness: |
655 | #ifndef NDEBUG |
656 | CU.verifyDependencies(); |
657 | #endif |
658 | |
659 | if (ArtificialTypeUnit) { |
660 | if (Error Err = |
661 | CU.assignTypeNames(TypePoolRef&: ArtificialTypeUnit->getTypePool())) |
662 | return std::move(Err); |
663 | } |
664 | CU.setStage(CompileUnit::Stage::TypeNamesAssigned); |
665 | break; |
666 | |
667 | case CompileUnit::Stage::TypeNamesAssigned: |
668 | // Clone input compile unit. |
669 | if (CU.isClangModule() || |
670 | GlobalData.getOptions().UpdateIndexTablesOnly || |
671 | CU.getContaingFile().Addresses->hasValidRelocs()) { |
672 | if (Error Err = CU.cloneAndEmit(TargetTriple: GlobalData.getTargetTriple(), |
673 | ArtificialTypeUnit)) |
674 | return std::move(Err); |
675 | } |
676 | |
677 | CU.setStage(CompileUnit::Stage::Cloned); |
678 | break; |
679 | |
680 | case CompileUnit::Stage::Cloned: |
681 | // Update DIEs referencies. |
682 | CU.updateDieRefPatchesWithClonedOffsets(); |
683 | CU.setStage(CompileUnit::Stage::PatchesUpdated); |
684 | break; |
685 | |
686 | case CompileUnit::Stage::PatchesUpdated: |
687 | // Cleanup resources. |
688 | CU.cleanupDataAfterClonning(); |
689 | CU.setStage(CompileUnit::Stage::Cleaned); |
690 | break; |
691 | |
692 | case CompileUnit::Stage::Cleaned: |
693 | assert(false); |
694 | break; |
695 | |
696 | case CompileUnit::Stage::Skipped: |
697 | // Nothing to do. |
698 | break; |
699 | } |
700 | |
701 | return true; |
702 | })) { |
703 | CU.error(Err: std::move(Err)); |
704 | CU.cleanupDataAfterClonning(); |
705 | CU.setStage(CompileUnit::Stage::Skipped); |
706 | } |
707 | } |
708 | |
709 | Error DWARFLinkerImpl::LinkContext::emitInvariantSections() { |
710 | if (!GlobalData.getTargetTriple().has_value()) |
711 | return Error::success(); |
712 | |
713 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLoc).OS |
714 | << InputDWARFFile.Dwarf->getDWARFObj().getLocSection().Data; |
715 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLocLists).OS |
716 | << InputDWARFFile.Dwarf->getDWARFObj().getLoclistsSection().Data; |
717 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugRange).OS |
718 | << InputDWARFFile.Dwarf->getDWARFObj().getRangesSection().Data; |
719 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugRngLists).OS |
720 | << InputDWARFFile.Dwarf->getDWARFObj().getRnglistsSection().Data; |
721 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugARanges).OS |
722 | << InputDWARFFile.Dwarf->getDWARFObj().getArangesSection(); |
723 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugFrame).OS |
724 | << InputDWARFFile.Dwarf->getDWARFObj().getFrameSection().Data; |
725 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugAddr).OS |
726 | << InputDWARFFile.Dwarf->getDWARFObj().getAddrSection().Data; |
727 | |
728 | return Error::success(); |
729 | } |
730 | |
731 | Error DWARFLinkerImpl::LinkContext::cloneAndEmitDebugFrame() { |
732 | if (!GlobalData.getTargetTriple().has_value()) |
733 | return Error::success(); |
734 | |
735 | if (InputDWARFFile.Dwarf == nullptr) |
736 | return Error::success(); |
737 | |
738 | const DWARFObject &InputDWARFObj = InputDWARFFile.Dwarf->getDWARFObj(); |
739 | |
740 | StringRef OrigFrameData = InputDWARFObj.getFrameSection().Data; |
741 | if (OrigFrameData.empty()) |
742 | return Error::success(); |
743 | |
744 | RangesTy AllUnitsRanges; |
745 | for (std::unique_ptr<CompileUnit> &Unit : CompileUnits) { |
746 | for (auto CurRange : Unit->getFunctionRanges()) |
747 | AllUnitsRanges.insert(Range: CurRange.Range, Value: CurRange.Value); |
748 | } |
749 | |
750 | unsigned SrcAddrSize = InputDWARFObj.getAddressSize(); |
751 | |
752 | SectionDescriptor &OutSection = |
753 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugFrame); |
754 | |
755 | DataExtractor Data(OrigFrameData, InputDWARFObj.isLittleEndian(), 0); |
756 | uint64_t InputOffset = 0; |
757 | |
758 | // Store the data of the CIEs defined in this object, keyed by their |
759 | // offsets. |
760 | DenseMap<uint64_t, StringRef> LocalCIES; |
761 | |
762 | /// The CIEs that have been emitted in the output section. The actual CIE |
763 | /// data serves a the key to this StringMap. |
764 | StringMap<uint32_t> EmittedCIEs; |
765 | |
766 | while (Data.isValidOffset(offset: InputOffset)) { |
767 | uint64_t EntryOffset = InputOffset; |
768 | uint32_t InitialLength = Data.getU32(offset_ptr: &InputOffset); |
769 | if (InitialLength == 0xFFFFFFFF) |
770 | return createFileError(F: InputDWARFObj.getFileName(), |
771 | E: createStringError(EC: std::errc::invalid_argument, |
772 | Fmt: "Dwarf64 bits no supported" )); |
773 | |
774 | uint32_t CIEId = Data.getU32(offset_ptr: &InputOffset); |
775 | if (CIEId == 0xFFFFFFFF) { |
776 | // This is a CIE, store it. |
777 | StringRef CIEData = OrigFrameData.substr(Start: EntryOffset, N: InitialLength + 4); |
778 | LocalCIES[EntryOffset] = CIEData; |
779 | // The -4 is to account for the CIEId we just read. |
780 | InputOffset += InitialLength - 4; |
781 | continue; |
782 | } |
783 | |
784 | uint64_t Loc = Data.getUnsigned(offset_ptr: &InputOffset, byte_size: SrcAddrSize); |
785 | |
786 | // Some compilers seem to emit frame info that doesn't start at |
787 | // the function entry point, thus we can't just lookup the address |
788 | // in the debug map. Use the AddressInfo's range map to see if the FDE |
789 | // describes something that we can relocate. |
790 | std::optional<AddressRangeValuePair> Range = |
791 | AllUnitsRanges.getRangeThatContains(Addr: Loc); |
792 | if (!Range) { |
793 | // The +4 is to account for the size of the InitialLength field itself. |
794 | InputOffset = EntryOffset + InitialLength + 4; |
795 | continue; |
796 | } |
797 | |
798 | // This is an FDE, and we have a mapping. |
799 | // Have we already emitted a corresponding CIE? |
800 | StringRef CIEData = LocalCIES[CIEId]; |
801 | if (CIEData.empty()) |
802 | return createFileError( |
803 | F: InputDWARFObj.getFileName(), |
804 | E: createStringError(EC: std::errc::invalid_argument, |
805 | Fmt: "Inconsistent debug_frame content. Dropping." )); |
806 | |
807 | uint64_t OffsetToCIERecord = OutSection.OS.tell(); |
808 | |
809 | // Look if we already emitted a CIE that corresponds to the |
810 | // referenced one (the CIE data is the key of that lookup). |
811 | auto IteratorInserted = |
812 | EmittedCIEs.insert(KV: std::make_pair(x&: CIEData, y&: OffsetToCIERecord)); |
813 | OffsetToCIERecord = IteratorInserted.first->getValue(); |
814 | |
815 | // Emit CIE for this ID if it is not emitted yet. |
816 | if (IteratorInserted.second) |
817 | OutSection.OS << CIEData; |
818 | |
819 | // Remember offset to the FDE record, so that we might update |
820 | // field referencing CIE record(containing OffsetToCIERecord), |
821 | // when final offsets are known. OffsetToCIERecord(which is written later) |
822 | // is local to the current .debug_frame section, it should be updated |
823 | // with final offset of the .debug_frame section. |
824 | OutSection.notePatch( |
825 | Patch: DebugOffsetPatch{OutSection.OS.tell() + 4, &OutSection, true}); |
826 | |
827 | // Emit the FDE with updated address and CIE pointer. |
828 | // (4 + AddrSize) is the size of the CIEId + initial_location |
829 | // fields that will get reconstructed by emitFDE(). |
830 | unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize); |
831 | emitFDE(CIEOffset: OffsetToCIERecord, AddrSize: SrcAddrSize, Address: Loc + Range->Value, |
832 | FDEBytes: OrigFrameData.substr(Start: InputOffset, N: FDERemainingBytes), Section&: OutSection); |
833 | InputOffset += FDERemainingBytes; |
834 | } |
835 | |
836 | return Error::success(); |
837 | } |
838 | |
839 | /// Emit a FDE into the debug_frame section. \p FDEBytes |
840 | /// contains the FDE data without the length, CIE offset and address |
841 | /// which will be replaced with the parameter values. |
842 | void DWARFLinkerImpl::LinkContext::emitFDE(uint32_t CIEOffset, |
843 | uint32_t AddrSize, uint64_t Address, |
844 | StringRef FDEBytes, |
845 | SectionDescriptor &Section) { |
846 | Section.emitIntVal(Val: FDEBytes.size() + 4 + AddrSize, Size: 4); |
847 | Section.emitIntVal(Val: CIEOffset, Size: 4); |
848 | Section.emitIntVal(Val: Address, Size: AddrSize); |
849 | Section.OS.write(Ptr: FDEBytes.data(), Size: FDEBytes.size()); |
850 | } |
851 | |
852 | void DWARFLinkerImpl::glueCompileUnitsAndWriteToTheOutput() { |
853 | if (!GlobalData.getTargetTriple().has_value()) |
854 | return; |
855 | assert(SectionHandler); |
856 | |
857 | // Go through all object files, all compile units and assign |
858 | // offsets to them. |
859 | assignOffsets(); |
860 | |
861 | // Patch size/offsets fields according to the assigned CU offsets. |
862 | patchOffsetsAndSizes(); |
863 | |
864 | // Emit common sections and write debug tables from all object files/compile |
865 | // units into the resulting file. |
866 | emitCommonSectionsAndWriteCompileUnitsToTheOutput(); |
867 | |
868 | if (ArtificialTypeUnit != nullptr) |
869 | ArtificialTypeUnit.reset(); |
870 | |
871 | // Write common debug sections into the resulting file. |
872 | writeCommonSectionsToTheOutput(); |
873 | |
874 | // Cleanup data. |
875 | cleanupDataAfterDWARFOutputIsWritten(); |
876 | |
877 | if (GlobalData.getOptions().Statistics) |
878 | printStatistic(); |
879 | } |
880 | |
881 | void DWARFLinkerImpl::printStatistic() { |
882 | |
883 | // For each object file map how many bytes were emitted. |
884 | StringMap<DebugInfoSize> SizeByObject; |
885 | |
886 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
887 | uint64_t AllDebugInfoSectionsSize = 0; |
888 | |
889 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
890 | if (std::optional<SectionDescriptor *> DebugInfo = |
891 | CU->tryGetSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo)) |
892 | AllDebugInfoSectionsSize += (*DebugInfo)->getContents().size(); |
893 | |
894 | SizeByObject[Context->InputDWARFFile.FileName].Input = |
895 | Context->OriginalDebugInfoSize; |
896 | SizeByObject[Context->InputDWARFFile.FileName].Output = |
897 | AllDebugInfoSectionsSize; |
898 | } |
899 | |
900 | // Create a vector sorted in descending order by output size. |
901 | std::vector<std::pair<StringRef, DebugInfoSize>> Sorted; |
902 | for (auto &E : SizeByObject) |
903 | Sorted.emplace_back(args: E.first(), args&: E.second); |
904 | llvm::sort(C&: Sorted, Comp: [](auto &LHS, auto &RHS) { |
905 | return LHS.second.Output > RHS.second.Output; |
906 | }); |
907 | |
908 | auto ComputePercentange = [](int64_t Input, int64_t Output) -> float { |
909 | const float Difference = Output - Input; |
910 | const float Sum = Input + Output; |
911 | if (Sum == 0) |
912 | return 0; |
913 | return (Difference / (Sum / 2)); |
914 | }; |
915 | |
916 | int64_t InputTotal = 0; |
917 | int64_t OutputTotal = 0; |
918 | const char *FormatStr = "{0,-45} {1,10}b {2,10}b {3,8:P}\n" ; |
919 | |
920 | // Print header. |
921 | outs() << ".debug_info section size (in bytes)\n" ; |
922 | outs() << "----------------------------------------------------------------" |
923 | "---------------\n" ; |
924 | outs() << "Filename Object " |
925 | " dSYM Change\n" ; |
926 | outs() << "----------------------------------------------------------------" |
927 | "---------------\n" ; |
928 | |
929 | // Print body. |
930 | for (auto &E : Sorted) { |
931 | InputTotal += E.second.Input; |
932 | OutputTotal += E.second.Output; |
933 | llvm::outs() << formatv( |
934 | Fmt: FormatStr, Vals: sys::path::filename(path: E.first).take_back(N: 45), Vals&: E.second.Input, |
935 | Vals&: E.second.Output, Vals: ComputePercentange(E.second.Input, E.second.Output)); |
936 | } |
937 | // Print total and footer. |
938 | outs() << "----------------------------------------------------------------" |
939 | "---------------\n" ; |
940 | llvm::outs() << formatv(Fmt: FormatStr, Vals: "Total" , Vals&: InputTotal, Vals&: OutputTotal, |
941 | Vals: ComputePercentange(InputTotal, OutputTotal)); |
942 | outs() << "----------------------------------------------------------------" |
943 | "---------------\n\n" ; |
944 | } |
945 | |
946 | void DWARFLinkerImpl::assignOffsets() { |
947 | llvm::parallel::TaskGroup TGroup; |
948 | TGroup.spawn(f: [&]() { assignOffsetsToStrings(); }); |
949 | TGroup.spawn(f: [&]() { assignOffsetsToSections(); }); |
950 | } |
951 | |
952 | void DWARFLinkerImpl::assignOffsetsToStrings() { |
953 | size_t CurDebugStrIndex = 1; // start from 1 to take into account zero entry. |
954 | uint64_t CurDebugStrOffset = |
955 | 1; // start from 1 to take into account zero entry. |
956 | size_t CurDebugLineStrIndex = 0; |
957 | uint64_t CurDebugLineStrOffset = 0; |
958 | |
959 | // Enumerates all strings, add them into the DwarfStringPoolEntry map, |
960 | // assign offset and index to the string if it is not indexed yet. |
961 | forEachOutputString(StringHandler: [&](StringDestinationKind Kind, |
962 | const StringEntry *String) { |
963 | switch (Kind) { |
964 | case StringDestinationKind::DebugStr: { |
965 | DwarfStringPoolEntryWithExtString *Entry = DebugStrStrings.add(String); |
966 | assert(Entry != nullptr); |
967 | |
968 | if (!Entry->isIndexed()) { |
969 | Entry->Offset = CurDebugStrOffset; |
970 | CurDebugStrOffset += Entry->String.size() + 1; |
971 | Entry->Index = CurDebugStrIndex++; |
972 | } |
973 | } break; |
974 | case StringDestinationKind::DebugLineStr: { |
975 | DwarfStringPoolEntryWithExtString *Entry = |
976 | DebugLineStrStrings.add(String); |
977 | assert(Entry != nullptr); |
978 | |
979 | if (!Entry->isIndexed()) { |
980 | Entry->Offset = CurDebugLineStrOffset; |
981 | CurDebugLineStrOffset += Entry->String.size() + 1; |
982 | Entry->Index = CurDebugLineStrIndex++; |
983 | } |
984 | } break; |
985 | } |
986 | }); |
987 | } |
988 | |
989 | void DWARFLinkerImpl::assignOffsetsToSections() { |
990 | std::array<uint64_t, SectionKindsNum> SectionSizesAccumulator = {0}; |
991 | |
992 | forEachObjectSectionsSet(SectionsSetHandler: [&](OutputSections &UnitSections) { |
993 | UnitSections.assignSectionsOffsetAndAccumulateSize(SectionSizesAccumulator); |
994 | }); |
995 | } |
996 | |
997 | void DWARFLinkerImpl::forEachOutputString( |
998 | function_ref<void(StringDestinationKind Kind, const StringEntry *String)> |
999 | StringHandler) { |
1000 | // To save space we do not create any separate string table. |
1001 | // We use already allocated string patches and accelerator entries: |
1002 | // enumerate them in natural order and assign offsets. |
1003 | // ASSUMPTION: strings should be stored into .debug_str/.debug_line_str |
1004 | // sections in the same order as they were assigned offsets. |
1005 | forEachCompileUnit(UnitHandler: [&](CompileUnit *CU) { |
1006 | CU->forEach(Handler: [&](SectionDescriptor &OutSection) { |
1007 | OutSection.ListDebugStrPatch.forEach(Handler: [&](DebugStrPatch &Patch) { |
1008 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1009 | }); |
1010 | |
1011 | OutSection.ListDebugLineStrPatch.forEach(Handler: [&](DebugLineStrPatch &Patch) { |
1012 | StringHandler(StringDestinationKind::DebugLineStr, Patch.String); |
1013 | }); |
1014 | }); |
1015 | |
1016 | CU->forEachAcceleratorRecord(Handler: [&](DwarfUnit::AccelInfo &Info) { |
1017 | StringHandler(DebugStr, Info.String); |
1018 | }); |
1019 | }); |
1020 | |
1021 | if (ArtificialTypeUnit != nullptr) { |
1022 | ArtificialTypeUnit->forEach(Handler: [&](SectionDescriptor &OutSection) { |
1023 | OutSection.ListDebugStrPatch.forEach(Handler: [&](DebugStrPatch &Patch) { |
1024 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1025 | }); |
1026 | |
1027 | OutSection.ListDebugLineStrPatch.forEach(Handler: [&](DebugLineStrPatch &Patch) { |
1028 | StringHandler(StringDestinationKind::DebugLineStr, Patch.String); |
1029 | }); |
1030 | |
1031 | OutSection.ListDebugTypeStrPatch.forEach(Handler: [&](DebugTypeStrPatch &Patch) { |
1032 | if (Patch.Die == nullptr) |
1033 | return; |
1034 | |
1035 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1036 | }); |
1037 | |
1038 | OutSection.ListDebugTypeLineStrPatch.forEach( |
1039 | Handler: [&](DebugTypeLineStrPatch &Patch) { |
1040 | if (Patch.Die == nullptr) |
1041 | return; |
1042 | |
1043 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1044 | }); |
1045 | }); |
1046 | } |
1047 | } |
1048 | |
1049 | void DWARFLinkerImpl::forEachObjectSectionsSet( |
1050 | function_ref<void(OutputSections &)> SectionsSetHandler) { |
1051 | // Handle artificial type unit first. |
1052 | if (ArtificialTypeUnit != nullptr) |
1053 | SectionsSetHandler(*ArtificialTypeUnit); |
1054 | |
1055 | // Then all modules(before regular compilation units). |
1056 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1057 | for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) |
1058 | if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) |
1059 | SectionsSetHandler(*ModuleUnit.Unit); |
1060 | |
1061 | // Finally all compilation units. |
1062 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
1063 | // Handle object file common sections. |
1064 | SectionsSetHandler(*Context); |
1065 | |
1066 | // Handle compilation units. |
1067 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
1068 | if (CU->getStage() != CompileUnit::Stage::Skipped) |
1069 | SectionsSetHandler(*CU); |
1070 | } |
1071 | } |
1072 | |
1073 | void DWARFLinkerImpl::forEachCompileAndTypeUnit( |
1074 | function_ref<void(DwarfUnit *CU)> UnitHandler) { |
1075 | if (ArtificialTypeUnit != nullptr) |
1076 | UnitHandler(ArtificialTypeUnit.get()); |
1077 | |
1078 | // Enumerate module units. |
1079 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1080 | for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) |
1081 | if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) |
1082 | UnitHandler(ModuleUnit.Unit.get()); |
1083 | |
1084 | // Enumerate compile units. |
1085 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1086 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
1087 | if (CU->getStage() != CompileUnit::Stage::Skipped) |
1088 | UnitHandler(CU.get()); |
1089 | } |
1090 | |
1091 | void DWARFLinkerImpl::forEachCompileUnit( |
1092 | function_ref<void(CompileUnit *CU)> UnitHandler) { |
1093 | // Enumerate module units. |
1094 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1095 | for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) |
1096 | if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) |
1097 | UnitHandler(ModuleUnit.Unit.get()); |
1098 | |
1099 | // Enumerate compile units. |
1100 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1101 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
1102 | if (CU->getStage() != CompileUnit::Stage::Skipped) |
1103 | UnitHandler(CU.get()); |
1104 | } |
1105 | |
1106 | void DWARFLinkerImpl::patchOffsetsAndSizes() { |
1107 | forEachObjectSectionsSet(SectionsSetHandler: [&](OutputSections &SectionsSet) { |
1108 | SectionsSet.forEach(Handler: [&](SectionDescriptor &OutSection) { |
1109 | SectionsSet.applyPatches(Section&: OutSection, DebugStrStrings, DebugLineStrStrings, |
1110 | TypeUnitPtr: ArtificialTypeUnit.get()); |
1111 | }); |
1112 | }); |
1113 | } |
1114 | |
1115 | void DWARFLinkerImpl::emitCommonSectionsAndWriteCompileUnitsToTheOutput() { |
1116 | llvm::parallel::TaskGroup TG; |
1117 | |
1118 | // Create section descriptors ahead if they are not exist at the moment. |
1119 | // SectionDescriptors container is not thread safe. Thus we should be sure |
1120 | // that descriptors would not be created in following parallel tasks. |
1121 | |
1122 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugStr); |
1123 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLineStr); |
1124 | |
1125 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1126 | Element: AccelTableKind::Apple)) { |
1127 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::AppleNames); |
1128 | CommonSections.getOrCreateSectionDescriptor( |
1129 | SectionKind: DebugSectionKind::AppleNamespaces); |
1130 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::AppleObjC); |
1131 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::AppleTypes); |
1132 | } |
1133 | |
1134 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1135 | Element: AccelTableKind::DebugNames)) |
1136 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugNames); |
1137 | |
1138 | // Emit .debug_str and .debug_line_str sections. |
1139 | TG.spawn(f: [&]() { emitStringSections(); }); |
1140 | |
1141 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1142 | Element: AccelTableKind::Apple)) { |
1143 | // Emit apple accelerator sections. |
1144 | TG.spawn(f: [&]() { |
1145 | emitAppleAcceleratorSections(TargetTriple: (*GlobalData.getTargetTriple()).get()); |
1146 | }); |
1147 | } |
1148 | |
1149 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1150 | Element: AccelTableKind::DebugNames)) { |
1151 | // Emit .debug_names section. |
1152 | TG.spawn(f: [&]() { |
1153 | emitDWARFv5DebugNamesSection(TargetTriple: (*GlobalData.getTargetTriple()).get()); |
1154 | }); |
1155 | } |
1156 | |
1157 | // Write compile units to the output file. |
1158 | TG.spawn(f: [&]() { writeCompileUnitsToTheOutput(); }); |
1159 | } |
1160 | |
1161 | void DWARFLinkerImpl::emitStringSections() { |
1162 | uint64_t DebugStrNextOffset = 0; |
1163 | uint64_t DebugLineStrNextOffset = 0; |
1164 | |
1165 | // Emit zero length string. Accelerator tables does not work correctly |
1166 | // if the first string is not zero length string. |
1167 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugStr) |
1168 | .emitInplaceString(String: "" ); |
1169 | DebugStrNextOffset++; |
1170 | |
1171 | forEachOutputString( |
1172 | StringHandler: [&](StringDestinationKind Kind, const StringEntry *String) { |
1173 | switch (Kind) { |
1174 | case StringDestinationKind::DebugStr: { |
1175 | DwarfStringPoolEntryWithExtString *StringToEmit = |
1176 | DebugStrStrings.getExistingEntry(String); |
1177 | assert(StringToEmit->isIndexed()); |
1178 | |
1179 | // Strings may be repeated. Use accumulated DebugStrNextOffset |
1180 | // to understand whether corresponding string is already emitted. |
1181 | // Skip string if its offset less than accumulated offset. |
1182 | if (StringToEmit->Offset >= DebugStrNextOffset) { |
1183 | DebugStrNextOffset = |
1184 | StringToEmit->Offset + StringToEmit->String.size() + 1; |
1185 | // Emit the string itself. |
1186 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugStr) |
1187 | .emitInplaceString(String: StringToEmit->String); |
1188 | } |
1189 | } break; |
1190 | case StringDestinationKind::DebugLineStr: { |
1191 | DwarfStringPoolEntryWithExtString *StringToEmit = |
1192 | DebugLineStrStrings.getExistingEntry(String); |
1193 | assert(StringToEmit->isIndexed()); |
1194 | |
1195 | // Strings may be repeated. Use accumulated DebugLineStrStrings |
1196 | // to understand whether corresponding string is already emitted. |
1197 | // Skip string if its offset less than accumulated offset. |
1198 | if (StringToEmit->Offset >= DebugLineStrNextOffset) { |
1199 | DebugLineStrNextOffset = |
1200 | StringToEmit->Offset + StringToEmit->String.size() + 1; |
1201 | // Emit the string itself. |
1202 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugLineStr) |
1203 | .emitInplaceString(String: StringToEmit->String); |
1204 | } |
1205 | } break; |
1206 | } |
1207 | }); |
1208 | } |
1209 | |
1210 | void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) { |
1211 | AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces; |
1212 | AccelTable<AppleAccelTableStaticOffsetData> AppleNames; |
1213 | AccelTable<AppleAccelTableStaticOffsetData> AppleObjC; |
1214 | AccelTable<AppleAccelTableStaticTypeData> AppleTypes; |
1215 | |
1216 | forEachCompileAndTypeUnit(UnitHandler: [&](DwarfUnit *CU) { |
1217 | CU->forEachAcceleratorRecord(Handler: [&](const DwarfUnit::AccelInfo &Info) { |
1218 | uint64_t OutOffset = Info.OutOffset; |
1219 | switch (Info.Type) { |
1220 | case DwarfUnit::AccelType::None: { |
1221 | llvm_unreachable("Unknown accelerator record" ); |
1222 | } break; |
1223 | case DwarfUnit::AccelType::Namespace: { |
1224 | AppleNamespaces.addName( |
1225 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1226 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1227 | OutOffset); |
1228 | } break; |
1229 | case DwarfUnit::AccelType::Name: { |
1230 | AppleNames.addName( |
1231 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1232 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1233 | OutOffset); |
1234 | } break; |
1235 | case DwarfUnit::AccelType::ObjC: { |
1236 | AppleObjC.addName( |
1237 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1238 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1239 | OutOffset); |
1240 | } break; |
1241 | case DwarfUnit::AccelType::Type: { |
1242 | AppleTypes.addName( |
1243 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1244 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1245 | OutOffset, |
1246 | Args: Info.Tag, |
1247 | Args: Info.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation |
1248 | : 0, |
1249 | Args: Info.QualifiedNameHash); |
1250 | } break; |
1251 | } |
1252 | }); |
1253 | }); |
1254 | |
1255 | { |
1256 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1257 | // It might be beneficial to directly emit accelerator data |
1258 | // to the raw_svector_ostream. |
1259 | SectionDescriptor &OutSection = |
1260 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleNamespaces); |
1261 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1262 | OutSection.OS); |
1263 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1264 | consumeError(Err: std::move(Err)); |
1265 | return; |
1266 | } |
1267 | |
1268 | // Emit table. |
1269 | Emitter.emitAppleNamespaces(Table&: AppleNamespaces); |
1270 | Emitter.finish(); |
1271 | |
1272 | // Set start offset and size for output section. |
1273 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1274 | } |
1275 | |
1276 | { |
1277 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1278 | // It might be beneficial to directly emit accelerator data |
1279 | // to the raw_svector_ostream. |
1280 | SectionDescriptor &OutSection = |
1281 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleNames); |
1282 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1283 | OutSection.OS); |
1284 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1285 | consumeError(Err: std::move(Err)); |
1286 | return; |
1287 | } |
1288 | |
1289 | // Emit table. |
1290 | Emitter.emitAppleNames(Table&: AppleNames); |
1291 | Emitter.finish(); |
1292 | |
1293 | // Set start offset ans size for output section. |
1294 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1295 | } |
1296 | |
1297 | { |
1298 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1299 | // It might be beneficial to directly emit accelerator data |
1300 | // to the raw_svector_ostream. |
1301 | SectionDescriptor &OutSection = |
1302 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleObjC); |
1303 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1304 | OutSection.OS); |
1305 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1306 | consumeError(Err: std::move(Err)); |
1307 | return; |
1308 | } |
1309 | |
1310 | // Emit table. |
1311 | Emitter.emitAppleObjc(Table&: AppleObjC); |
1312 | Emitter.finish(); |
1313 | |
1314 | // Set start offset ans size for output section. |
1315 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1316 | } |
1317 | |
1318 | { |
1319 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1320 | // It might be beneficial to directly emit accelerator data |
1321 | // to the raw_svector_ostream. |
1322 | SectionDescriptor &OutSection = |
1323 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleTypes); |
1324 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1325 | OutSection.OS); |
1326 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1327 | consumeError(Err: std::move(Err)); |
1328 | return; |
1329 | } |
1330 | |
1331 | // Emit table. |
1332 | Emitter.emitAppleTypes(Table&: AppleTypes); |
1333 | Emitter.finish(); |
1334 | |
1335 | // Set start offset ans size for output section. |
1336 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1337 | } |
1338 | } |
1339 | |
1340 | void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) { |
1341 | std::unique_ptr<DWARF5AccelTable> DebugNames; |
1342 | |
1343 | DebugNamesUnitsOffsets CompUnits; |
1344 | CompUnitIDToIdx CUidToIdx; |
1345 | |
1346 | unsigned Id = 0; |
1347 | |
1348 | forEachCompileAndTypeUnit(UnitHandler: [&](DwarfUnit *CU) { |
1349 | bool HasRecords = false; |
1350 | CU->forEachAcceleratorRecord(Handler: [&](const DwarfUnit::AccelInfo &Info) { |
1351 | if (DebugNames == nullptr) |
1352 | DebugNames = std::make_unique<DWARF5AccelTable>(); |
1353 | |
1354 | HasRecords = true; |
1355 | switch (Info.Type) { |
1356 | case DwarfUnit::AccelType::Name: |
1357 | case DwarfUnit::AccelType::Namespace: |
1358 | case DwarfUnit::AccelType::Type: { |
1359 | DebugNames->addName(Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1360 | Args: Info.OutOffset, Args: std::nullopt /*ParentDIEOffset*/, |
1361 | Args: Info.Tag, Args: CU->getUniqueID(), |
1362 | Args: CU->getTag() == dwarf::DW_TAG_type_unit); |
1363 | } break; |
1364 | |
1365 | default: |
1366 | break; // Nothing to do. |
1367 | }; |
1368 | }); |
1369 | |
1370 | if (HasRecords) { |
1371 | CompUnits.push_back( |
1372 | x: CU->getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo) |
1373 | .StartOffset); |
1374 | CUidToIdx[CU->getUniqueID()] = Id++; |
1375 | } |
1376 | }); |
1377 | |
1378 | if (DebugNames != nullptr) { |
1379 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1380 | // It might be beneficial to directly emit accelerator data |
1381 | // to the raw_svector_ostream. |
1382 | SectionDescriptor &OutSection = |
1383 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugNames); |
1384 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1385 | OutSection.OS); |
1386 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1387 | consumeError(Err: std::move(Err)); |
1388 | return; |
1389 | } |
1390 | |
1391 | // Emit table. |
1392 | Emitter.emitDebugNames(Table&: *DebugNames, CUOffsets&: CompUnits, UnitIDToIdxMap&: CUidToIdx); |
1393 | Emitter.finish(); |
1394 | |
1395 | // Set start offset ans size for output section. |
1396 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1397 | } |
1398 | } |
1399 | |
1400 | void DWARFLinkerImpl::cleanupDataAfterDWARFOutputIsWritten() { |
1401 | GlobalData.getStringPool().clear(); |
1402 | DebugStrStrings.clear(); |
1403 | DebugLineStrStrings.clear(); |
1404 | } |
1405 | |
1406 | void DWARFLinkerImpl::writeCompileUnitsToTheOutput() { |
1407 | // Enumerate all sections and store them into the final emitter. |
1408 | forEachObjectSectionsSet(SectionsSetHandler: [&](OutputSections &Sections) { |
1409 | Sections.forEach(Handler: [&](std::shared_ptr<SectionDescriptor> OutSection) { |
1410 | // Emit section content. |
1411 | SectionHandler(OutSection); |
1412 | }); |
1413 | }); |
1414 | } |
1415 | |
1416 | void DWARFLinkerImpl::writeCommonSectionsToTheOutput() { |
1417 | CommonSections.forEach(Handler: [&](std::shared_ptr<SectionDescriptor> OutSection) { |
1418 | SectionHandler(OutSection); |
1419 | }); |
1420 | } |
1421 | |