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