aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm14/lib/DWP/DWP.cpp
blob: f6538c0549d0befa42d619ebc14c8f183e20c922 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
//===-- llvm-dwp.cpp - Split DWARF merging tool for llvm ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// A utility for merging DWARF 5 Split DWARF .dwo files into .dwp (DWARF
// package files).
//
//===----------------------------------------------------------------------===//
#include "llvm/DWP/DWP.h"
#include "llvm/DWP/DWPError.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/Object/Decompressor.h"

using namespace llvm;
using namespace llvm::object;

static mc::RegisterMCTargetOptionsFlags MCTargetOptionsFlags;

// Returns the size of debug_str_offsets section headers in bytes.
static uint64_t debugStrOffsetsHeaderSize(DataExtractor StrOffsetsData,
                                          uint16_t DwarfVersion) {
  if (DwarfVersion <= 4)
    return 0; // There is no header before dwarf 5.
  uint64_t Offset = 0;
  uint64_t Length = StrOffsetsData.getU32(&Offset);
  if (Length == llvm::dwarf::DW_LENGTH_DWARF64)
    return 16; // unit length: 12 bytes, version: 2 bytes, padding: 2 bytes.
  return 8;    // unit length: 4 bytes, version: 2 bytes, padding: 2 bytes.
}

static uint64_t getCUAbbrev(StringRef Abbrev, uint64_t AbbrCode) {
  uint64_t Offset = 0;
  DataExtractor AbbrevData(Abbrev, true, 0);
  while (AbbrevData.getULEB128(&Offset) != AbbrCode) {
    // Tag
    AbbrevData.getULEB128(&Offset);
    // DW_CHILDREN
    AbbrevData.getU8(&Offset);
    // Attributes
    while (AbbrevData.getULEB128(&Offset) | AbbrevData.getULEB128(&Offset))
      ;
  }
  return Offset;
}

static Expected<const char *>
getIndexedString(dwarf::Form Form, DataExtractor InfoData, uint64_t &InfoOffset,
                 StringRef StrOffsets, StringRef Str, uint16_t Version) {
  if (Form == dwarf::DW_FORM_string)
    return InfoData.getCStr(&InfoOffset);
  uint64_t StrIndex;
  switch (Form) {
  case dwarf::DW_FORM_strx1:
    StrIndex = InfoData.getU8(&InfoOffset);
    break;
  case dwarf::DW_FORM_strx2:
    StrIndex = InfoData.getU16(&InfoOffset);
    break;
  case dwarf::DW_FORM_strx3:
    StrIndex = InfoData.getU24(&InfoOffset);
    break;
  case dwarf::DW_FORM_strx4:
    StrIndex = InfoData.getU32(&InfoOffset);
    break;
  case dwarf::DW_FORM_strx:
  case dwarf::DW_FORM_GNU_str_index:
    StrIndex = InfoData.getULEB128(&InfoOffset);
    break;
  default:
    return make_error<DWPError>(
        "string field must be encoded with one of the following: "
        "DW_FORM_string, DW_FORM_strx, DW_FORM_strx1, DW_FORM_strx2, "
        "DW_FORM_strx3, DW_FORM_strx4, or DW_FORM_GNU_str_index.");
  }
  DataExtractor StrOffsetsData(StrOffsets, true, 0);
  uint64_t StrOffsetsOffset = 4 * StrIndex;
  StrOffsetsOffset += debugStrOffsetsHeaderSize(StrOffsetsData, Version);

  uint64_t StrOffset = StrOffsetsData.getU32(&StrOffsetsOffset);
  DataExtractor StrData(Str, true, 0);
  return StrData.getCStr(&StrOffset);
}

static Expected<CompileUnitIdentifiers>
getCUIdentifiers(InfoSectionUnitHeader &Header, StringRef Abbrev,
                 StringRef Info, StringRef StrOffsets, StringRef Str) {
  DataExtractor InfoData(Info, true, 0);
  uint64_t Offset = Header.HeaderSize;
  if (Header.Version >= 5 && Header.UnitType != dwarf::DW_UT_split_compile)
    return make_error<DWPError>(
        std::string("unit type DW_UT_split_compile type not found in "
                    "debug_info header. Unexpected unit type 0x" +
                    utostr(Header.UnitType) + " found"));

  CompileUnitIdentifiers ID;

  uint32_t AbbrCode = InfoData.getULEB128(&Offset);
  DataExtractor AbbrevData(Abbrev, true, 0);
  uint64_t AbbrevOffset = getCUAbbrev(Abbrev, AbbrCode);
  auto Tag = static_cast<dwarf::Tag>(AbbrevData.getULEB128(&AbbrevOffset));
  if (Tag != dwarf::DW_TAG_compile_unit)
    return make_error<DWPError>("top level DIE is not a compile unit");
  // DW_CHILDREN
  AbbrevData.getU8(&AbbrevOffset);
  uint32_t Name;
  dwarf::Form Form;
  while ((Name = AbbrevData.getULEB128(&AbbrevOffset)) |
             (Form = static_cast<dwarf::Form>(
                  AbbrevData.getULEB128(&AbbrevOffset))) &&
         (Name != 0 || Form != 0)) {
    switch (Name) {
    case dwarf::DW_AT_name: {
      Expected<const char *> EName = getIndexedString(
          Form, InfoData, Offset, StrOffsets, Str, Header.Version);
      if (!EName)
        return EName.takeError();
      ID.Name = *EName;
      break;
    }
    case dwarf::DW_AT_GNU_dwo_name:
    case dwarf::DW_AT_dwo_name: {
      Expected<const char *> EName = getIndexedString(
          Form, InfoData, Offset, StrOffsets, Str, Header.Version);
      if (!EName)
        return EName.takeError();
      ID.DWOName = *EName;
      break;
    }
    case dwarf::DW_AT_GNU_dwo_id:
      Header.Signature = InfoData.getU64(&Offset);
      break;
    default:
      DWARFFormValue::skipValue(
          Form, InfoData, &Offset,
          dwarf::FormParams({Header.Version, Header.AddrSize, Header.Format}));
    }
  }
  if (!Header.Signature)
    return make_error<DWPError>("compile unit missing dwo_id");
  ID.Signature = *Header.Signature;
  return ID;
}

static bool isSupportedSectionKind(DWARFSectionKind Kind) {
  return Kind != DW_SECT_EXT_unknown;
}

namespace llvm {
// Convert an internal section identifier into the index to use with
// UnitIndexEntry::Contributions.
unsigned getContributionIndex(DWARFSectionKind Kind, uint32_t IndexVersion) {
  assert(serializeSectionKind(Kind, IndexVersion) >= DW_SECT_INFO);
  return serializeSectionKind(Kind, IndexVersion) - DW_SECT_INFO;
}
} // namespace llvm

// Convert a UnitIndexEntry::Contributions index to the corresponding on-disk
// value of the section identifier.
static unsigned getOnDiskSectionId(unsigned Index) {
  return Index + DW_SECT_INFO;
}

static StringRef getSubsection(StringRef Section,
                               const DWARFUnitIndex::Entry &Entry,
                               DWARFSectionKind Kind) {
  const auto *Off = Entry.getContribution(Kind);
  if (!Off)
    return StringRef();
  return Section.substr(Off->Offset, Off->Length);
}

static void
addAllTypesFromDWP(MCStreamer &Out,
                   MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
                   const DWARFUnitIndex &TUIndex, MCSection *OutputTypes,
                   StringRef Types, const UnitIndexEntry &TUEntry,
                   uint32_t &TypesOffset, unsigned TypesContributionIndex) {
  Out.SwitchSection(OutputTypes);
  for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) {
    auto *I = E.getContributions();
    if (!I)
      continue;
    auto P = TypeIndexEntries.insert(std::make_pair(E.getSignature(), TUEntry));
    if (!P.second)
      continue;
    auto &Entry = P.first->second;
    // Zero out the debug_info contribution
    Entry.Contributions[0] = {};
    for (auto Kind : TUIndex.getColumnKinds()) {
      if (!isSupportedSectionKind(Kind))
        continue;
      auto &C =
          Entry.Contributions[getContributionIndex(Kind, TUIndex.getVersion())];
      C.Offset += I->Offset;
      C.Length = I->Length;
      ++I;
    }
    auto &C = Entry.Contributions[TypesContributionIndex];
    Out.emitBytes(Types.substr(
        C.Offset - TUEntry.Contributions[TypesContributionIndex].Offset,
        C.Length));
    C.Offset = TypesOffset;
    TypesOffset += C.Length;
  }
}

static void addAllTypesFromTypesSection(
    MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
    MCSection *OutputTypes, const std::vector<StringRef> &TypesSections,
    const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) {
  for (StringRef Types : TypesSections) {
    Out.SwitchSection(OutputTypes);
    uint64_t Offset = 0;
    DataExtractor Data(Types, true, 0);
    while (Data.isValidOffset(Offset)) {
      UnitIndexEntry Entry = CUEntry;
      // Zero out the debug_info contribution
      Entry.Contributions[0] = {};
      auto &C = Entry.Contributions[getContributionIndex(DW_SECT_EXT_TYPES, 2)];
      C.Offset = TypesOffset;
      auto PrevOffset = Offset;
      // Length of the unit, including the 4 byte length field.
      C.Length = Data.getU32(&Offset) + 4;

      Data.getU16(&Offset); // Version
      Data.getU32(&Offset); // Abbrev offset
      Data.getU8(&Offset);  // Address size
      auto Signature = Data.getU64(&Offset);
      Offset = PrevOffset + C.Length;

      auto P = TypeIndexEntries.insert(std::make_pair(Signature, Entry));
      if (!P.second)
        continue;

      Out.emitBytes(Types.substr(PrevOffset, C.Length));
      TypesOffset += C.Length;
    }
  }
}

static std::string buildDWODescription(StringRef Name, StringRef DWPName,
                                       StringRef DWOName) {
  std::string Text = "\'";
  Text += Name;
  Text += '\'';
  if (!DWPName.empty()) {
    Text += " (from ";
    if (!DWOName.empty()) {
      Text += '\'';
      Text += DWOName;
      Text += "' in ";
    }
    Text += '\'';
    Text += DWPName;
    Text += "')";
  }
  return Text;
}

static Error createError(StringRef Name, Error E) {
  return make_error<DWPError>(
      ("failure while decompressing compressed section: '" + Name + "', " +
       llvm::toString(std::move(E)))
          .str());
}

static Error
handleCompressedSection(std::deque<SmallString<32>> &UncompressedSections,
                        StringRef &Name, StringRef &Contents) {
  if (!Decompressor::isGnuStyle(Name))
    return Error::success();

  Expected<Decompressor> Dec =
      Decompressor::create(Name, Contents, false /*IsLE*/, false /*Is64Bit*/);
  if (!Dec)
    return createError(Name, Dec.takeError());

  UncompressedSections.emplace_back();
  if (Error E = Dec->resizeAndDecompress(UncompressedSections.back()))
    return createError(Name, std::move(E));

  Name = Name.substr(2); // Drop ".z"
  Contents = UncompressedSections.back();
  return Error::success();
}

namespace llvm {
// Parse and return the header of an info section compile/type unit.
Expected<InfoSectionUnitHeader> parseInfoSectionUnitHeader(StringRef Info) {
  InfoSectionUnitHeader Header;
  Error Err = Error::success();
  uint64_t Offset = 0;
  DWARFDataExtractor InfoData(Info, true, 0);
  std::tie(Header.Length, Header.Format) =
      InfoData.getInitialLength(&Offset, &Err);
  if (Err)
    return make_error<DWPError>("cannot parse compile unit length: " +
                                llvm::toString(std::move(Err)));

  if (!InfoData.isValidOffset(Offset + (Header.Length - 1))) {
    return make_error<DWPError>(
        "compile unit exceeds .debug_info section range: " +
        utostr(Offset + Header.Length) + " >= " + utostr(InfoData.size()));
  }

  Header.Version = InfoData.getU16(&Offset, &Err);
  if (Err)
    return make_error<DWPError>("cannot parse compile unit version: " +
                                llvm::toString(std::move(Err)));

  uint64_t MinHeaderLength;
  if (Header.Version >= 5) {
    // Size: Version (2), UnitType (1), AddrSize (1), DebugAbbrevOffset (4),
    // Signature (8)
    MinHeaderLength = 16;
  } else {
    // Size: Version (2), DebugAbbrevOffset (4), AddrSize (1)
    MinHeaderLength = 7;
  }
  if (Header.Length < MinHeaderLength) {
    return make_error<DWPError>("unit length is too small: expected at least " +
                                utostr(MinHeaderLength) + " got " +
                                utostr(Header.Length) + ".");
  }
  if (Header.Version >= 5) {
    Header.UnitType = InfoData.getU8(&Offset);
    Header.AddrSize = InfoData.getU8(&Offset);
    Header.DebugAbbrevOffset = InfoData.getU32(&Offset);
    Header.Signature = InfoData.getU64(&Offset);
    if (Header.UnitType == dwarf::DW_UT_split_type) {
      // Type offset.
      MinHeaderLength += 4;
      if (Header.Length < MinHeaderLength)
        return make_error<DWPError>("type unit is missing type offset");
      InfoData.getU32(&Offset);
    }
  } else {
    // Note that, address_size and debug_abbrev_offset fields have switched
    // places between dwarf version 4 and 5.
    Header.DebugAbbrevOffset = InfoData.getU32(&Offset);
    Header.AddrSize = InfoData.getU8(&Offset);
  }

  Header.HeaderSize = Offset;
  return Header;
}

void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings,
                            MCSection *StrOffsetSection,
                            StringRef CurStrSection,
                            StringRef CurStrOffsetSection, uint16_t Version) {
  // Could possibly produce an error or warning if one of these was non-null but
  // the other was null.
  if (CurStrSection.empty() || CurStrOffsetSection.empty())
    return;

  DenseMap<uint64_t, uint32_t> OffsetRemapping;

  DataExtractor Data(CurStrSection, true, 0);
  uint64_t LocalOffset = 0;
  uint64_t PrevOffset = 0;
  while (const char *S = Data.getCStr(&LocalOffset)) {
    OffsetRemapping[PrevOffset] =
        Strings.getOffset(S, LocalOffset - PrevOffset);
    PrevOffset = LocalOffset;
  }

  Data = DataExtractor(CurStrOffsetSection, true, 0);

  Out.SwitchSection(StrOffsetSection);

  uint64_t HeaderSize = debugStrOffsetsHeaderSize(Data, Version);
  uint64_t Offset = 0;
  uint64_t Size = CurStrOffsetSection.size();
  // FIXME: This can be caused by bad input and should be handled as such.
  assert(HeaderSize <= Size && "StrOffsetSection size is less than its header");
  // Copy the header to the output.
  Out.emitBytes(Data.getBytes(&Offset, HeaderSize));
  while (Offset < Size) {
    auto OldOffset = Data.getU32(&Offset);
    auto NewOffset = OffsetRemapping[OldOffset];
    Out.emitIntValue(NewOffset, 4);
  }
}

void writeIndexTable(
    MCStreamer &Out, ArrayRef<unsigned> ContributionOffsets,
    const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
    uint32_t DWARFUnitIndex::Entry::SectionContribution::*Field) {
  for (const auto &E : IndexEntries)
    for (size_t I = 0; I != array_lengthof(E.second.Contributions); ++I)
      if (ContributionOffsets[I])
        Out.emitIntValue(E.second.Contributions[I].*Field, 4);
}

void writeIndex(MCStreamer &Out, MCSection *Section,
                ArrayRef<unsigned> ContributionOffsets,
                const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
                uint32_t IndexVersion) {
  if (IndexEntries.empty())
    return;

  unsigned Columns = 0;
  for (auto &C : ContributionOffsets)
    if (C)
      ++Columns;

  std::vector<unsigned> Buckets(NextPowerOf2(3 * IndexEntries.size() / 2));
  uint64_t Mask = Buckets.size() - 1;
  size_t I = 0;
  for (const auto &P : IndexEntries) {
    auto S = P.first;
    auto H = S & Mask;
    auto HP = ((S >> 32) & Mask) | 1;
    while (Buckets[H]) {
      assert(S != IndexEntries.begin()[Buckets[H] - 1].first &&
             "Duplicate unit");
      H = (H + HP) & Mask;
    }
    Buckets[H] = I + 1;
    ++I;
  }

  Out.SwitchSection(Section);
  Out.emitIntValue(IndexVersion, 4);        // Version
  Out.emitIntValue(Columns, 4);             // Columns
  Out.emitIntValue(IndexEntries.size(), 4); // Num Units
  Out.emitIntValue(Buckets.size(), 4);      // Num Buckets

  // Write the signatures.
  for (const auto &I : Buckets)
    Out.emitIntValue(I ? IndexEntries.begin()[I - 1].first : 0, 8);

  // Write the indexes.
  for (const auto &I : Buckets)
    Out.emitIntValue(I, 4);

  // Write the column headers (which sections will appear in the table)
  for (size_t I = 0; I != ContributionOffsets.size(); ++I)
    if (ContributionOffsets[I])
      Out.emitIntValue(getOnDiskSectionId(I), 4);

  // Write the offsets.
  writeIndexTable(Out, ContributionOffsets, IndexEntries,
                  &DWARFUnitIndex::Entry::SectionContribution::Offset);

  // Write the lengths.
  writeIndexTable(Out, ContributionOffsets, IndexEntries,
                  &DWARFUnitIndex::Entry::SectionContribution::Length);
}

Error buildDuplicateError(const std::pair<uint64_t, UnitIndexEntry> &PrevE,
                          const CompileUnitIdentifiers &ID, StringRef DWPName) {
  return make_error<DWPError>(
      std::string("duplicate DWO ID (") + utohexstr(PrevE.first) + ") in " +
      buildDWODescription(PrevE.second.Name, PrevE.second.DWPName,
                          PrevE.second.DWOName) +
      " and " + buildDWODescription(ID.Name, DWPName, ID.DWOName));
}

Error handleSection(
    const StringMap<std::pair<MCSection *, DWARFSectionKind>> &KnownSections,
    const MCSection *StrSection, const MCSection *StrOffsetSection,
    const MCSection *TypesSection, const MCSection *CUIndexSection,
    const MCSection *TUIndexSection, const MCSection *InfoSection,
    const SectionRef &Section, MCStreamer &Out,
    std::deque<SmallString<32>> &UncompressedSections,
    uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry,
    StringRef &CurStrSection, StringRef &CurStrOffsetSection,
    std::vector<StringRef> &CurTypesSection,
    std::vector<StringRef> &CurInfoSection, StringRef &AbbrevSection,
    StringRef &CurCUIndexSection, StringRef &CurTUIndexSection,
    std::vector<std::pair<DWARFSectionKind, uint32_t>> &SectionLength) {
  if (Section.isBSS())
    return Error::success();

  if (Section.isVirtual())
    return Error::success();

  Expected<StringRef> NameOrErr = Section.getName();
  if (!NameOrErr)
    return NameOrErr.takeError();
  StringRef Name = *NameOrErr;

  Expected<StringRef> ContentsOrErr = Section.getContents();
  if (!ContentsOrErr)
    return ContentsOrErr.takeError();
  StringRef Contents = *ContentsOrErr;

  if (auto Err = handleCompressedSection(UncompressedSections, Name, Contents))
    return Err;

  Name = Name.substr(Name.find_first_not_of("._"));

  auto SectionPair = KnownSections.find(Name);
  if (SectionPair == KnownSections.end())
    return Error::success();

  if (DWARFSectionKind Kind = SectionPair->second.second) {
    if (Kind != DW_SECT_EXT_TYPES && Kind != DW_SECT_INFO) {
      SectionLength.push_back(std::make_pair(Kind, Contents.size()));
    }

    if (Kind == DW_SECT_ABBREV) {
      AbbrevSection = Contents;
    }
  }

  MCSection *OutSection = SectionPair->second.first;
  if (OutSection == StrOffsetSection)
    CurStrOffsetSection = Contents;
  else if (OutSection == StrSection)
    CurStrSection = Contents;
  else if (OutSection == TypesSection)
    CurTypesSection.push_back(Contents);
  else if (OutSection == CUIndexSection)
    CurCUIndexSection = Contents;
  else if (OutSection == TUIndexSection)
    CurTUIndexSection = Contents;
  else if (OutSection == InfoSection)
    CurInfoSection.push_back(Contents);
  else {
    Out.SwitchSection(OutSection);
    Out.emitBytes(Contents);
  }
  return Error::success();
}

Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
  const auto &MCOFI = *Out.getContext().getObjectFileInfo();
  MCSection *const StrSection = MCOFI.getDwarfStrDWOSection();
  MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection();
  MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection();
  MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection();
  MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection();
  MCSection *const InfoSection = MCOFI.getDwarfInfoDWOSection();
  const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = {
      {"debug_info.dwo", {InfoSection, DW_SECT_INFO}},
      {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}},
      {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}},
      {"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}},
      {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}},
      {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}},
      {"debug_macro.dwo", {MCOFI.getDwarfMacroDWOSection(), DW_SECT_MACRO}},
      {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}},
      {"debug_loclists.dwo",
       {MCOFI.getDwarfLoclistsDWOSection(), DW_SECT_LOCLISTS}},
      {"debug_rnglists.dwo",
       {MCOFI.getDwarfRnglistsDWOSection(), DW_SECT_RNGLISTS}},
      {"debug_cu_index", {CUIndexSection, static_cast<DWARFSectionKind>(0)}},
      {"debug_tu_index", {TUIndexSection, static_cast<DWARFSectionKind>(0)}}};

  MapVector<uint64_t, UnitIndexEntry> IndexEntries;
  MapVector<uint64_t, UnitIndexEntry> TypeIndexEntries;

  uint32_t ContributionOffsets[8] = {};
  uint16_t Version = 0;
  uint32_t IndexVersion = 0;

  DWPStringPool Strings(Out, StrSection);

  SmallVector<OwningBinary<object::ObjectFile>, 128> Objects;
  Objects.reserve(Inputs.size());

  std::deque<SmallString<32>> UncompressedSections;

  for (const auto &Input : Inputs) {
    auto ErrOrObj = object::ObjectFile::createObjectFile(Input);
    if (!ErrOrObj)
      return ErrOrObj.takeError();

    auto &Obj = *ErrOrObj->getBinary();
    Objects.push_back(std::move(*ErrOrObj));

    UnitIndexEntry CurEntry = {};

    StringRef CurStrSection;
    StringRef CurStrOffsetSection;
    std::vector<StringRef> CurTypesSection;
    std::vector<StringRef> CurInfoSection;
    StringRef AbbrevSection;
    StringRef CurCUIndexSection;
    StringRef CurTUIndexSection;

    // This maps each section contained in this file to its length.
    // This information is later on used to calculate the contributions,
    // i.e. offset and length, of each compile/type unit to a section.
    std::vector<std::pair<DWARFSectionKind, uint32_t>> SectionLength;

    for (const auto &Section : Obj.sections())
      if (auto Err = handleSection(
              KnownSections, StrSection, StrOffsetSection, TypesSection,
              CUIndexSection, TUIndexSection, InfoSection, Section, Out,
              UncompressedSections, ContributionOffsets, CurEntry,
              CurStrSection, CurStrOffsetSection, CurTypesSection,
              CurInfoSection, AbbrevSection, CurCUIndexSection,
              CurTUIndexSection, SectionLength))
        return Err;

    if (CurInfoSection.empty())
      continue;

    Expected<InfoSectionUnitHeader> HeaderOrErr =
        parseInfoSectionUnitHeader(CurInfoSection.front());
    if (!HeaderOrErr)
      return HeaderOrErr.takeError();
    InfoSectionUnitHeader &Header = *HeaderOrErr;

    if (Version == 0) {
      Version = Header.Version;
      IndexVersion = Version < 5 ? 2 : 5;
    } else if (Version != Header.Version) {
      return make_error<DWPError>("incompatible DWARF compile unit versions.");
    }

    writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection,
                           CurStrOffsetSection, Header.Version);

    for (auto Pair : SectionLength) {
      auto Index = getContributionIndex(Pair.first, IndexVersion);
      CurEntry.Contributions[Index].Offset = ContributionOffsets[Index];
      ContributionOffsets[Index] +=
          (CurEntry.Contributions[Index].Length = Pair.second);
    }

    uint32_t &InfoSectionOffset =
        ContributionOffsets[getContributionIndex(DW_SECT_INFO, IndexVersion)];
    if (CurCUIndexSection.empty()) {
      bool FoundCUUnit = false;
      Out.SwitchSection(InfoSection);
      for (StringRef Info : CurInfoSection) {
        uint64_t UnitOffset = 0;
        while (Info.size() > UnitOffset) {
          Expected<InfoSectionUnitHeader> HeaderOrError =
              parseInfoSectionUnitHeader(Info.substr(UnitOffset, Info.size()));
          if (!HeaderOrError)
            return HeaderOrError.takeError();
          InfoSectionUnitHeader &Header = *HeaderOrError;

          UnitIndexEntry Entry = CurEntry;
          auto &C = Entry.Contributions[getContributionIndex(DW_SECT_INFO,
                                                             IndexVersion)];
          C.Offset = InfoSectionOffset;
          C.Length = Header.Length + 4;
          UnitOffset += C.Length;
          if (Header.Version < 5 ||
              Header.UnitType == dwarf::DW_UT_split_compile) {
            Expected<CompileUnitIdentifiers> EID =
                getCUIdentifiers(Header, AbbrevSection,
                                 Info.substr(UnitOffset - C.Length, C.Length),
                                 CurStrOffsetSection, CurStrSection);

            if (!EID)
              return createFileError(Input, EID.takeError());
            const auto &ID = *EID;
            auto P = IndexEntries.insert(std::make_pair(ID.Signature, Entry));
            if (!P.second)
              return buildDuplicateError(*P.first, ID, "");
            P.first->second.Name = ID.Name;
            P.first->second.DWOName = ID.DWOName;

            FoundCUUnit = true;
          } else if (Header.UnitType == dwarf::DW_UT_split_type) {
            auto P = TypeIndexEntries.insert(
                std::make_pair(Header.Signature.getValue(), Entry));
            if (!P.second)
              continue;
          }
          Out.emitBytes(Info.substr(UnitOffset - C.Length, C.Length));
          InfoSectionOffset += C.Length;
        }
      }

      if (!FoundCUUnit)
        return make_error<DWPError>("no compile unit found in file: " + Input);

      if (IndexVersion == 2) {
        // Add types from the .debug_types section from DWARF < 5.
        addAllTypesFromTypesSection(
            Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry,
            ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)]);
      }
      continue;
    }

    if (CurInfoSection.size() != 1)
      return make_error<DWPError>("expected exactly one occurrence of a debug "
                                  "info section in a .dwp file");
    StringRef DwpSingleInfoSection = CurInfoSection.front();

    DWARFUnitIndex CUIndex(DW_SECT_INFO);
    DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0);
    if (!CUIndex.parse(CUIndexData))
      return make_error<DWPError>("failed to parse cu_index");
    if (CUIndex.getVersion() != IndexVersion)
      return make_error<DWPError>("incompatible cu_index versions, found " +
                                  utostr(CUIndex.getVersion()) +
                                  " and expecting " + utostr(IndexVersion));

    Out.SwitchSection(InfoSection);
    for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) {
      auto *I = E.getContributions();
      if (!I)
        continue;
      auto P = IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry));
      StringRef CUInfoSection =
          getSubsection(DwpSingleInfoSection, E, DW_SECT_INFO);
      Expected<InfoSectionUnitHeader> HeaderOrError =
          parseInfoSectionUnitHeader(CUInfoSection);
      if (!HeaderOrError)
        return HeaderOrError.takeError();
      InfoSectionUnitHeader &Header = *HeaderOrError;

      Expected<CompileUnitIdentifiers> EID = getCUIdentifiers(
          Header, getSubsection(AbbrevSection, E, DW_SECT_ABBREV),
          CUInfoSection,
          getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS),
          CurStrSection);
      if (!EID)
        return createFileError(Input, EID.takeError());
      const auto &ID = *EID;
      if (!P.second)
        return buildDuplicateError(*P.first, ID, Input);
      auto &NewEntry = P.first->second;
      NewEntry.Name = ID.Name;
      NewEntry.DWOName = ID.DWOName;
      NewEntry.DWPName = Input;
      for (auto Kind : CUIndex.getColumnKinds()) {
        if (!isSupportedSectionKind(Kind))
          continue;
        auto &C =
            NewEntry.Contributions[getContributionIndex(Kind, IndexVersion)];
        C.Offset += I->Offset;
        C.Length = I->Length;
        ++I;
      }
      unsigned Index = getContributionIndex(DW_SECT_INFO, IndexVersion);
      auto &C = NewEntry.Contributions[Index];
      Out.emitBytes(CUInfoSection);
      C.Offset = InfoSectionOffset;
      InfoSectionOffset += C.Length;
    }

    if (!CurTUIndexSection.empty()) {
      llvm::DWARFSectionKind TUSectionKind;
      MCSection *OutSection;
      StringRef TypeInputSection;
      // Write type units into debug info section for DWARFv5.
      if (Version >= 5) {
        TUSectionKind = DW_SECT_INFO;
        OutSection = InfoSection;
        TypeInputSection = DwpSingleInfoSection;
      } else {
        // Write type units into debug types section for DWARF < 5.
        if (CurTypesSection.size() != 1)
          return make_error<DWPError>(
              "multiple type unit sections in .dwp file");

        TUSectionKind = DW_SECT_EXT_TYPES;
        OutSection = TypesSection;
        TypeInputSection = CurTypesSection.front();
      }

      DWARFUnitIndex TUIndex(TUSectionKind);
      DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0);
      if (!TUIndex.parse(TUIndexData))
        return make_error<DWPError>("failed to parse tu_index");
      if (TUIndex.getVersion() != IndexVersion)
        return make_error<DWPError>("incompatible tu_index versions, found " +
                                    utostr(TUIndex.getVersion()) +
                                    " and expecting " + utostr(IndexVersion));

      unsigned TypesContributionIndex =
          getContributionIndex(TUSectionKind, IndexVersion);
      addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, OutSection,
                         TypeInputSection, CurEntry,
                         ContributionOffsets[TypesContributionIndex],
                         TypesContributionIndex);
    }
  }

  if (Version < 5) {
    // Lie about there being no info contributions so the TU index only includes
    // the type unit contribution for DWARF < 5. In DWARFv5 the TU index has a
    // contribution to the info section, so we do not want to lie about it.
    ContributionOffsets[0] = 0;
  }
  writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets,
             TypeIndexEntries, IndexVersion);

  if (Version < 5) {
    // Lie about the type contribution for DWARF < 5. In DWARFv5 the type
    // section does not exist, so no need to do anything about this.
    ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)] = 0;
    // Unlie about the info contribution
    ContributionOffsets[0] = 1;
  }

  writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets,
             IndexEntries, IndexVersion);

  return Error::success();
}
} // namespace llvm