LLVM: lib/ProfileData/Coverage/CoverageMappingReader.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
39#include
40
41using namespace llvm;
42using namespace coverage;
43using namespace object;
44
45#define DEBUG_TYPE "coverage-mapping"
46
47STATISTIC(CovMapNumRecords, "The # of coverage function records");
48STATISTIC(CovMapNumUsedRecords, "The # of used coverage function records");
49
50void CoverageMappingIterator::increment() {
52 return;
53
54
55
60 else
61 ReadErr = CME.get();
62 });
63}
64
68 unsigned N = 0;
72 "the size of ULEB128 is too big");
75}
76
79 return Err;
80 if (Result >= MaxPlus1)
81 return make_error(
83 "the value of ULEB128 is greater than or equal to MaxPlus1");
85}
86
89 return Err;
92 "the value of ULEB128 is too big");
94}
95
99 return Err;
103}
104
107 if (auto Err = readSize(NumFilenames))
108 return Err;
109 if (!NumFilenames)
111 "number of filenames is zero");
112
114 return readUncompressed(Version, NumFilenames);
115
116
117
119 if (auto Err = readULEB128(UncompressedLen))
120 return Err;
121
123 if (auto Err = readSize(CompressedLen))
124 return Err;
125
126 if (CompressedLen > 0) {
128 return make_error(
130
131
133
134
138 arrayRefFromStringRef(CompressedFilenames), StorageBuf,
139 UncompressedLen);
140 if (Err) {
142 return make_error(
144 }
145
147 CompilationDir);
148 return Delegate.readUncompressed(Version, NumFilenames);
149 }
150
151 return readUncompressed(Version, NumFilenames);
152}
153
156
158 for (size_t I = 0; I < NumFilenames; ++I) {
161 return Err;
162 Filenames.push_back(Filename.str());
163 }
164 } else {
167 return Err;
168 Filenames.push_back(CWD.str());
169
170 for (size_t I = 1; I < NumFilenames; ++I) {
173 return Err;
175 Filenames.push_back(Filename.str());
176 } else {
178 if (!CompilationDir.empty())
179 P.assign(CompilationDir);
180 else
181 P.assign(CWD);
184 Filenames.push_back(static_caststd::string\(P.str()));
185 }
186 }
187 }
189}
190
191Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) {
193 switch (Tag) {
200 default:
201 break;
202 }
204 switch (Tag) {
208 if (ID >= Expressions.size())
210 "counter expression is invalid");
213 break;
214 }
215 default:
217 "counter expression kind is invalid");
218 }
220}
221
222Error RawCoverageMappingReader::readCounter(Counter &C) {
224 if (auto Err =
225 readIntMax(EncodedCounter, std::numeric_limits::max()))
226 return Err;
227 if (auto Err = decodeCounter(EncodedCounter, C))
228 return Err;
230}
231
234
235
236
237
238Error RawCoverageMappingReader::readMappingRegionsSubArray(
239 std::vector &MappingRegions, unsigned InferredFileID,
240 size_t NumFileIDs) {
242 if (auto Err = readSize(NumRegions))
243 return Err;
244 unsigned LineStart = 0;
245 for (size_t I = 0; I < NumRegions; ++I) {
248
252
253
254 uint64_t EncodedCounterAndRegion;
255 if (auto Err = readIntMax(EncodedCounterAndRegion,
256 std::numeric_limits::max()))
257 return Err;
260
261
262
263
264
265
266
267
268
269
270
271
273 if (auto Err = decodeCounter(EncodedCounterAndRegion, C))
274 return Err;
275 } else {
276
279 ExpandedFileID = EncodedCounterAndRegion >>
281 if (ExpandedFileID >= NumFileIDs)
283 "ExpandedFileID is invalid");
284 } else {
285 switch (EncodedCounterAndRegion >>
288
289 break;
292 break;
294
296 if (auto Err = readCounter(C))
297 return Err;
298 if (auto Err = readCounter(C2))
299 return Err;
300 break;
302
304 if (auto Err = readCounter(C))
305 return Err;
306 if (auto Err = readCounter(C2))
307 return Err;
308 if (auto Err = readIntMax(ID1, std::numeric_limits<int16_t>::max()))
309 return Err;
310 if (auto Err = readIntMax(TID1, std::numeric_limits<int16_t>::max()))
311 return Err;
312 if (auto Err = readIntMax(FID1, std::numeric_limits<int16_t>::max()))
313 return Err;
314 if (ID1 == 0)
315 return make_error(
317 "MCDCConditionID shouldn't be zero");
319 static_cast<int16_t>(static_cast<int16_t>(ID1) - 1),
320 {static_cast<int16_t>(static_cast<int16_t>(FID1) - 1),
321 static_cast<int16_t>(static_cast<int16_t>(TID1) - 1)}};
322 break;
325 if (auto Err = readIntMax(BIDX, std::numeric_limits::max()))
326 return Err;
327 if (auto Err = readIntMax(NC, std::numeric_limits<int16_t>::max()))
328 return Err;
331 break;
332 default:
334 "region kind is incorrect");
335 }
336 }
337 }
338
339
340 uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd;
341 if (auto Err =
342 readIntMax(LineStartDelta, std::numeric_limits::max()))
343 return Err;
345 return Err;
346 if (ColumnStart > std::numeric_limits::max())
348 "start column is too big");
349 if (auto Err = readIntMax(NumLines, std::numeric_limits::max()))
350 return Err;
351 if (auto Err = readIntMax(ColumnEnd, std::numeric_limits::max()))
352 return Err;
353 LineStart += LineStartDelta;
354
355
356 if (ColumnEnd & (1U << 31)) {
358 ColumnEnd &= ~(1U << 31);
359 }
360
361
362
363
364
365
366
367
368
369 if (ColumnStart == 0 && ColumnEnd == 0) {
370 ColumnStart = 1;
371 ColumnEnd = std::numeric_limits::max();
372 }
373
375 dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":"
376 << ColumnStart << " -> " << (LineStart + NumLines) << ":"
377 << ColumnEnd << ", ";
379 dbgs() << "Expands to file " << ExpandedFileID;
380 else
382 dbgs() << "\n";
383 });
384
386 C, C2, InferredFileID, ExpandedFileID, LineStart, ColumnStart,
387 LineStart + NumLines, ColumnEnd, Kind, Params);
388 if (CMR.startLoc() > CMR.endLoc())
389 return make_error(
391 "counter mapping region locations are incorrect");
392 MappingRegions.push_back(CMR);
393 }
395}
396
398
401 if (auto Err = readSize(NumFileMappings))
402 return Err;
403 for (size_t I = 0; I < NumFileMappings; ++I) {
405 if (auto Err = readIntMax(FilenameIndex, TranslationUnitFilenames.size()))
406 return Err;
407 VirtualFileMapping.push_back(FilenameIndex);
408 }
409
410
411 for (auto I : VirtualFileMapping) {
412 Filenames.push_back(TranslationUnitFilenames[I]);
413 }
414
415
417 if (auto Err = readSize(NumExpressions))
418 return Err;
419
420
421
422 Expressions.resize(
423 NumExpressions,
425 for (size_t I = 0; I < NumExpressions; ++I) {
426 if (auto Err = readCounter(Expressions[I].LHS))
427 return Err;
428 if (auto Err = readCounter(Expressions[I].RHS))
429 return Err;
430 }
431
432
433 for (unsigned InferredFileID = 0, S = VirtualFileMapping.size();
434 InferredFileID < S; ++InferredFileID) {
435 if (auto Err = readMappingRegionsSubArray(MappingRegions, InferredFileID,
436 VirtualFileMapping.size()))
437 return Err;
438 }
439
440
441
442
443
444
446 FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr);
447 for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) {
448 for (auto &R : MappingRegions) {
450 continue;
451 assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]);
452 FileIDExpansionRegionMapping[R.ExpandedFileID] = &R;
453 }
454 for (auto &R : MappingRegions) {
455 if (FileIDExpansionRegionMapping[R.FileID]) {
456 FileIDExpansionRegionMapping[R.FileID]->Count = R.Count;
457 FileIDExpansionRegionMapping[R.FileID] = nullptr;
458 }
459 }
460 }
461
463}
464
466
469 return std::move(Err);
470 if (NumFileMappings != 1)
471 return false;
472
475 readIntMax(FilenameIndex, std::numeric_limits::max()))
476 return std::move(Err);
479 return std::move(Err);
480 if (NumExpressions != 0)
481 return false;
484 return std::move(Err);
485 if (NumRegions != 1)
486 return false;
487 uint64_t EncodedCounterAndRegion;
489 std::numeric_limits::max()))
490 return std::move(Err);
493}
494
495
497 const ObjectFile *Obj = Section.getObject();
498
499
500
501
505 return true;
506 return false;
507}
508
511 if (!DataOrErr)
513 Data = *DataOrErr;
514 Address = Section.getAddress();
515
518
520}
521
529}
530
531
533
534 if (Hash)
535 return false;
537}
538
539
540
544
546 : StartingIndex(StartingIndex), Length(Length) {}
547
550};
551
552namespace {
553
554
555struct CovMapFuncRecordReader {
556 virtual ~CovMapFuncRecordReader() = default;
557
558
559
560
561
562
563
564
566 const char *CovBufEnd) = 0;
567
568
569
570
571
572
573
574
575
576
577
579 readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
580 std::optional OutOfLineFileRange,
581 const char *OutOfLineMappingBuf,
582 const char *OutOfLineMappingBufEnd) = 0;
583
584 template <class IntPtrT, llvm::endianness Endian>
587 std::vectorBinaryCoverageReader::ProfileMappingRecord &R, StringRef D,
588 std::vectorstd::string &F);
589};
590
591
592template <CovMapVersion Version, class IntPtrT, llvm::endianness Endian>
593class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
594 using FuncRecordType =
597
598
599
603 std::vectorstd::string &Filenames;
604 std::vectorBinaryCoverageReader::ProfileMappingRecord &Records;
605
606
607
609
610
611
612
613
614
615
616 Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR,
619 ++CovMapNumRecords;
620 uint64_t FuncHash = CFR->template getFuncHash();
621 NameRefType NameRef = CFR->template getFuncNameRef();
622 auto InsertResult =
623 FunctionRecords.insert(std::make_pair(NameRef, Records.size()));
624 if (InsertResult.second) {
626 if (Error Err = CFR->template getFuncName(ProfileNames, FuncName))
627 return Err;
628 if (FuncName.empty())
629 return make_error(instrprof_error::malformed,
630 "function name is empty");
631 ++CovMapNumUsedRecords;
632 Records.emplace_back(Version, FuncName, FuncHash, Mapping,
635 }
636
637 size_t OldRecordIndex = InsertResult.first->second;
643 return Err;
644 if (!*OldIsDummyExpected)
649 return Err;
650 if (*NewIsDummyExpected)
652 ++CovMapNumUsedRecords;
658 }
659
660public:
661 VersionedCovMapFuncRecordReader(
663 std::vectorBinaryCoverageReader::ProfileMappingRecord &R, StringRef D,
664 std::vectorstd::string &F)
665 : ProfileNames(P), CompilationDir(D), Filenames(F), Records(R) {}
666
667 ~VersionedCovMapFuncRecordReader() override = default;
668
670 const char *CovBufEnd) override {
671 using namespace support;
672
673 if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)
674 return make_error(
675 coveragemap_error::malformed,
676 "coverage mapping header section is larger than buffer size");
677 auto CovHeader = reinterpret_cast<const CovMapHeader *>(CovBuf);
678 uint32_t NRecords = CovHeader->getNRecords<Endian>();
679 uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>();
680 uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>();
682 CovBuf = reinterpret_cast<const char *>(CovHeader + 1);
683
684
685
686
687 const char *FuncRecBuf = nullptr;
688 const char *FuncRecBufEnd = nullptr;
689 if (Version < CovMapVersion::Version4)
690 FuncRecBuf = CovBuf;
691 CovBuf += NRecords * sizeof(FuncRecordType);
692 if (Version < CovMapVersion::Version4)
693 FuncRecBufEnd = CovBuf;
694
695
696 if (CovBuf + FilenamesSize > CovBufEnd)
697 return make_error(
698 coveragemap_error::malformed,
699 "filenames section is larger than buffer size");
700 size_t FilenamesBegin = Filenames.size();
701 StringRef FilenameRegion(CovBuf, FilenamesSize);
703 CompilationDir);
704 if (auto Err = Reader.read(Version))
705 return std::move(Err);
706 CovBuf += FilenamesSize;
707 FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin);
708
709 if (Version >= CovMapVersion::Version4) {
710
711
712 int64_t FilenamesRef =
715 FileRangeMap.insert(std::make_pair(FilenamesRef, FileRange));
716 if (.second) {
717
718
719 auto It = Filenames.begin();
725
726 FileRange = OrigRange;
727 else
728
730 }
731 }
732
733
734
735
736 const char *MappingBuf = CovBuf;
737 if (Version >= CovMapVersion::Version4 && CoverageSize != 0)
738 return make_error(coveragemap_error::malformed,
739 "coverage mapping size is not zero");
740 CovBuf += CoverageSize;
741 const char *MappingEnd = CovBuf;
742
743 if (CovBuf > CovBufEnd)
744 return make_error(
745 coveragemap_error::malformed,
746 "function records section is larger than buffer size");
747
748 if (Version < CovMapVersion::Version4) {
749
750 if (Error E = readFunctionRecords(FuncRecBuf, FuncRecBufEnd, FileRange,
751 MappingBuf, MappingEnd))
752 return std::move(E);
753 }
754
755
756
758
759 return CovBuf;
760 }
761
762 Error readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
763 std::optional OutOfLineFileRange,
764 const char *OutOfLineMappingBuf,
765 const char *OutOfLineMappingBufEnd) override {
766 auto CFR = reinterpret_cast<const FuncRecordType *>(FuncRecBuf);
767 while ((const char *)CFR < FuncRecBufEnd) {
768
769 const char *NextMappingBuf;
770 const FuncRecordType *NextCFR;
771 std::tie(NextMappingBuf, NextCFR) =
772 CFR->template advanceByOne(OutOfLineMappingBuf);
773 if (Version < CovMapVersion::Version4)
774 if (NextMappingBuf > OutOfLineMappingBufEnd)
775 return make_error(
776 coveragemap_error::malformed,
777 "next mapping buffer is larger than buffer size");
778
779
780 std::optional FileRange;
781 if (Version < CovMapVersion::Version4) {
782 FileRange = OutOfLineFileRange;
783 } else {
784 uint64_t FilenamesRef = CFR->template getFilenamesRef();
785 auto It = FileRangeMap.find(FilenamesRef);
786 if (It == FileRangeMap.end())
787 return make_error(
788 coveragemap_error::malformed,
789 "no filename found for function with hash=0x" +
791 else
792 FileRange = It->getSecond();
793 }
794
795
796 if (FileRange && !FileRange->isInvalid()) {
798 CFR->template getCoverageMapping(OutOfLineMappingBuf);
799 if (Version >= CovMapVersion::Version4 &&
800 Mapping.data() + Mapping.size() > FuncRecBufEnd)
801 return make_error(
802 coveragemap_error::malformed,
803 "coverage mapping data is larger than buffer size");
804 if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange))
805 return Err;
806 }
807
808 std::tie(OutOfLineMappingBuf, CFR) = std::tie(NextMappingBuf, NextCFR);
809 }
811 }
812};
813
814}
815
816template <class IntPtrT, llvm::endianness Endian>
819 std::vectorBinaryCoverageReader::ProfileMappingRecord &R, StringRef D,
820 std::vectorstd::string &F) {
821 using namespace coverage;
822
825 return std::make_unique<VersionedCovMapFuncRecordReader<
833
834 if (Error E = P.create(P.getNameData()))
835 return std::move(E);
837 return std::make_unique<VersionedCovMapFuncRecordReader<
840 return std::make_unique<VersionedCovMapFuncRecordReader<
843 return std::make_unique<VersionedCovMapFuncRecordReader<
846 return std::make_unique<VersionedCovMapFuncRecordReader<
849 return std::make_unique<VersionedCovMapFuncRecordReader<
852 return std::make_unique<VersionedCovMapFuncRecordReader<
854 }
856}
857
858template <typename T, llvm::endianness Endian>
861 std::vectorBinaryCoverageReader::ProfileMappingRecord &Records,
862 StringRef CompilationDir, std::vectorstd::string &Filenames) {
863 using namespace coverage;
864
865
866 auto CovHeader =
872 CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records,
873 CompilationDir, Filenames);
875 return E;
876 auto Reader = std::move(ReaderExpected.get());
877 const char *CovBuf = CovMap.data();
878 const char *CovBufEnd = CovBuf + CovMap.size();
879 const char *FuncRecBuf = FuncRecords.data();
880 const char *FuncRecBufEnd = FuncRecords.data() + FuncRecords.size();
881 while (CovBuf < CovBufEnd) {
882
883
884
885
886
887
888 auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd);
889 if (auto E = NextOrErr.takeError())
890 return E;
891 CovBuf = NextOrErr.get();
892 }
893
894
896 return Reader->readFunctionRecords(FuncRecBuf, FuncRecBufEnd, std::nullopt,
897 nullptr, nullptr);
899}
900
905 std::unique_ptr ProfileNamesPtr, uint8_t BytesInAddress,
907 if (ProfileNamesPtr == nullptr)
909 "Caller must provide ProfileNames");
910 std::unique_ptr Reader(
912 std::move(FuncRecords), std::move(CoverageMap)));
914 StringRef FuncRecordsRef = Reader->FuncRecords->getBuffer();
916 if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::little>(
917 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
918 CompilationDir, Reader->Filenames))
919 return std::move(E);
921 if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::big>(
922 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
923 CompilationDir, Reader->Filenames))
924 return std::move(E);
926 if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::little>(
927 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
928 CompilationDir, Reader->Filenames))
929 return std::move(E);
931 if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::big>(
932 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
933 CompilationDir, Reader->Filenames))
934 return std::move(E);
935 } else
936 return make_error(
938 "not supported endianness or bytes in address");
939 return std::move(Reader);
940}
941
944 uint8_t BytesInAddress = 8;
946
947
951 "the size of data is too small");
952 auto TestingVersion =
953 support::endian::byte_swap<uint64_t, llvm::endianness::little>(
954 *reinterpret_cast<const uint64_t *>(Data.data()));
956
957
958 if (Data.empty())
960 unsigned N = 0;
963 return make_error(
965 "the size of TestingFormatMagic is too big");
967 if (Data.empty())
969 N = 0;
973 "the size of ULEB128 is too big");
975 if (Data.size() < ProfileNamesSize)
977 "the size of ProfileNames is too big");
978 auto ProfileNames = std::make_unique();
980 return std::move(E);
981 Data = Data.substr(ProfileNamesSize);
982
983
984 uint64_t CoverageMappingSize;
986 N = 0;
990 "the size of ULEB128 is too big");
992 if (CoverageMappingSize < sizeof(CovMapHeader))
993 return make_error(
995 "the size of CoverageMapping is teoo small");
998 }
999
1000
1002 if (Data.size() < Pad)
1004 "insufficient padding");
1007 return make_error(
1009 "coverage mapping header section is larger than data size");
1010 auto const *CovHeader = reinterpret_cast<const CovMapHeader *>(
1014
1015
1018 CoverageMappingSize = Data.size();
1019 } else {
1020 auto FilenamesSize =
1022 CoverageMappingSize = sizeof(CovMapHeader) + FilenamesSize;
1023 }
1024 }
1025
1027 Data = Data.substr(CoverageMappingSize);
1028
1029
1031 if (.empty())
1033 "data is not empty");
1034 } else {
1035
1036
1038 if (Data.size() < Pad)
1040 "insufficient padding");
1042 }
1045
1048 std::move(ProfileNames), BytesInAddress, Endian, CompilationDir);
1049}
1050
1051
1052
1058
1059
1060
1061 bool IsCOFF = isa(OF);
1062 auto stripSuffix = [IsCOFF](StringRef N) {
1063 return IsCOFF ? N.split('$').first : N;
1064 };
1066
1067 std::vector Sections;
1068 for (const auto &Section : OF.sections()) {
1070 if (!NameOrErr)
1072 if (stripSuffix(*NameOrErr) == Name) {
1073
1074
1075
1076 if (IPSK == IPSK_name &&
1077 (Section.getSize() == 0 || (IsCOFF && Section.getSize() == 2)))
1078 continue;
1079 Sections.push_back(Section);
1080 }
1081 }
1082 if (Sections.empty())
1084 return Sections;
1085}
1086
1087
1088
1089
1092
1093 if (auto *WOF = dyn_cast(&OF)) {
1094 std::vector<const WasmSegment *> Segments;
1098 for (const auto &DebugName : WOF->debugNames()) {
1100 DebugName.Name != Name)
1101 continue;
1102 if (DebugName.Index >= WOF->dataSegments().size())
1104 auto &Segment = WOF->dataSegments()[DebugName.Index];
1105 Segments.push_back(&Segment);
1106 }
1107 if (Segments.empty())
1109 if (Segments.size() != 1)
1111
1112 const auto &Segment = *Segments.front();
1113 auto &Data = Segment.Data;
1115 Data.Content.size());
1116 return std::make_pair(Content, Segment.SectionOffset);
1117 }
1118
1119
1121 if (!Sections)
1122 return Sections.takeError();
1123 if (Sections->size() != 1)
1124 return make_error(
1126 "the size of coverage mapping section is not one");
1127 auto &Section = Sections->front();
1128 auto ContentsOrErr = Section.getContents();
1129 if (!ContentsOrErr)
1130 return ContentsOrErr.takeError();
1131 auto Content = *ContentsOrErr;
1134 return std::make_pair(Content, Section.getAddress());
1135}
1136
1141 std::unique_ptr OF;
1142 if (auto *Universal = dyn_cast(Bin.get())) {
1143
1144
1145 auto ObjectFileOrErr = Universal->getMachOObjectForArch(Arch);
1146 if (!ObjectFileOrErr)
1147 return ObjectFileOrErr.takeError();
1148 OF = std::move(ObjectFileOrErr.get());
1149 } else if (isa(Bin.get())) {
1150
1151 OF.reset(cast(Bin.release()));
1152
1153 if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch())
1155 } else
1156
1158 "binary is not an object file");
1159
1160
1161 uint8_t BytesInAddress = OF->getBytesInAddress();
1164
1165
1166 auto ProfileNames = std::make_unique();
1167
1168
1170 if (auto E = NamesSection.takeError()) {
1173 if (auto E = NamesSection.takeError())
1174 return std::move(E);
1175 }
1176
1179 std::tie(NamesContent, NamesAddress) = *NamesSection;
1180 if (Error E = ProfileNames->create(NamesContent, NamesAddress))
1181 return std::move(E);
1182
1183 auto CoverageSection = lookupSections(*OF, IPSK_covmap);
1184 if (auto E = CoverageSection.takeError())
1185 return std::move(E);
1186 std::vector CoverageSectionRefs = *CoverageSection;
1187 if (CoverageSectionRefs.size() != 1)
1189 "the size of name section is not one");
1190 auto CoverageMappingOrErr = CoverageSectionRefs.back().getContents();
1191 if (!CoverageMappingOrErr)
1192 return CoverageMappingOrErr.takeError();
1194
1195
1196
1197
1198 std::unique_ptr CoverageMapCopy;
1202 }
1203
1204
1205 auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun);
1206
1208 if (auto E = CoverageRecordsSections.takeError()) {
1211 } else {
1212
1213
1214
1215
1216 const Align RecordAlignment(8);
1217 uint64_t FuncRecordsSize = 0;
1218 for (SectionRef Section : *CoverageRecordsSections) {
1219 auto CoverageRecordsOrErr = Section.getContents();
1220 if (!CoverageRecordsOrErr)
1221 return CoverageRecordsOrErr.takeError();
1222 FuncRecordsSize += alignTo(CoverageRecordsOrErr->size(), RecordAlignment);
1223 }
1224 auto WritableBuffer =
1226 char *FuncRecordsBuffer = WritableBuffer->getBufferStart();
1228 "Allocated memory is correctly aligned");
1229
1230 for (SectionRef Section : *CoverageRecordsSections) {
1231 auto CoverageRecordsOrErr = Section.getContents();
1232 if (!CoverageRecordsOrErr)
1233 return CoverageRecordsOrErr.takeError();
1234 const auto &CoverageRecords = CoverageRecordsOrErr.get();
1235 FuncRecordsBuffer = std::copy(CoverageRecords.begin(),
1236 CoverageRecords.end(), FuncRecordsBuffer);
1237 FuncRecordsBuffer =
1238 std::fill_n(FuncRecordsBuffer,
1239 alignAddr(FuncRecordsBuffer, RecordAlignment) -
1240 (uintptr_t)FuncRecordsBuffer,
1241 '\0');
1242 }
1243 assert(FuncRecordsBuffer == WritableBuffer->getBufferEnd() &&
1244 "consistent init");
1245 FuncRecords = std::move(WritableBuffer);
1246 }
1247
1248 if (BinaryID)
1250
1252 CoverageMapping, std::move(FuncRecords), std::move(CoverageMapCopy),
1253 std::move(ProfileNames), BytesInAddress, Endian, CompilationDir);
1254}
1255
1256
1258
1259
1260 if (auto *Universal = dyn_cast(Bin)) {
1261 for (auto &ObjForArch : Universal->objects())
1262 if (Arch == ObjForArch.getArchFlagName())
1263 return false;
1264 return true;
1265 }
1266 return false;
1267}
1268
1272 SmallVectorImpl<std::unique_ptr> &ObjectFileBuffers,
1274 std::vector<std::unique_ptr> Readers;
1275
1278 support::endian::byte_swap<uint64_t, llvm::endianness::little>(
1281
1282 auto ReaderOrErr =
1284 if (!ReaderOrErr)
1285 return ReaderOrErr.takeError();
1286 Readers.push_back(std::move(ReaderOrErr.get()));
1287 return std::move(Readers);
1288 }
1289 }
1290
1292 if (!BinOrErr)
1293 return BinOrErr.takeError();
1294 std::unique_ptr Bin = std::move(BinOrErr.get());
1295
1297 return make_error(
1299
1300
1301
1302 if (auto *Universal = dyn_cast(Bin.get())) {
1303 for (auto &ObjForArch : Universal->objects()) {
1304
1305 std::string ObjArch = ObjForArch.getArchFlagName();
1306 if (Arch != ObjArch)
1307 continue;
1308
1309 auto ArchiveOrErr = ObjForArch.getAsArchive();
1310 if (!ArchiveOrErr) {
1311
1313 break;
1314 }
1315
1317 ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers,
1318 CompilationDir, BinaryIDs);
1319 }
1320 }
1321
1322
1323 if (auto *Ar = dyn_cast(Bin.get())) {
1325 for (auto &Child : Ar->children(Err)) {
1327 if (!ChildBufOrErr)
1328 return ChildBufOrErr.takeError();
1329
1331 ChildBufOrErr.get(), Arch, ObjectFileBuffers, CompilationDir,
1332 BinaryIDs);
1333 if (!ChildReadersOrErr)
1334 return ChildReadersOrErr.takeError();
1335 for (auto &Reader : ChildReadersOrErr.get())
1336 Readers.push_back(std::move(Reader));
1337 }
1338 if (Err)
1339 return std::move(Err);
1340
1341
1342
1343
1344 if (Ar->isThin())
1345 for (auto &Buffer : Ar->takeThinBuffers())
1346 ObjectFileBuffers.push_back(std::move(Buffer));
1347
1348 return std::move(Readers);
1349 }
1350
1352 auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch, CompilationDir,
1353 BinaryIDs ? &BinaryID : nullptr);
1354 if (!ReaderOrErr)
1355 return ReaderOrErr.takeError();
1356 Readers.push_back(std::move(ReaderOrErr.get()));
1357 if (!BinaryID.empty())
1359 return std::move(Readers);
1360}
1361
1363 if (CurrentRecord >= MappingRecords.size())
1365
1366 FunctionsFilenames.clear();
1367 Expressions.clear();
1368 MappingRegions.clear();
1369 auto &R = MappingRecords[CurrentRecord];
1370 auto F = ArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize);
1372 Expressions, MappingRegions);
1373 if (auto Err = Reader.read())
1374 return Err;
1375
1376 Record.FunctionName = R.FunctionName;
1377 Record.FunctionHash = R.FunctionHash;
1378 Record.Filenames = FunctionsFilenames;
1379 Record.Expressions = Expressions;
1380 Record.MappingRegions = MappingRegions;
1381
1382 ++CurrentRecord;
1384}
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static Error readCoverageMappingData(InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords, std::vector< BinaryCoverageReader::ProfileMappingRecord > &Records, StringRef CompilationDir, std::vector< std::string > &Filenames)
static Expected< std::pair< StringRef, uint64_t > > lookupAllocatableSection(ObjectFile &OF, InstrProfSectKind IPSK)
Find a section that matches Name and is allocatable at runtime.
static Expected< std::unique_ptr< BinaryCoverageReader > > loadBinaryFormat(std::unique_ptr< Binary > Bin, StringRef Arch, StringRef CompilationDir="", object::BuildIDRef *BinaryID=nullptr)
static Expected< std::unique_ptr< BinaryCoverageReader > > loadTestingFormat(StringRef Data, StringRef CompilationDir)
static Expected< std::vector< SectionRef > > lookupSections(ObjectFile &OF, InstrProfSectKind IPSK)
Find all sections that match IPSK name.
static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch)
Determine whether Arch is invalid or empty, given Bin.
static bool shouldSkipSectionFirstByte(SectionRef &Section)
Determine if we should skip the first byte of the section content.
static Expected< bool > isCoverageMappingDummy(uint64_t Hash, StringRef Mapping)
static const unsigned EncodingExpansionRegionBit
This file defines the DenseMap class.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
reference get()
Returns a reference to the stored T value.
A symbol table used for function [IR]PGO name look-up with keys (such as pointers,...
Error create(object::SectionRef &Section)
Create InstrProfSymtab from an object file section which contains function PGO names.
StringRef getFuncName(uint64_t FuncNameAddress, size_t NameSize)
Return function's PGO name from the function name's symbol address in the object file.
const char * getBufferStart() const
StringRef getBuffer() const
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
Pass interface - Implemented by all 'passes'.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
constexpr bool empty() const
empty - Check if the string is empty.
constexpr size_t size() const
size - Get the string size.
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
const unsigned char * bytes_begin() const
Triple - Helper class for working with autoconf configuration names.
static Twine utohexstr(const uint64_t &Val)
LLVM Value Representation.
static std::unique_ptr< WritableMemoryBuffer > getNewUninitMemBuffer(size_t Size, const Twine &BufferName="", std::optional< Align > Alignment=std::nullopt)
Allocate a new MemoryBuffer of the specified size that is not initialized.
Reader for the coverage mapping data that is emitted by the frontend and stored in an object file.
static Expected< std::unique_ptr< BinaryCoverageReader > > createCoverageReaderFromBuffer(StringRef Coverage, FuncRecordsStorage &&FuncRecords, CoverageMapCopyStorage &&CoverageMap, std::unique_ptr< InstrProfSymtab > ProfileNamesPtr, uint8_t BytesInAddress, llvm::endianness Endian, StringRef CompilationDir="")
std::unique_ptr< MemoryBuffer > CoverageMapCopyStorage
static Expected< std::vector< std::unique_ptr< BinaryCoverageReader > > > create(MemoryBufferRef ObjectBuffer, StringRef Arch, SmallVectorImpl< std::unique_ptr< MemoryBuffer > > &ObjectFileBuffers, StringRef CompilationDir="", SmallVectorImpl< object::BuildIDRef > *BinaryIDs=nullptr)
std::unique_ptr< MemoryBuffer > FuncRecordsStorage
Error readNextRecord(CoverageMappingRecord &Record) override
A Counter mapping context is used to connect the counters, expressions and the obtained counter value...
void dump(const Counter &C, raw_ostream &OS) const
coveragemap_error get() const
A file format agnostic iterator over coverage mapping data.
virtual Error readNextRecord(CoverageMappingRecord &Record)=0
The mapping of profile information to coverage data.
Reader for the raw coverage filenames.
Error read(CovMapVersion Version)
Checks if the given coverage mapping data is exported for an unused function.
Expected< bool > isDummy()
Reader for the raw coverage mapping data.
Error readSize(uint64_t &Result)
Error readIntMax(uint64_t &Result, uint64_t MaxPlus1)
Error readULEB128(uint64_t &Result)
Error readString(StringRef &Result)
Triple::ObjectFormatType getTripleObjectFormat() const
This class is the base class for all object file types.
section_iterator_range sections() const
virtual bool isRelocatableObject() const =0
True if this is a relocatable object (.o/.obj).
Represents a GOFF physical record.
This is a value type class that represents a single section in the list of sections in the object fil...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
uint64_t ComputeHash(StringRef K)
llvm::SmallVector< std::shared_ptr< RecordsSlice >, 4 > Records
Error decompress(ArrayRef< uint8_t > Input, uint8_t *Output, size_t &UncompressedSize)
std::variant< std::monostate, DecisionParameters, BranchParameters > Parameters
The type of MC/DC-specific parameters.
@ invalid_or_missing_arch_specifier
constexpr uint64_t TestingFormatMagic
BuildIDRef getBuildID(const ObjectFile *Obj)
Returns the build ID, if any, contained in the given object file.
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
This is an optimization pass for GlobalISel generic memory operations.
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
uint64_t decodeULEB128(const uint8_t *p, unsigned *n=nullptr, const uint8_t *end=nullptr, const char **error=nullptr)
Utility function to decode a ULEB128 value.
uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment)
Returns the necessary adjustment for aligning Addr to Alignment bytes, rounding up.
std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
void consumeError(Error Err)
Consume a Error without doing anything.
bool isAddrAligned(Align Lhs, const void *Addr)
Checks that Addr is a multiple of the alignment.
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
A range of filename indices.
FilenameRange(unsigned StartingIndex, unsigned Length)
This struct is a compact representation of a valid (non-zero power of two) alignment.
StringRef CoverageMapping
A Counter expression is a value that represents an arithmetic operation with two counters.
A Counter mapping region associates a source range with a specific counter.
@ ExpansionRegion
An ExpansionRegion represents a file expansion region that associates a source range with the expansi...
@ MCDCDecisionRegion
A DecisionRegion represents a top-level boolean expression and is associated with a variable length b...
@ MCDCBranchRegion
A Branch Region can be extended to include IDs to facilitate MC/DC.
@ SkippedRegion
A SkippedRegion represents a source range with code that was skipped by a preprocessor or similar mea...
@ GapRegion
A GapRegion is like a CodeRegion, but its count is only set as the line execution count when its the ...
@ BranchRegion
A BranchRegion represents leaf-level boolean expressions and is associated with two counters,...
@ CodeRegion
A CodeRegion associates some code with a counter.
A Counter is an abstract value that describes how to compute the execution count for a region of code...
static const unsigned EncodingTagBits
static Counter getZero()
Return the counter that represents the number zero.
static Counter getCounter(unsigned CounterId)
Return the counter that corresponds to a specific profile counter.
static const unsigned EncodingCounterTagAndExpansionRegionTagBits
static const unsigned EncodingTagMask
static Counter getExpression(unsigned ExpressionId)
Return the counter that corresponds to a specific addition counter expression.
Coverage mapping information for a single function.