1 | //===-- llvm-dwp.cpp - Split DWARF merging tool for llvm ------------------===// |
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 | // A utility for merging DWARF 5 Split DWARF .dwo files into .dwp (DWARF |
10 | // package files). |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | #include "llvm/DWP/DWP.h" |
14 | #include "llvm/ADT/Twine.h" |
15 | #include "llvm/DWP/DWPError.h" |
16 | #include "llvm/MC/MCContext.h" |
17 | #include "llvm/MC/MCObjectFileInfo.h" |
18 | #include "llvm/MC/MCTargetOptionsCommandFlags.h" |
19 | #include "llvm/Object/Decompressor.h" |
20 | #include "llvm/Object/ELFObjectFile.h" |
21 | #include "llvm/Support/CommandLine.h" |
22 | #include "llvm/Support/MemoryBuffer.h" |
23 | #include <limits> |
24 | |
25 | using namespace llvm; |
26 | using namespace llvm::object; |
27 | |
28 | static mc::RegisterMCTargetOptionsFlags MCTargetOptionsFlags; |
29 | |
30 | // Returns the size of debug_str_offsets section headers in bytes. |
31 | static uint64_t (DataExtractor StrOffsetsData, |
32 | uint16_t DwarfVersion) { |
33 | if (DwarfVersion <= 4) |
34 | return 0; // There is no header before dwarf 5. |
35 | uint64_t Offset = 0; |
36 | uint64_t Length = StrOffsetsData.getU32(offset_ptr: &Offset); |
37 | if (Length == llvm::dwarf::DW_LENGTH_DWARF64) |
38 | return 16; // unit length: 12 bytes, version: 2 bytes, padding: 2 bytes. |
39 | return 8; // unit length: 4 bytes, version: 2 bytes, padding: 2 bytes. |
40 | } |
41 | |
42 | static uint64_t getCUAbbrev(StringRef Abbrev, uint64_t AbbrCode) { |
43 | uint64_t Offset = 0; |
44 | DataExtractor AbbrevData(Abbrev, true, 0); |
45 | while (AbbrevData.getULEB128(offset_ptr: &Offset) != AbbrCode) { |
46 | // Tag |
47 | AbbrevData.getULEB128(offset_ptr: &Offset); |
48 | // DW_CHILDREN |
49 | AbbrevData.getU8(offset_ptr: &Offset); |
50 | // Attributes |
51 | while (AbbrevData.getULEB128(offset_ptr: &Offset) | AbbrevData.getULEB128(offset_ptr: &Offset)) |
52 | ; |
53 | } |
54 | return Offset; |
55 | } |
56 | |
57 | static Expected<const char *> |
58 | (dwarf::Form Form, DataExtractor InfoData, uint64_t &InfoOffset, |
59 | StringRef StrOffsets, StringRef Str, uint16_t Version) { |
60 | if (Form == dwarf::DW_FORM_string) |
61 | return InfoData.getCStr(OffsetPtr: &InfoOffset); |
62 | uint64_t StrIndex; |
63 | switch (Form) { |
64 | case dwarf::DW_FORM_strx1: |
65 | StrIndex = InfoData.getU8(offset_ptr: &InfoOffset); |
66 | break; |
67 | case dwarf::DW_FORM_strx2: |
68 | StrIndex = InfoData.getU16(offset_ptr: &InfoOffset); |
69 | break; |
70 | case dwarf::DW_FORM_strx3: |
71 | StrIndex = InfoData.getU24(OffsetPtr: &InfoOffset); |
72 | break; |
73 | case dwarf::DW_FORM_strx4: |
74 | StrIndex = InfoData.getU32(offset_ptr: &InfoOffset); |
75 | break; |
76 | case dwarf::DW_FORM_strx: |
77 | case dwarf::DW_FORM_GNU_str_index: |
78 | StrIndex = InfoData.getULEB128(offset_ptr: &InfoOffset); |
79 | break; |
80 | default: |
81 | return make_error<DWPError>( |
82 | Args: "string field must be encoded with one of the following: " |
83 | "DW_FORM_string, DW_FORM_strx, DW_FORM_strx1, DW_FORM_strx2, " |
84 | "DW_FORM_strx3, DW_FORM_strx4, or DW_FORM_GNU_str_index." ); |
85 | } |
86 | DataExtractor StrOffsetsData(StrOffsets, true, 0); |
87 | uint64_t StrOffsetsOffset = 4 * StrIndex; |
88 | StrOffsetsOffset += debugStrOffsetsHeaderSize(StrOffsetsData, DwarfVersion: Version); |
89 | |
90 | uint64_t StrOffset = StrOffsetsData.getU32(offset_ptr: &StrOffsetsOffset); |
91 | DataExtractor StrData(Str, true, 0); |
92 | return StrData.getCStr(OffsetPtr: &StrOffset); |
93 | } |
94 | |
95 | static Expected<CompileUnitIdentifiers> |
96 | (InfoSectionUnitHeader &, StringRef Abbrev, |
97 | StringRef Info, StringRef StrOffsets, StringRef Str) { |
98 | DataExtractor InfoData(Info, true, 0); |
99 | uint64_t Offset = Header.HeaderSize; |
100 | if (Header.Version >= 5 && Header.UnitType != dwarf::DW_UT_split_compile) |
101 | return make_error<DWPError>( |
102 | Args: std::string("unit type DW_UT_split_compile type not found in " |
103 | "debug_info header. Unexpected unit type 0x" + |
104 | utostr(X: Header.UnitType) + " found" )); |
105 | |
106 | CompileUnitIdentifiers ID; |
107 | |
108 | uint32_t AbbrCode = InfoData.getULEB128(offset_ptr: &Offset); |
109 | DataExtractor AbbrevData(Abbrev, true, 0); |
110 | uint64_t AbbrevOffset = getCUAbbrev(Abbrev, AbbrCode); |
111 | auto Tag = static_cast<dwarf::Tag>(AbbrevData.getULEB128(offset_ptr: &AbbrevOffset)); |
112 | if (Tag != dwarf::DW_TAG_compile_unit) |
113 | return make_error<DWPError>(Args: "top level DIE is not a compile unit" ); |
114 | // DW_CHILDREN |
115 | AbbrevData.getU8(offset_ptr: &AbbrevOffset); |
116 | uint32_t Name; |
117 | dwarf::Form Form; |
118 | while ((Name = AbbrevData.getULEB128(offset_ptr: &AbbrevOffset)) | |
119 | (Form = static_cast<dwarf::Form>( |
120 | AbbrevData.getULEB128(offset_ptr: &AbbrevOffset))) && |
121 | (Name != 0 || Form != 0)) { |
122 | switch (Name) { |
123 | case dwarf::DW_AT_name: { |
124 | Expected<const char *> EName = getIndexedString( |
125 | Form, InfoData, InfoOffset&: Offset, StrOffsets, Str, Version: Header.Version); |
126 | if (!EName) |
127 | return EName.takeError(); |
128 | ID.Name = *EName; |
129 | break; |
130 | } |
131 | case dwarf::DW_AT_GNU_dwo_name: |
132 | case dwarf::DW_AT_dwo_name: { |
133 | Expected<const char *> EName = getIndexedString( |
134 | Form, InfoData, InfoOffset&: Offset, StrOffsets, Str, Version: Header.Version); |
135 | if (!EName) |
136 | return EName.takeError(); |
137 | ID.DWOName = *EName; |
138 | break; |
139 | } |
140 | case dwarf::DW_AT_GNU_dwo_id: |
141 | Header.Signature = InfoData.getU64(offset_ptr: &Offset); |
142 | break; |
143 | default: |
144 | DWARFFormValue::skipValue( |
145 | Form, DebugInfoData: InfoData, OffsetPtr: &Offset, |
146 | FormParams: dwarf::FormParams({.Version: Header.Version, .AddrSize: Header.AddrSize, .Format: Header.Format})); |
147 | } |
148 | } |
149 | if (!Header.Signature) |
150 | return make_error<DWPError>(Args: "compile unit missing dwo_id" ); |
151 | ID.Signature = *Header.Signature; |
152 | return ID; |
153 | } |
154 | |
155 | static bool isSupportedSectionKind(DWARFSectionKind Kind) { |
156 | return Kind != DW_SECT_EXT_unknown; |
157 | } |
158 | |
159 | namespace llvm { |
160 | // Convert an internal section identifier into the index to use with |
161 | // UnitIndexEntry::Contributions. |
162 | unsigned getContributionIndex(DWARFSectionKind Kind, uint32_t IndexVersion) { |
163 | assert(serializeSectionKind(Kind, IndexVersion) >= DW_SECT_INFO); |
164 | return serializeSectionKind(Kind, IndexVersion) - DW_SECT_INFO; |
165 | } |
166 | } // namespace llvm |
167 | |
168 | // Convert a UnitIndexEntry::Contributions index to the corresponding on-disk |
169 | // value of the section identifier. |
170 | static unsigned getOnDiskSectionId(unsigned Index) { |
171 | return Index + DW_SECT_INFO; |
172 | } |
173 | |
174 | static StringRef getSubsection(StringRef Section, |
175 | const DWARFUnitIndex::Entry &Entry, |
176 | DWARFSectionKind Kind) { |
177 | const auto *Off = Entry.getContribution(Sec: Kind); |
178 | if (!Off) |
179 | return StringRef(); |
180 | return Section.substr(Start: Off->getOffset(), N: Off->getLength()); |
181 | } |
182 | |
183 | static Error sectionOverflowErrorOrWarning(uint32_t PrevOffset, |
184 | uint32_t OverflowedOffset, |
185 | StringRef SectionName, |
186 | OnCuIndexOverflow OverflowOptValue, |
187 | bool &AnySectionOverflow) { |
188 | std::string Msg = |
189 | (SectionName + |
190 | Twine(" Section Contribution Offset overflow 4G. Previous Offset " ) + |
191 | Twine(PrevOffset) + Twine(", After overflow offset " ) + |
192 | Twine(OverflowedOffset) + Twine("." )) |
193 | .str(); |
194 | if (OverflowOptValue == OnCuIndexOverflow::Continue) { |
195 | WithColor::defaultWarningHandler(Warning: make_error<DWPError>(Args&: Msg)); |
196 | return Error::success(); |
197 | } else if (OverflowOptValue == OnCuIndexOverflow::SoftStop) { |
198 | AnySectionOverflow = true; |
199 | WithColor::defaultWarningHandler(Warning: make_error<DWPError>(Args&: Msg)); |
200 | return Error::success(); |
201 | } |
202 | return make_error<DWPError>(Args&: Msg); |
203 | } |
204 | |
205 | static Error addAllTypesFromDWP( |
206 | MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries, |
207 | const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types, |
208 | const UnitIndexEntry &TUEntry, uint32_t &TypesOffset, |
209 | unsigned TypesContributionIndex, OnCuIndexOverflow OverflowOptValue, |
210 | bool &AnySectionOverflow) { |
211 | Out.switchSection(Section: OutputTypes); |
212 | for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) { |
213 | auto *I = E.getContributions(); |
214 | if (!I) |
215 | continue; |
216 | auto P = TypeIndexEntries.insert(KV: std::make_pair(x: E.getSignature(), y: TUEntry)); |
217 | if (!P.second) |
218 | continue; |
219 | auto &Entry = P.first->second; |
220 | // Zero out the debug_info contribution |
221 | Entry.Contributions[0] = {}; |
222 | for (auto Kind : TUIndex.getColumnKinds()) { |
223 | if (!isSupportedSectionKind(Kind)) |
224 | continue; |
225 | auto &C = |
226 | Entry.Contributions[getContributionIndex(Kind, IndexVersion: TUIndex.getVersion())]; |
227 | C.setOffset(C.getOffset() + I->getOffset()); |
228 | C.setLength(I->getLength()); |
229 | ++I; |
230 | } |
231 | auto &C = Entry.Contributions[TypesContributionIndex]; |
232 | Out.emitBytes(Data: Types.substr( |
233 | Start: C.getOffset() - |
234 | TUEntry.Contributions[TypesContributionIndex].getOffset(), |
235 | N: C.getLength())); |
236 | C.setOffset(TypesOffset); |
237 | uint32_t OldOffset = TypesOffset; |
238 | static_assert(sizeof(OldOffset) == sizeof(TypesOffset)); |
239 | TypesOffset += C.getLength(); |
240 | if (OldOffset > TypesOffset) { |
241 | if (Error Err = sectionOverflowErrorOrWarning(PrevOffset: OldOffset, OverflowedOffset: TypesOffset, |
242 | SectionName: "Types" , OverflowOptValue, |
243 | AnySectionOverflow)) |
244 | return Err; |
245 | if (AnySectionOverflow) { |
246 | TypesOffset = OldOffset; |
247 | return Error::success(); |
248 | } |
249 | } |
250 | } |
251 | return Error::success(); |
252 | } |
253 | |
254 | static Error addAllTypesFromTypesSection( |
255 | MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries, |
256 | MCSection *OutputTypes, const std::vector<StringRef> &TypesSections, |
257 | const UnitIndexEntry &CUEntry, uint32_t &TypesOffset, |
258 | OnCuIndexOverflow OverflowOptValue, bool &AnySectionOverflow) { |
259 | for (StringRef Types : TypesSections) { |
260 | Out.switchSection(Section: OutputTypes); |
261 | uint64_t Offset = 0; |
262 | DataExtractor Data(Types, true, 0); |
263 | while (Data.isValidOffset(offset: Offset)) { |
264 | UnitIndexEntry Entry = CUEntry; |
265 | // Zero out the debug_info contribution |
266 | Entry.Contributions[0] = {}; |
267 | auto &C = Entry.Contributions[getContributionIndex(Kind: DW_SECT_EXT_TYPES, IndexVersion: 2)]; |
268 | C.setOffset(TypesOffset); |
269 | auto PrevOffset = Offset; |
270 | // Length of the unit, including the 4 byte length field. |
271 | C.setLength(Data.getU32(offset_ptr: &Offset) + 4); |
272 | |
273 | Data.getU16(offset_ptr: &Offset); // Version |
274 | Data.getU32(offset_ptr: &Offset); // Abbrev offset |
275 | Data.getU8(offset_ptr: &Offset); // Address size |
276 | auto Signature = Data.getU64(offset_ptr: &Offset); |
277 | Offset = PrevOffset + C.getLength32(); |
278 | |
279 | auto P = TypeIndexEntries.insert(KV: std::make_pair(x&: Signature, y&: Entry)); |
280 | if (!P.second) |
281 | continue; |
282 | |
283 | Out.emitBytes(Data: Types.substr(Start: PrevOffset, N: C.getLength32())); |
284 | uint32_t OldOffset = TypesOffset; |
285 | TypesOffset += C.getLength32(); |
286 | if (OldOffset > TypesOffset) { |
287 | if (Error Err = sectionOverflowErrorOrWarning(PrevOffset: OldOffset, OverflowedOffset: TypesOffset, |
288 | SectionName: "Types" , OverflowOptValue, |
289 | AnySectionOverflow)) |
290 | return Err; |
291 | if (AnySectionOverflow) { |
292 | TypesOffset = OldOffset; |
293 | return Error::success(); |
294 | } |
295 | } |
296 | } |
297 | } |
298 | return Error::success(); |
299 | } |
300 | |
301 | static std::string buildDWODescription(StringRef Name, StringRef DWPName, |
302 | StringRef DWOName) { |
303 | std::string Text = "\'" ; |
304 | Text += Name; |
305 | Text += '\''; |
306 | bool HasDWO = !DWOName.empty(); |
307 | bool HasDWP = !DWPName.empty(); |
308 | if (HasDWO || HasDWP) { |
309 | Text += " (from " ; |
310 | if (HasDWO) { |
311 | Text += '\''; |
312 | Text += DWOName; |
313 | Text += '\''; |
314 | } |
315 | if (HasDWO && HasDWP) |
316 | Text += " in " ; |
317 | if (!DWPName.empty()) { |
318 | Text += '\''; |
319 | Text += DWPName; |
320 | Text += '\''; |
321 | } |
322 | Text += ")" ; |
323 | } |
324 | return Text; |
325 | } |
326 | |
327 | static Error createError(StringRef Name, Error E) { |
328 | return make_error<DWPError>( |
329 | Args: ("failure while decompressing compressed section: '" + Name + "', " + |
330 | llvm::toString(E: std::move(E))) |
331 | .str()); |
332 | } |
333 | |
334 | static Error |
335 | handleCompressedSection(std::deque<SmallString<32>> &UncompressedSections, |
336 | SectionRef Sec, StringRef Name, StringRef &Contents) { |
337 | auto *Obj = dyn_cast<ELFObjectFileBase>(Val: Sec.getObject()); |
338 | if (!Obj || |
339 | !(static_cast<ELFSectionRef>(Sec).getFlags() & ELF::SHF_COMPRESSED)) |
340 | return Error::success(); |
341 | bool IsLE = isa<object::ELF32LEObjectFile>(Val: Obj) || |
342 | isa<object::ELF64LEObjectFile>(Val: Obj); |
343 | bool Is64 = isa<object::ELF64LEObjectFile>(Val: Obj) || |
344 | isa<object::ELF64BEObjectFile>(Val: Obj); |
345 | Expected<Decompressor> Dec = Decompressor::create(Name, Data: Contents, IsLE, Is64Bit: Is64); |
346 | if (!Dec) |
347 | return createError(Name, E: Dec.takeError()); |
348 | |
349 | UncompressedSections.emplace_back(); |
350 | if (Error E = Dec->resizeAndDecompress(Out&: UncompressedSections.back())) |
351 | return createError(Name, E: std::move(E)); |
352 | |
353 | Contents = UncompressedSections.back(); |
354 | return Error::success(); |
355 | } |
356 | |
357 | namespace llvm { |
358 | // Parse and return the header of an info section compile/type unit. |
359 | Expected<InfoSectionUnitHeader> (StringRef Info) { |
360 | InfoSectionUnitHeader ; |
361 | Error Err = Error::success(); |
362 | uint64_t Offset = 0; |
363 | DWARFDataExtractor InfoData(Info, true, 0); |
364 | std::tie(args&: Header.Length, args&: Header.Format) = |
365 | InfoData.getInitialLength(Off: &Offset, Err: &Err); |
366 | if (Err) |
367 | return make_error<DWPError>(Args: "cannot parse compile unit length: " + |
368 | llvm::toString(E: std::move(Err))); |
369 | |
370 | if (!InfoData.isValidOffset(offset: Offset + (Header.Length - 1))) { |
371 | return make_error<DWPError>( |
372 | Args: "compile unit exceeds .debug_info section range: " + |
373 | utostr(X: Offset + Header.Length) + " >= " + utostr(X: InfoData.size())); |
374 | } |
375 | |
376 | Header.Version = InfoData.getU16(offset_ptr: &Offset, Err: &Err); |
377 | if (Err) |
378 | return make_error<DWPError>(Args: "cannot parse compile unit version: " + |
379 | llvm::toString(E: std::move(Err))); |
380 | |
381 | uint64_t ; |
382 | if (Header.Version >= 5) { |
383 | // Size: Version (2), UnitType (1), AddrSize (1), DebugAbbrevOffset (4), |
384 | // Signature (8) |
385 | MinHeaderLength = 16; |
386 | } else { |
387 | // Size: Version (2), DebugAbbrevOffset (4), AddrSize (1) |
388 | MinHeaderLength = 7; |
389 | } |
390 | if (Header.Length < MinHeaderLength) { |
391 | return make_error<DWPError>(Args: "unit length is too small: expected at least " + |
392 | utostr(X: MinHeaderLength) + " got " + |
393 | utostr(X: Header.Length) + "." ); |
394 | } |
395 | if (Header.Version >= 5) { |
396 | Header.UnitType = InfoData.getU8(offset_ptr: &Offset); |
397 | Header.AddrSize = InfoData.getU8(offset_ptr: &Offset); |
398 | Header.DebugAbbrevOffset = InfoData.getU32(offset_ptr: &Offset); |
399 | Header.Signature = InfoData.getU64(offset_ptr: &Offset); |
400 | if (Header.UnitType == dwarf::DW_UT_split_type) { |
401 | // Type offset. |
402 | MinHeaderLength += 4; |
403 | if (Header.Length < MinHeaderLength) |
404 | return make_error<DWPError>(Args: "type unit is missing type offset" ); |
405 | InfoData.getU32(offset_ptr: &Offset); |
406 | } |
407 | } else { |
408 | // Note that, address_size and debug_abbrev_offset fields have switched |
409 | // places between dwarf version 4 and 5. |
410 | Header.DebugAbbrevOffset = InfoData.getU32(offset_ptr: &Offset); |
411 | Header.AddrSize = InfoData.getU8(offset_ptr: &Offset); |
412 | } |
413 | |
414 | Header.HeaderSize = Offset; |
415 | return Header; |
416 | } |
417 | |
418 | static void (MCStreamer &Out, DataExtractor &Data, |
419 | DenseMap<uint64_t, uint32_t> &OffsetRemapping, |
420 | uint64_t &Offset, uint64_t &Size) { |
421 | |
422 | while (Offset < Size) { |
423 | auto OldOffset = Data.getU32(offset_ptr: &Offset); |
424 | auto NewOffset = OffsetRemapping[OldOffset]; |
425 | Out.emitIntValue(Value: NewOffset, Size: 4); |
426 | } |
427 | } |
428 | |
429 | void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings, |
430 | MCSection *StrOffsetSection, |
431 | StringRef CurStrSection, |
432 | StringRef CurStrOffsetSection, uint16_t Version) { |
433 | // Could possibly produce an error or warning if one of these was non-null but |
434 | // the other was null. |
435 | if (CurStrSection.empty() || CurStrOffsetSection.empty()) |
436 | return; |
437 | |
438 | DenseMap<uint64_t, uint32_t> OffsetRemapping; |
439 | |
440 | DataExtractor Data(CurStrSection, true, 0); |
441 | uint64_t LocalOffset = 0; |
442 | uint64_t PrevOffset = 0; |
443 | while (const char *S = Data.getCStr(OffsetPtr: &LocalOffset)) { |
444 | OffsetRemapping[PrevOffset] = |
445 | Strings.getOffset(Str: S, Length: LocalOffset - PrevOffset); |
446 | PrevOffset = LocalOffset; |
447 | } |
448 | |
449 | Data = DataExtractor(CurStrOffsetSection, true, 0); |
450 | |
451 | Out.switchSection(Section: StrOffsetSection); |
452 | |
453 | uint64_t Offset = 0; |
454 | uint64_t Size = CurStrOffsetSection.size(); |
455 | if (Version > 4) { |
456 | while (Offset < Size) { |
457 | uint64_t = debugStrOffsetsHeaderSize(StrOffsetsData: Data, DwarfVersion: Version); |
458 | assert(HeaderSize <= Size - Offset && |
459 | "StrOffsetSection size is less than its header" ); |
460 | |
461 | uint64_t ContributionEnd = 0; |
462 | uint64_t ContributionSize = 0; |
463 | uint64_t = Offset; |
464 | if (HeaderSize == 8) { |
465 | ContributionSize = Data.getU32(offset_ptr: &HeaderLengthOffset); |
466 | } else if (HeaderSize == 16) { |
467 | HeaderLengthOffset += 4; // skip the dwarf64 marker |
468 | ContributionSize = Data.getU64(offset_ptr: &HeaderLengthOffset); |
469 | } |
470 | ContributionEnd = ContributionSize + HeaderLengthOffset; |
471 | Out.emitBytes(Data: Data.getBytes(OffsetPtr: &Offset, Length: HeaderSize)); |
472 | writeNewOffsetsTo(Out, Data, OffsetRemapping, Offset, Size&: ContributionEnd); |
473 | } |
474 | |
475 | } else { |
476 | writeNewOffsetsTo(Out, Data, OffsetRemapping, Offset, Size); |
477 | } |
478 | } |
479 | |
480 | enum AccessField { Offset, Length }; |
481 | void writeIndexTable(MCStreamer &Out, ArrayRef<unsigned> ContributionOffsets, |
482 | const MapVector<uint64_t, UnitIndexEntry> &IndexEntries, |
483 | const AccessField &Field) { |
484 | for (const auto &E : IndexEntries) |
485 | for (size_t I = 0; I != std::size(E.second.Contributions); ++I) |
486 | if (ContributionOffsets[I]) |
487 | Out.emitIntValue(Value: (Field == AccessField::Offset |
488 | ? E.second.Contributions[I].getOffset32() |
489 | : E.second.Contributions[I].getLength32()), |
490 | Size: 4); |
491 | } |
492 | |
493 | void writeIndex(MCStreamer &Out, MCSection *Section, |
494 | ArrayRef<unsigned> ContributionOffsets, |
495 | const MapVector<uint64_t, UnitIndexEntry> &IndexEntries, |
496 | uint32_t IndexVersion) { |
497 | if (IndexEntries.empty()) |
498 | return; |
499 | |
500 | unsigned Columns = 0; |
501 | for (auto &C : ContributionOffsets) |
502 | if (C) |
503 | ++Columns; |
504 | |
505 | std::vector<unsigned> Buckets(NextPowerOf2(A: 3 * IndexEntries.size() / 2)); |
506 | uint64_t Mask = Buckets.size() - 1; |
507 | size_t I = 0; |
508 | for (const auto &P : IndexEntries) { |
509 | auto S = P.first; |
510 | auto H = S & Mask; |
511 | auto HP = ((S >> 32) & Mask) | 1; |
512 | while (Buckets[H]) { |
513 | assert(S != IndexEntries.begin()[Buckets[H] - 1].first && |
514 | "Duplicate unit" ); |
515 | H = (H + HP) & Mask; |
516 | } |
517 | Buckets[H] = I + 1; |
518 | ++I; |
519 | } |
520 | |
521 | Out.switchSection(Section); |
522 | Out.emitIntValue(Value: IndexVersion, Size: 4); // Version |
523 | Out.emitIntValue(Value: Columns, Size: 4); // Columns |
524 | Out.emitIntValue(Value: IndexEntries.size(), Size: 4); // Num Units |
525 | Out.emitIntValue(Value: Buckets.size(), Size: 4); // Num Buckets |
526 | |
527 | // Write the signatures. |
528 | for (const auto &I : Buckets) |
529 | Out.emitIntValue(Value: I ? IndexEntries.begin()[I - 1].first : 0, Size: 8); |
530 | |
531 | // Write the indexes. |
532 | for (const auto &I : Buckets) |
533 | Out.emitIntValue(Value: I, Size: 4); |
534 | |
535 | // Write the column headers (which sections will appear in the table) |
536 | for (size_t I = 0; I != ContributionOffsets.size(); ++I) |
537 | if (ContributionOffsets[I]) |
538 | Out.emitIntValue(Value: getOnDiskSectionId(Index: I), Size: 4); |
539 | |
540 | // Write the offsets. |
541 | writeIndexTable(Out, ContributionOffsets, IndexEntries, Field: AccessField::Offset); |
542 | |
543 | // Write the lengths. |
544 | writeIndexTable(Out, ContributionOffsets, IndexEntries, Field: AccessField::Length); |
545 | } |
546 | |
547 | Error buildDuplicateError(const std::pair<uint64_t, UnitIndexEntry> &PrevE, |
548 | const CompileUnitIdentifiers &ID, StringRef DWPName) { |
549 | return make_error<DWPError>( |
550 | Args: std::string("duplicate DWO ID (" ) + utohexstr(X: PrevE.first) + ") in " + |
551 | buildDWODescription(Name: PrevE.second.Name, DWPName: PrevE.second.DWPName, |
552 | DWOName: PrevE.second.DWOName) + |
553 | " and " + buildDWODescription(Name: ID.Name, DWPName, DWOName: ID.DWOName)); |
554 | } |
555 | |
556 | Error handleSection( |
557 | const StringMap<std::pair<MCSection *, DWARFSectionKind>> &KnownSections, |
558 | const MCSection *StrSection, const MCSection *StrOffsetSection, |
559 | const MCSection *TypesSection, const MCSection *CUIndexSection, |
560 | const MCSection *TUIndexSection, const MCSection *InfoSection, |
561 | const SectionRef &Section, MCStreamer &Out, |
562 | std::deque<SmallString<32>> &UncompressedSections, |
563 | uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry, |
564 | StringRef &CurStrSection, StringRef &CurStrOffsetSection, |
565 | std::vector<StringRef> &CurTypesSection, |
566 | std::vector<StringRef> &CurInfoSection, StringRef &AbbrevSection, |
567 | StringRef &CurCUIndexSection, StringRef &CurTUIndexSection, |
568 | std::vector<std::pair<DWARFSectionKind, uint32_t>> &SectionLength) { |
569 | if (Section.isBSS()) |
570 | return Error::success(); |
571 | |
572 | if (Section.isVirtual()) |
573 | return Error::success(); |
574 | |
575 | Expected<StringRef> NameOrErr = Section.getName(); |
576 | if (!NameOrErr) |
577 | return NameOrErr.takeError(); |
578 | StringRef Name = *NameOrErr; |
579 | |
580 | Expected<StringRef> ContentsOrErr = Section.getContents(); |
581 | if (!ContentsOrErr) |
582 | return ContentsOrErr.takeError(); |
583 | StringRef Contents = *ContentsOrErr; |
584 | |
585 | if (auto Err = handleCompressedSection(UncompressedSections, Sec: Section, Name, |
586 | Contents)) |
587 | return Err; |
588 | |
589 | Name = Name.substr(Start: Name.find_first_not_of(Chars: "._" )); |
590 | |
591 | auto SectionPair = KnownSections.find(Key: Name); |
592 | if (SectionPair == KnownSections.end()) |
593 | return Error::success(); |
594 | |
595 | if (DWARFSectionKind Kind = SectionPair->second.second) { |
596 | if (Kind != DW_SECT_EXT_TYPES && Kind != DW_SECT_INFO) { |
597 | SectionLength.push_back(x: std::make_pair(x&: Kind, y: Contents.size())); |
598 | } |
599 | |
600 | if (Kind == DW_SECT_ABBREV) { |
601 | AbbrevSection = Contents; |
602 | } |
603 | } |
604 | |
605 | MCSection *OutSection = SectionPair->second.first; |
606 | if (OutSection == StrOffsetSection) |
607 | CurStrOffsetSection = Contents; |
608 | else if (OutSection == StrSection) |
609 | CurStrSection = Contents; |
610 | else if (OutSection == TypesSection) |
611 | CurTypesSection.push_back(x: Contents); |
612 | else if (OutSection == CUIndexSection) |
613 | CurCUIndexSection = Contents; |
614 | else if (OutSection == TUIndexSection) |
615 | CurTUIndexSection = Contents; |
616 | else if (OutSection == InfoSection) |
617 | CurInfoSection.push_back(x: Contents); |
618 | else { |
619 | Out.switchSection(Section: OutSection); |
620 | Out.emitBytes(Data: Contents); |
621 | } |
622 | return Error::success(); |
623 | } |
624 | |
625 | Error write(MCStreamer &Out, ArrayRef<std::string> Inputs, |
626 | OnCuIndexOverflow OverflowOptValue) { |
627 | const auto &MCOFI = *Out.getContext().getObjectFileInfo(); |
628 | MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); |
629 | MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); |
630 | MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection(); |
631 | MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection(); |
632 | MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection(); |
633 | MCSection *const InfoSection = MCOFI.getDwarfInfoDWOSection(); |
634 | const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = { |
635 | {"debug_info.dwo" , {InfoSection, DW_SECT_INFO}}, |
636 | {"debug_types.dwo" , {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}}, |
637 | {"debug_str_offsets.dwo" , {StrOffsetSection, DW_SECT_STR_OFFSETS}}, |
638 | {"debug_str.dwo" , {StrSection, static_cast<DWARFSectionKind>(0)}}, |
639 | {"debug_loc.dwo" , {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}}, |
640 | {"debug_line.dwo" , {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, |
641 | {"debug_macro.dwo" , {MCOFI.getDwarfMacroDWOSection(), DW_SECT_MACRO}}, |
642 | {"debug_abbrev.dwo" , {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, |
643 | {"debug_loclists.dwo" , |
644 | {MCOFI.getDwarfLoclistsDWOSection(), DW_SECT_LOCLISTS}}, |
645 | {"debug_rnglists.dwo" , |
646 | {MCOFI.getDwarfRnglistsDWOSection(), DW_SECT_RNGLISTS}}, |
647 | {"debug_cu_index" , {CUIndexSection, static_cast<DWARFSectionKind>(0)}}, |
648 | {"debug_tu_index" , {TUIndexSection, static_cast<DWARFSectionKind>(0)}}}; |
649 | |
650 | MapVector<uint64_t, UnitIndexEntry> IndexEntries; |
651 | MapVector<uint64_t, UnitIndexEntry> TypeIndexEntries; |
652 | |
653 | uint32_t ContributionOffsets[8] = {}; |
654 | uint16_t Version = 0; |
655 | uint32_t IndexVersion = 0; |
656 | bool AnySectionOverflow = false; |
657 | |
658 | DWPStringPool Strings(Out, StrSection); |
659 | |
660 | SmallVector<OwningBinary<object::ObjectFile>, 128> Objects; |
661 | Objects.reserve(N: Inputs.size()); |
662 | |
663 | std::deque<SmallString<32>> UncompressedSections; |
664 | |
665 | for (const auto &Input : Inputs) { |
666 | auto ErrOrObj = object::ObjectFile::createObjectFile(ObjectPath: Input); |
667 | if (!ErrOrObj) { |
668 | return handleErrors(E: ErrOrObj.takeError(), |
669 | Hs: [&](std::unique_ptr<ECError> EC) -> Error { |
670 | return createFileError(F: Input, E: Error(std::move(EC))); |
671 | }); |
672 | } |
673 | |
674 | auto &Obj = *ErrOrObj->getBinary(); |
675 | Objects.push_back(Elt: std::move(*ErrOrObj)); |
676 | |
677 | UnitIndexEntry CurEntry = {}; |
678 | |
679 | StringRef CurStrSection; |
680 | StringRef CurStrOffsetSection; |
681 | std::vector<StringRef> CurTypesSection; |
682 | std::vector<StringRef> CurInfoSection; |
683 | StringRef AbbrevSection; |
684 | StringRef CurCUIndexSection; |
685 | StringRef CurTUIndexSection; |
686 | |
687 | // This maps each section contained in this file to its length. |
688 | // This information is later on used to calculate the contributions, |
689 | // i.e. offset and length, of each compile/type unit to a section. |
690 | std::vector<std::pair<DWARFSectionKind, uint32_t>> SectionLength; |
691 | |
692 | for (const auto &Section : Obj.sections()) |
693 | if (auto Err = handleSection( |
694 | KnownSections, StrSection, StrOffsetSection, TypesSection, |
695 | CUIndexSection, TUIndexSection, InfoSection, Section, Out, |
696 | UncompressedSections, ContributionOffsets, CurEntry, |
697 | CurStrSection, CurStrOffsetSection, CurTypesSection, |
698 | CurInfoSection, AbbrevSection, CurCUIndexSection, |
699 | CurTUIndexSection, SectionLength)) |
700 | return Err; |
701 | |
702 | if (CurInfoSection.empty()) |
703 | continue; |
704 | |
705 | Expected<InfoSectionUnitHeader> = |
706 | parseInfoSectionUnitHeader(Info: CurInfoSection.front()); |
707 | if (!HeaderOrErr) |
708 | return HeaderOrErr.takeError(); |
709 | InfoSectionUnitHeader & = *HeaderOrErr; |
710 | |
711 | if (Version == 0) { |
712 | Version = Header.Version; |
713 | IndexVersion = Version < 5 ? 2 : 5; |
714 | } else if (Version != Header.Version) { |
715 | return make_error<DWPError>(Args: "incompatible DWARF compile unit versions." ); |
716 | } |
717 | |
718 | writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection, |
719 | CurStrOffsetSection, Version: Header.Version); |
720 | |
721 | for (auto Pair : SectionLength) { |
722 | auto Index = getContributionIndex(Kind: Pair.first, IndexVersion); |
723 | CurEntry.Contributions[Index].setOffset(ContributionOffsets[Index]); |
724 | CurEntry.Contributions[Index].setLength(Pair.second); |
725 | uint32_t OldOffset = ContributionOffsets[Index]; |
726 | ContributionOffsets[Index] += CurEntry.Contributions[Index].getLength32(); |
727 | if (OldOffset > ContributionOffsets[Index]) { |
728 | uint32_t SectionIndex = 0; |
729 | for (auto &Section : Obj.sections()) { |
730 | if (SectionIndex == Index) { |
731 | if (Error Err = sectionOverflowErrorOrWarning( |
732 | PrevOffset: OldOffset, OverflowedOffset: ContributionOffsets[Index], SectionName: *Section.getName(), |
733 | OverflowOptValue, AnySectionOverflow)) |
734 | return Err; |
735 | } |
736 | ++SectionIndex; |
737 | } |
738 | if (AnySectionOverflow) |
739 | break; |
740 | } |
741 | } |
742 | |
743 | uint32_t &InfoSectionOffset = |
744 | ContributionOffsets[getContributionIndex(Kind: DW_SECT_INFO, IndexVersion)]; |
745 | if (CurCUIndexSection.empty()) { |
746 | bool FoundCUUnit = false; |
747 | Out.switchSection(Section: InfoSection); |
748 | for (StringRef Info : CurInfoSection) { |
749 | uint64_t UnitOffset = 0; |
750 | while (Info.size() > UnitOffset) { |
751 | Expected<InfoSectionUnitHeader> = |
752 | parseInfoSectionUnitHeader(Info: Info.substr(Start: UnitOffset, N: Info.size())); |
753 | if (!HeaderOrError) |
754 | return HeaderOrError.takeError(); |
755 | InfoSectionUnitHeader & = *HeaderOrError; |
756 | |
757 | UnitIndexEntry Entry = CurEntry; |
758 | auto &C = Entry.Contributions[getContributionIndex(Kind: DW_SECT_INFO, |
759 | IndexVersion)]; |
760 | C.setOffset(InfoSectionOffset); |
761 | C.setLength(Header.Length + 4); |
762 | |
763 | if (std::numeric_limits<uint32_t>::max() - InfoSectionOffset < |
764 | C.getLength32()) { |
765 | if (Error Err = sectionOverflowErrorOrWarning( |
766 | PrevOffset: InfoSectionOffset, OverflowedOffset: InfoSectionOffset + C.getLength32(), |
767 | SectionName: "debug_info" , OverflowOptValue, AnySectionOverflow)) |
768 | return Err; |
769 | if (AnySectionOverflow) { |
770 | if (Header.Version < 5 || |
771 | Header.UnitType == dwarf::DW_UT_split_compile) |
772 | FoundCUUnit = true; |
773 | break; |
774 | } |
775 | } |
776 | |
777 | UnitOffset += C.getLength32(); |
778 | if (Header.Version < 5 || |
779 | Header.UnitType == dwarf::DW_UT_split_compile) { |
780 | Expected<CompileUnitIdentifiers> EID = getCUIdentifiers( |
781 | Header, Abbrev: AbbrevSection, |
782 | Info: Info.substr(Start: UnitOffset - C.getLength32(), N: C.getLength32()), |
783 | StrOffsets: CurStrOffsetSection, Str: CurStrSection); |
784 | |
785 | if (!EID) |
786 | return createFileError(F: Input, E: EID.takeError()); |
787 | const auto &ID = *EID; |
788 | auto P = IndexEntries.insert(KV: std::make_pair(x: ID.Signature, y&: Entry)); |
789 | if (!P.second) |
790 | return buildDuplicateError(PrevE: *P.first, ID, DWPName: "" ); |
791 | P.first->second.Name = ID.Name; |
792 | P.first->second.DWOName = ID.DWOName; |
793 | |
794 | FoundCUUnit = true; |
795 | } else if (Header.UnitType == dwarf::DW_UT_split_type) { |
796 | auto P = TypeIndexEntries.insert( |
797 | KV: std::make_pair(x&: *Header.Signature, y&: Entry)); |
798 | if (!P.second) |
799 | continue; |
800 | } |
801 | Out.emitBytes( |
802 | Data: Info.substr(Start: UnitOffset - C.getLength32(), N: C.getLength32())); |
803 | InfoSectionOffset += C.getLength32(); |
804 | } |
805 | if (AnySectionOverflow) |
806 | break; |
807 | } |
808 | |
809 | if (!FoundCUUnit) |
810 | return make_error<DWPError>(Args: "no compile unit found in file: " + Input); |
811 | |
812 | if (IndexVersion == 2) { |
813 | // Add types from the .debug_types section from DWARF < 5. |
814 | if (Error Err = addAllTypesFromTypesSection( |
815 | Out, TypeIndexEntries, OutputTypes: TypesSection, TypesSections: CurTypesSection, CUEntry: CurEntry, |
816 | TypesOffset&: ContributionOffsets[getContributionIndex(Kind: DW_SECT_EXT_TYPES, IndexVersion: 2)], |
817 | OverflowOptValue, AnySectionOverflow)) |
818 | return Err; |
819 | } |
820 | if (AnySectionOverflow) |
821 | break; |
822 | continue; |
823 | } |
824 | |
825 | if (CurInfoSection.size() != 1) |
826 | return make_error<DWPError>(Args: "expected exactly one occurrence of a debug " |
827 | "info section in a .dwp file" ); |
828 | StringRef DwpSingleInfoSection = CurInfoSection.front(); |
829 | |
830 | DWARFUnitIndex CUIndex(DW_SECT_INFO); |
831 | DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0); |
832 | if (!CUIndex.parse(IndexData: CUIndexData)) |
833 | return make_error<DWPError>(Args: "failed to parse cu_index" ); |
834 | if (CUIndex.getVersion() != IndexVersion) |
835 | return make_error<DWPError>(Args: "incompatible cu_index versions, found " + |
836 | utostr(X: CUIndex.getVersion()) + |
837 | " and expecting " + utostr(X: IndexVersion)); |
838 | |
839 | Out.switchSection(Section: InfoSection); |
840 | for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { |
841 | auto *I = E.getContributions(); |
842 | if (!I) |
843 | continue; |
844 | auto P = IndexEntries.insert(KV: std::make_pair(x: E.getSignature(), y&: CurEntry)); |
845 | StringRef CUInfoSection = |
846 | getSubsection(Section: DwpSingleInfoSection, Entry: E, Kind: DW_SECT_INFO); |
847 | Expected<InfoSectionUnitHeader> = |
848 | parseInfoSectionUnitHeader(Info: CUInfoSection); |
849 | if (!HeaderOrError) |
850 | return HeaderOrError.takeError(); |
851 | InfoSectionUnitHeader & = *HeaderOrError; |
852 | |
853 | Expected<CompileUnitIdentifiers> EID = getCUIdentifiers( |
854 | Header, Abbrev: getSubsection(Section: AbbrevSection, Entry: E, Kind: DW_SECT_ABBREV), |
855 | Info: CUInfoSection, |
856 | StrOffsets: getSubsection(Section: CurStrOffsetSection, Entry: E, Kind: DW_SECT_STR_OFFSETS), |
857 | Str: CurStrSection); |
858 | if (!EID) |
859 | return createFileError(F: Input, E: EID.takeError()); |
860 | const auto &ID = *EID; |
861 | if (!P.second) |
862 | return buildDuplicateError(PrevE: *P.first, ID, DWPName: Input); |
863 | auto &NewEntry = P.first->second; |
864 | NewEntry.Name = ID.Name; |
865 | NewEntry.DWOName = ID.DWOName; |
866 | NewEntry.DWPName = Input; |
867 | for (auto Kind : CUIndex.getColumnKinds()) { |
868 | if (!isSupportedSectionKind(Kind)) |
869 | continue; |
870 | auto &C = |
871 | NewEntry.Contributions[getContributionIndex(Kind, IndexVersion)]; |
872 | C.setOffset(C.getOffset() + I->getOffset()); |
873 | C.setLength(I->getLength()); |
874 | ++I; |
875 | } |
876 | unsigned Index = getContributionIndex(Kind: DW_SECT_INFO, IndexVersion); |
877 | auto &C = NewEntry.Contributions[Index]; |
878 | Out.emitBytes(Data: CUInfoSection); |
879 | C.setOffset(InfoSectionOffset); |
880 | InfoSectionOffset += C.getLength32(); |
881 | } |
882 | |
883 | if (!CurTUIndexSection.empty()) { |
884 | llvm::DWARFSectionKind TUSectionKind; |
885 | MCSection *OutSection; |
886 | StringRef TypeInputSection; |
887 | // Write type units into debug info section for DWARFv5. |
888 | if (Version >= 5) { |
889 | TUSectionKind = DW_SECT_INFO; |
890 | OutSection = InfoSection; |
891 | TypeInputSection = DwpSingleInfoSection; |
892 | } else { |
893 | // Write type units into debug types section for DWARF < 5. |
894 | if (CurTypesSection.size() != 1) |
895 | return make_error<DWPError>( |
896 | Args: "multiple type unit sections in .dwp file" ); |
897 | |
898 | TUSectionKind = DW_SECT_EXT_TYPES; |
899 | OutSection = TypesSection; |
900 | TypeInputSection = CurTypesSection.front(); |
901 | } |
902 | |
903 | DWARFUnitIndex TUIndex(TUSectionKind); |
904 | DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0); |
905 | if (!TUIndex.parse(IndexData: TUIndexData)) |
906 | return make_error<DWPError>(Args: "failed to parse tu_index" ); |
907 | if (TUIndex.getVersion() != IndexVersion) |
908 | return make_error<DWPError>(Args: "incompatible tu_index versions, found " + |
909 | utostr(X: TUIndex.getVersion()) + |
910 | " and expecting " + utostr(X: IndexVersion)); |
911 | |
912 | unsigned TypesContributionIndex = |
913 | getContributionIndex(Kind: TUSectionKind, IndexVersion); |
914 | if (Error Err = addAllTypesFromDWP( |
915 | Out, TypeIndexEntries, TUIndex, OutputTypes: OutSection, Types: TypeInputSection, |
916 | TUEntry: CurEntry, TypesOffset&: ContributionOffsets[TypesContributionIndex], |
917 | TypesContributionIndex, OverflowOptValue, AnySectionOverflow)) |
918 | return Err; |
919 | } |
920 | if (AnySectionOverflow) |
921 | break; |
922 | } |
923 | |
924 | if (Version < 5) { |
925 | // Lie about there being no info contributions so the TU index only includes |
926 | // the type unit contribution for DWARF < 5. In DWARFv5 the TU index has a |
927 | // contribution to the info section, so we do not want to lie about it. |
928 | ContributionOffsets[0] = 0; |
929 | } |
930 | writeIndex(Out, Section: MCOFI.getDwarfTUIndexSection(), ContributionOffsets, |
931 | IndexEntries: TypeIndexEntries, IndexVersion); |
932 | |
933 | if (Version < 5) { |
934 | // Lie about the type contribution for DWARF < 5. In DWARFv5 the type |
935 | // section does not exist, so no need to do anything about this. |
936 | ContributionOffsets[getContributionIndex(Kind: DW_SECT_EXT_TYPES, IndexVersion: 2)] = 0; |
937 | // Unlie about the info contribution |
938 | ContributionOffsets[0] = 1; |
939 | } |
940 | |
941 | writeIndex(Out, Section: MCOFI.getDwarfCUIndexSection(), ContributionOffsets, |
942 | IndexEntries, IndexVersion); |
943 | |
944 | return Error::success(); |
945 | } |
946 | } // namespace llvm |
947 | |