172208a82SEugene Zelenko //===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===//
2dc707122SEaswaran Raman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dc707122SEaswaran Raman //
7dc707122SEaswaran Raman //===----------------------------------------------------------------------===//
8dc707122SEaswaran Raman //
9dc707122SEaswaran Raman // This file contains support for reading coverage mapping data for
10dc707122SEaswaran Raman // instrumentation based coverage.
11dc707122SEaswaran Raman //
12dc707122SEaswaran Raman //===----------------------------------------------------------------------===//
13dc707122SEaswaran Raman 
144a5ddf80SXinliang David Li #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
15e78d131aSEugene Zelenko #include "llvm/ADT/ArrayRef.h"
16ac40e819SIgor Kudrin #include "llvm/ADT/DenseMap.h"
17e78d131aSEugene Zelenko #include "llvm/ADT/STLExtras.h"
184a5ddf80SXinliang David Li #include "llvm/ADT/SmallVector.h"
19dd1ea9deSVedant Kumar #include "llvm/ADT/Statistic.h"
20e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h"
21e78d131aSEugene Zelenko #include "llvm/ADT/Triple.h"
22e78d131aSEugene Zelenko #include "llvm/Object/Binary.h"
23ba7a92c0SNico Weber #include "llvm/Object/COFF.h"
24e78d131aSEugene Zelenko #include "llvm/Object/Error.h"
25dc707122SEaswaran Raman #include "llvm/Object/MachOUniversal.h"
26dc707122SEaswaran Raman #include "llvm/Object/ObjectFile.h"
27e78d131aSEugene Zelenko #include "llvm/ProfileData/InstrProf.h"
28e78d131aSEugene Zelenko #include "llvm/Support/Casting.h"
29dd1ea9deSVedant Kumar #include "llvm/Support/Compression.h"
30dc707122SEaswaran Raman #include "llvm/Support/Debug.h"
314a5ddf80SXinliang David Li #include "llvm/Support/Endian.h"
32e78d131aSEugene Zelenko #include "llvm/Support/Error.h"
33e78d131aSEugene Zelenko #include "llvm/Support/ErrorHandling.h"
34dc707122SEaswaran Raman #include "llvm/Support/LEB128.h"
35dc707122SEaswaran Raman #include "llvm/Support/MathExtras.h"
36ba7a92c0SNico Weber #include "llvm/Support/Path.h"
37dc707122SEaswaran Raman #include "llvm/Support/raw_ostream.h"
38e78d131aSEugene Zelenko #include <vector>
39dc707122SEaswaran Raman 
40dc707122SEaswaran Raman using namespace llvm;
41dc707122SEaswaran Raman using namespace coverage;
42dc707122SEaswaran Raman using namespace object;
43dc707122SEaswaran Raman 
44dc707122SEaswaran Raman #define DEBUG_TYPE "coverage-mapping"
45dc707122SEaswaran Raman 
46dd1ea9deSVedant Kumar STATISTIC(CovMapNumRecords, "The # of coverage function records");
47dd1ea9deSVedant Kumar STATISTIC(CovMapNumUsedRecords, "The # of used coverage function records");
48dd1ea9deSVedant Kumar 
49dc707122SEaswaran Raman void CoverageMappingIterator::increment() {
50bae83970SVedant Kumar   if (ReadErr != coveragemap_error::success)
51bae83970SVedant Kumar     return;
52bae83970SVedant Kumar 
53dc707122SEaswaran Raman   // Check if all the records were read or if an error occurred while reading
54dc707122SEaswaran Raman   // the next record.
55bae83970SVedant Kumar   if (auto E = Reader->readNextRecord(Record))
569152fd17SVedant Kumar     handleAllErrors(std::move(E), [&](const CoverageMapError &CME) {
579152fd17SVedant Kumar       if (CME.get() == coveragemap_error::eof)
58dc707122SEaswaran Raman         *this = CoverageMappingIterator();
599152fd17SVedant Kumar       else
60bae83970SVedant Kumar         ReadErr = CME.get();
619152fd17SVedant Kumar     });
629152fd17SVedant Kumar }
63dc707122SEaswaran Raman 
649152fd17SVedant Kumar Error RawCoverageReader::readULEB128(uint64_t &Result) {
6572208a82SEugene Zelenko   if (Data.empty())
669152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::truncated);
67dc707122SEaswaran Raman   unsigned N = 0;
686a0746a9SFangrui Song   Result = decodeULEB128(Data.bytes_begin(), &N);
69dc707122SEaswaran Raman   if (N > Data.size())
709152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
71dc707122SEaswaran Raman   Data = Data.substr(N);
729152fd17SVedant Kumar   return Error::success();
73dc707122SEaswaran Raman }
74dc707122SEaswaran Raman 
759152fd17SVedant Kumar Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) {
76dc707122SEaswaran Raman   if (auto Err = readULEB128(Result))
77dc707122SEaswaran Raman     return Err;
78dc707122SEaswaran Raman   if (Result >= MaxPlus1)
799152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
809152fd17SVedant Kumar   return Error::success();
81dc707122SEaswaran Raman }
82dc707122SEaswaran Raman 
839152fd17SVedant Kumar Error RawCoverageReader::readSize(uint64_t &Result) {
84dc707122SEaswaran Raman   if (auto Err = readULEB128(Result))
85dc707122SEaswaran Raman     return Err;
86dc707122SEaswaran Raman   // Sanity check the number.
87dc707122SEaswaran Raman   if (Result > Data.size())
889152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
899152fd17SVedant Kumar   return Error::success();
90dc707122SEaswaran Raman }
91dc707122SEaswaran Raman 
929152fd17SVedant Kumar Error RawCoverageReader::readString(StringRef &Result) {
93dc707122SEaswaran Raman   uint64_t Length;
94dc707122SEaswaran Raman   if (auto Err = readSize(Length))
95dc707122SEaswaran Raman     return Err;
96dc707122SEaswaran Raman   Result = Data.substr(0, Length);
97dc707122SEaswaran Raman   Data = Data.substr(Length);
989152fd17SVedant Kumar   return Error::success();
99dc707122SEaswaran Raman }
100dc707122SEaswaran Raman 
1015fbd1a33SPetr Hosek Error RawCoverageFilenamesReader::read(CovMapVersion Version) {
102dc707122SEaswaran Raman   uint64_t NumFilenames;
103dc707122SEaswaran Raman   if (auto Err = readSize(NumFilenames))
104dc707122SEaswaran Raman     return Err;
105dd1ea9deSVedant Kumar   if (!NumFilenames)
106dd1ea9deSVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
107dd1ea9deSVedant Kumar 
108dd1ea9deSVedant Kumar   if (Version < CovMapVersion::Version4)
1095fbd1a33SPetr Hosek     return readUncompressed(Version, NumFilenames);
110dd1ea9deSVedant Kumar 
111dd1ea9deSVedant Kumar   // The uncompressed length may exceed the size of the encoded filenames.
112dd1ea9deSVedant Kumar   // Skip size validation.
113dd1ea9deSVedant Kumar   uint64_t UncompressedLen;
114dd1ea9deSVedant Kumar   if (auto Err = readULEB128(UncompressedLen))
115dd1ea9deSVedant Kumar     return Err;
116dd1ea9deSVedant Kumar 
117dd1ea9deSVedant Kumar   uint64_t CompressedLen;
118dd1ea9deSVedant Kumar   if (auto Err = readSize(CompressedLen))
119dd1ea9deSVedant Kumar     return Err;
120dd1ea9deSVedant Kumar 
121dd1ea9deSVedant Kumar   if (CompressedLen > 0) {
122dd1ea9deSVedant Kumar     if (!zlib::isAvailable())
123dd1ea9deSVedant Kumar       return make_error<CoverageMapError>(
124dd1ea9deSVedant Kumar           coveragemap_error::decompression_failed);
125dd1ea9deSVedant Kumar 
1265fbd1a33SPetr Hosek     // Allocate memory for the decompressed filenames.
1275fbd1a33SPetr Hosek     SmallVector<char, 0> StorageBuf;
128dd1ea9deSVedant Kumar 
129dd1ea9deSVedant Kumar     // Read compressed filenames.
130dd1ea9deSVedant Kumar     StringRef CompressedFilenames = Data.substr(0, CompressedLen);
131dd1ea9deSVedant Kumar     Data = Data.substr(CompressedLen);
132dd1ea9deSVedant Kumar     auto Err =
133dd1ea9deSVedant Kumar         zlib::uncompress(CompressedFilenames, StorageBuf, UncompressedLen);
134dd1ea9deSVedant Kumar     if (Err) {
135dd1ea9deSVedant Kumar       consumeError(std::move(Err));
136dd1ea9deSVedant Kumar       return make_error<CoverageMapError>(
137dd1ea9deSVedant Kumar           coveragemap_error::decompression_failed);
138dd1ea9deSVedant Kumar     }
139dd1ea9deSVedant Kumar 
140dd1ea9deSVedant Kumar     StringRef UncompressedFilenames(StorageBuf.data(), StorageBuf.size());
141dd1ea9deSVedant Kumar     RawCoverageFilenamesReader Delegate(UncompressedFilenames, Filenames);
1425fbd1a33SPetr Hosek     return Delegate.readUncompressed(Version, NumFilenames);
143dd1ea9deSVedant Kumar   }
144dd1ea9deSVedant Kumar 
1455fbd1a33SPetr Hosek   return readUncompressed(Version, NumFilenames);
146dd1ea9deSVedant Kumar }
147dd1ea9deSVedant Kumar 
1485fbd1a33SPetr Hosek Error RawCoverageFilenamesReader::readUncompressed(CovMapVersion Version,
1495fbd1a33SPetr Hosek                                                    uint64_t NumFilenames) {
150dd1ea9deSVedant Kumar   // Read uncompressed filenames.
1515fbd1a33SPetr Hosek   if (Version < CovMapVersion::Version6) {
152dc707122SEaswaran Raman     for (size_t I = 0; I < NumFilenames; ++I) {
153dc707122SEaswaran Raman       StringRef Filename;
154dc707122SEaswaran Raman       if (auto Err = readString(Filename))
155dc707122SEaswaran Raman         return Err;
1565fbd1a33SPetr Hosek       Filenames.push_back(Filename.str());
1575fbd1a33SPetr Hosek     }
1585fbd1a33SPetr Hosek   } else {
1595fbd1a33SPetr Hosek     StringRef CWD;
1605fbd1a33SPetr Hosek     if (auto Err = readString(CWD))
1615fbd1a33SPetr Hosek       return Err;
1625fbd1a33SPetr Hosek     Filenames.push_back(CWD.str());
1635fbd1a33SPetr Hosek 
1645fbd1a33SPetr Hosek     for (size_t I = 1; I < NumFilenames; ++I) {
1655fbd1a33SPetr Hosek       StringRef Filename;
1665fbd1a33SPetr Hosek       if (auto Err = readString(Filename))
1675fbd1a33SPetr Hosek         return Err;
1685fbd1a33SPetr Hosek       if (sys::path::is_absolute(Filename)) {
1695fbd1a33SPetr Hosek         Filenames.push_back(Filename.str());
1705fbd1a33SPetr Hosek       } else {
1715fbd1a33SPetr Hosek         SmallString<256> P(CWD);
1725fbd1a33SPetr Hosek         llvm::sys::path::append(P, Filename);
1735fbd1a33SPetr Hosek         Filenames.push_back(static_cast<std::string>(P));
1745fbd1a33SPetr Hosek       }
1755fbd1a33SPetr Hosek     }
176dc707122SEaswaran Raman   }
1779152fd17SVedant Kumar   return Error::success();
178dc707122SEaswaran Raman }
179dc707122SEaswaran Raman 
1809152fd17SVedant Kumar Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) {
181dc707122SEaswaran Raman   auto Tag = Value & Counter::EncodingTagMask;
182dc707122SEaswaran Raman   switch (Tag) {
183dc707122SEaswaran Raman   case Counter::Zero:
184dc707122SEaswaran Raman     C = Counter::getZero();
1859152fd17SVedant Kumar     return Error::success();
186dc707122SEaswaran Raman   case Counter::CounterValueReference:
187dc707122SEaswaran Raman     C = Counter::getCounter(Value >> Counter::EncodingTagBits);
1889152fd17SVedant Kumar     return Error::success();
189dc707122SEaswaran Raman   default:
190dc707122SEaswaran Raman     break;
191dc707122SEaswaran Raman   }
192dc707122SEaswaran Raman   Tag -= Counter::Expression;
193dc707122SEaswaran Raman   switch (Tag) {
194dc707122SEaswaran Raman   case CounterExpression::Subtract:
195dc707122SEaswaran Raman   case CounterExpression::Add: {
196dc707122SEaswaran Raman     auto ID = Value >> Counter::EncodingTagBits;
197dc707122SEaswaran Raman     if (ID >= Expressions.size())
1989152fd17SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
199dc707122SEaswaran Raman     Expressions[ID].Kind = CounterExpression::ExprKind(Tag);
200dc707122SEaswaran Raman     C = Counter::getExpression(ID);
201dc707122SEaswaran Raman     break;
202dc707122SEaswaran Raman   }
203dc707122SEaswaran Raman   default:
2049152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
205dc707122SEaswaran Raman   }
2069152fd17SVedant Kumar   return Error::success();
207dc707122SEaswaran Raman }
208dc707122SEaswaran Raman 
2099152fd17SVedant Kumar Error RawCoverageMappingReader::readCounter(Counter &C) {
210dc707122SEaswaran Raman   uint64_t EncodedCounter;
211dc707122SEaswaran Raman   if (auto Err =
212dc707122SEaswaran Raman           readIntMax(EncodedCounter, std::numeric_limits<unsigned>::max()))
213dc707122SEaswaran Raman     return Err;
214dc707122SEaswaran Raman   if (auto Err = decodeCounter(EncodedCounter, C))
215dc707122SEaswaran Raman     return Err;
2169152fd17SVedant Kumar   return Error::success();
217dc707122SEaswaran Raman }
218dc707122SEaswaran Raman 
219dc707122SEaswaran Raman static const unsigned EncodingExpansionRegionBit = 1
220dc707122SEaswaran Raman                                                    << Counter::EncodingTagBits;
221dc707122SEaswaran Raman 
2225f8f34e4SAdrian Prantl /// Read the sub-array of regions for the given inferred file id.
223dc707122SEaswaran Raman /// \param NumFileIDs the number of file ids that are defined for this
224dc707122SEaswaran Raman /// function.
2259152fd17SVedant Kumar Error RawCoverageMappingReader::readMappingRegionsSubArray(
226dc707122SEaswaran Raman     std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID,
227dc707122SEaswaran Raman     size_t NumFileIDs) {
228dc707122SEaswaran Raman   uint64_t NumRegions;
229dc707122SEaswaran Raman   if (auto Err = readSize(NumRegions))
230dc707122SEaswaran Raman     return Err;
231dc707122SEaswaran Raman   unsigned LineStart = 0;
232dc707122SEaswaran Raman   for (size_t I = 0; I < NumRegions; ++I) {
2339f2967bcSAlan Phipps     Counter C, C2;
234dc707122SEaswaran Raman     CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion;
235dc707122SEaswaran Raman 
236dc707122SEaswaran Raman     // Read the combined counter + region kind.
237dc707122SEaswaran Raman     uint64_t EncodedCounterAndRegion;
238dc707122SEaswaran Raman     if (auto Err = readIntMax(EncodedCounterAndRegion,
239dc707122SEaswaran Raman                               std::numeric_limits<unsigned>::max()))
240dc707122SEaswaran Raman       return Err;
241dc707122SEaswaran Raman     unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask;
242dc707122SEaswaran Raman     uint64_t ExpandedFileID = 0;
2439f2967bcSAlan Phipps 
2449f2967bcSAlan Phipps     // If Tag does not represent a ZeroCounter, then it is understood to refer
2459f2967bcSAlan Phipps     // to a counter or counter expression with region kind assumed to be
2469f2967bcSAlan Phipps     // "CodeRegion". In that case, EncodedCounterAndRegion actually encodes the
2479f2967bcSAlan Phipps     // referenced counter or counter expression (and nothing else).
2489f2967bcSAlan Phipps     //
2499f2967bcSAlan Phipps     // If Tag represents a ZeroCounter and EncodingExpansionRegionBit is set,
2509f2967bcSAlan Phipps     // then EncodedCounterAndRegion is interpreted to represent an
2519f2967bcSAlan Phipps     // ExpansionRegion. In all other cases, EncodedCounterAndRegion is
2529f2967bcSAlan Phipps     // interpreted to refer to a specific region kind, after which additional
2539f2967bcSAlan Phipps     // fields may be read (e.g. BranchRegions have two encoded counters that
2549f2967bcSAlan Phipps     // follow an encoded region kind value).
255dc707122SEaswaran Raman     if (Tag != Counter::Zero) {
256dc707122SEaswaran Raman       if (auto Err = decodeCounter(EncodedCounterAndRegion, C))
257dc707122SEaswaran Raman         return Err;
258dc707122SEaswaran Raman     } else {
259dc707122SEaswaran Raman       // Is it an expansion region?
260dc707122SEaswaran Raman       if (EncodedCounterAndRegion & EncodingExpansionRegionBit) {
261dc707122SEaswaran Raman         Kind = CounterMappingRegion::ExpansionRegion;
262dc707122SEaswaran Raman         ExpandedFileID = EncodedCounterAndRegion >>
263dc707122SEaswaran Raman                          Counter::EncodingCounterTagAndExpansionRegionTagBits;
264dc707122SEaswaran Raman         if (ExpandedFileID >= NumFileIDs)
2659152fd17SVedant Kumar           return make_error<CoverageMapError>(coveragemap_error::malformed);
266dc707122SEaswaran Raman       } else {
267dc707122SEaswaran Raman         switch (EncodedCounterAndRegion >>
268dc707122SEaswaran Raman                 Counter::EncodingCounterTagAndExpansionRegionTagBits) {
269dc707122SEaswaran Raman         case CounterMappingRegion::CodeRegion:
270dc707122SEaswaran Raman           // Don't do anything when we have a code region with a zero counter.
271dc707122SEaswaran Raman           break;
272dc707122SEaswaran Raman         case CounterMappingRegion::SkippedRegion:
273dc707122SEaswaran Raman           Kind = CounterMappingRegion::SkippedRegion;
274dc707122SEaswaran Raman           break;
2759f2967bcSAlan Phipps         case CounterMappingRegion::BranchRegion:
2769f2967bcSAlan Phipps           // For a Branch Region, read two successive counters.
2779f2967bcSAlan Phipps           Kind = CounterMappingRegion::BranchRegion;
2789f2967bcSAlan Phipps           if (auto Err = readCounter(C))
2799f2967bcSAlan Phipps             return Err;
2809f2967bcSAlan Phipps           if (auto Err = readCounter(C2))
2819f2967bcSAlan Phipps             return Err;
2829f2967bcSAlan Phipps           break;
283dc707122SEaswaran Raman         default:
2849152fd17SVedant Kumar           return make_error<CoverageMapError>(coveragemap_error::malformed);
285dc707122SEaswaran Raman         }
286dc707122SEaswaran Raman       }
287dc707122SEaswaran Raman     }
288dc707122SEaswaran Raman 
289dc707122SEaswaran Raman     // Read the source range.
290dc707122SEaswaran Raman     uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd;
291dc707122SEaswaran Raman     if (auto Err =
292dc707122SEaswaran Raman             readIntMax(LineStartDelta, std::numeric_limits<unsigned>::max()))
293dc707122SEaswaran Raman       return Err;
294dc707122SEaswaran Raman     if (auto Err = readULEB128(ColumnStart))
295dc707122SEaswaran Raman       return Err;
296dc707122SEaswaran Raman     if (ColumnStart > std::numeric_limits<unsigned>::max())
2979152fd17SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
298dc707122SEaswaran Raman     if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max()))
299dc707122SEaswaran Raman       return Err;
300dc707122SEaswaran Raman     if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max()))
301dc707122SEaswaran Raman       return Err;
302dc707122SEaswaran Raman     LineStart += LineStartDelta;
303ad8f637bSVedant Kumar 
304ad8f637bSVedant Kumar     // If the high bit of ColumnEnd is set, this is a gap region.
305ad8f637bSVedant Kumar     if (ColumnEnd & (1U << 31)) {
306ad8f637bSVedant Kumar       Kind = CounterMappingRegion::GapRegion;
307ad8f637bSVedant Kumar       ColumnEnd &= ~(1U << 31);
308ad8f637bSVedant Kumar     }
309ad8f637bSVedant Kumar 
310dc707122SEaswaran Raman     // Adjust the column locations for the empty regions that are supposed to
311dc707122SEaswaran Raman     // cover whole lines. Those regions should be encoded with the
312dc707122SEaswaran Raman     // column range (1 -> std::numeric_limits<unsigned>::max()), but because
313dc707122SEaswaran Raman     // the encoded std::numeric_limits<unsigned>::max() is several bytes long,
314dc707122SEaswaran Raman     // we set the column range to (0 -> 0) to ensure that the column start and
315dc707122SEaswaran Raman     // column end take up one byte each.
316dc707122SEaswaran Raman     // The std::numeric_limits<unsigned>::max() is used to represent a column
317dc707122SEaswaran Raman     // position at the end of the line without knowing the length of that line.
318dc707122SEaswaran Raman     if (ColumnStart == 0 && ColumnEnd == 0) {
319dc707122SEaswaran Raman       ColumnStart = 1;
320dc707122SEaswaran Raman       ColumnEnd = std::numeric_limits<unsigned>::max();
321dc707122SEaswaran Raman     }
322dc707122SEaswaran Raman 
323d34e60caSNicola Zaghen     LLVM_DEBUG({
324dc707122SEaswaran Raman       dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":"
325dc707122SEaswaran Raman              << ColumnStart << " -> " << (LineStart + NumLines) << ":"
326dc707122SEaswaran Raman              << ColumnEnd << ", ";
327dc707122SEaswaran Raman       if (Kind == CounterMappingRegion::ExpansionRegion)
328dc707122SEaswaran Raman         dbgs() << "Expands to file " << ExpandedFileID;
329dc707122SEaswaran Raman       else
330dc707122SEaswaran Raman         CounterMappingContext(Expressions).dump(C, dbgs());
331dc707122SEaswaran Raman       dbgs() << "\n";
332dc707122SEaswaran Raman     });
333dc707122SEaswaran Raman 
3349f2967bcSAlan Phipps     auto CMR = CounterMappingRegion(C, C2, InferredFileID, ExpandedFileID,
335bae83970SVedant Kumar                                     LineStart, ColumnStart,
336bae83970SVedant Kumar                                     LineStart + NumLines, ColumnEnd, Kind);
337bae83970SVedant Kumar     if (CMR.startLoc() > CMR.endLoc())
338bae83970SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
339bae83970SVedant Kumar     MappingRegions.push_back(CMR);
340dc707122SEaswaran Raman   }
3419152fd17SVedant Kumar   return Error::success();
342dc707122SEaswaran Raman }
343dc707122SEaswaran Raman 
3449152fd17SVedant Kumar Error RawCoverageMappingReader::read() {
345dc707122SEaswaran Raman   // Read the virtual file mapping.
346e78d131aSEugene Zelenko   SmallVector<unsigned, 8> VirtualFileMapping;
347dc707122SEaswaran Raman   uint64_t NumFileMappings;
348dc707122SEaswaran Raman   if (auto Err = readSize(NumFileMappings))
349dc707122SEaswaran Raman     return Err;
350dc707122SEaswaran Raman   for (size_t I = 0; I < NumFileMappings; ++I) {
351dc707122SEaswaran Raman     uint64_t FilenameIndex;
352dc707122SEaswaran Raman     if (auto Err = readIntMax(FilenameIndex, TranslationUnitFilenames.size()))
353dc707122SEaswaran Raman       return Err;
354dc707122SEaswaran Raman     VirtualFileMapping.push_back(FilenameIndex);
355dc707122SEaswaran Raman   }
356dc707122SEaswaran Raman 
357dc707122SEaswaran Raman   // Construct the files using unique filenames and virtual file mapping.
358dc707122SEaswaran Raman   for (auto I : VirtualFileMapping) {
359dc707122SEaswaran Raman     Filenames.push_back(TranslationUnitFilenames[I]);
360dc707122SEaswaran Raman   }
361dc707122SEaswaran Raman 
362dc707122SEaswaran Raman   // Read the expressions.
363dc707122SEaswaran Raman   uint64_t NumExpressions;
364dc707122SEaswaran Raman   if (auto Err = readSize(NumExpressions))
365dc707122SEaswaran Raman     return Err;
366dc707122SEaswaran Raman   // Create an array of dummy expressions that get the proper counters
367dc707122SEaswaran Raman   // when the expressions are read, and the proper kinds when the counters
368dc707122SEaswaran Raman   // are decoded.
369dc707122SEaswaran Raman   Expressions.resize(
370dc707122SEaswaran Raman       NumExpressions,
371dc707122SEaswaran Raman       CounterExpression(CounterExpression::Subtract, Counter(), Counter()));
372dc707122SEaswaran Raman   for (size_t I = 0; I < NumExpressions; ++I) {
373dc707122SEaswaran Raman     if (auto Err = readCounter(Expressions[I].LHS))
374dc707122SEaswaran Raman       return Err;
375dc707122SEaswaran Raman     if (auto Err = readCounter(Expressions[I].RHS))
376dc707122SEaswaran Raman       return Err;
377dc707122SEaswaran Raman   }
378dc707122SEaswaran Raman 
379dc707122SEaswaran Raman   // Read the mapping regions sub-arrays.
380dc707122SEaswaran Raman   for (unsigned InferredFileID = 0, S = VirtualFileMapping.size();
381dc707122SEaswaran Raman        InferredFileID < S; ++InferredFileID) {
382dc707122SEaswaran Raman     if (auto Err = readMappingRegionsSubArray(MappingRegions, InferredFileID,
383dc707122SEaswaran Raman                                               VirtualFileMapping.size()))
384dc707122SEaswaran Raman       return Err;
385dc707122SEaswaran Raman   }
386dc707122SEaswaran Raman 
387dc707122SEaswaran Raman   // Set the counters for the expansion regions.
388dc707122SEaswaran Raman   // i.e. Counter of expansion region = counter of the first region
389dc707122SEaswaran Raman   // from the expanded file.
390dc707122SEaswaran Raman   // Perform multiple passes to correctly propagate the counters through
391dc707122SEaswaran Raman   // all the nested expansion regions.
392dc707122SEaswaran Raman   SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping;
393dc707122SEaswaran Raman   FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr);
394dc707122SEaswaran Raman   for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) {
395dc707122SEaswaran Raman     for (auto &R : MappingRegions) {
396dc707122SEaswaran Raman       if (R.Kind != CounterMappingRegion::ExpansionRegion)
397dc707122SEaswaran Raman         continue;
398dc707122SEaswaran Raman       assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]);
399dc707122SEaswaran Raman       FileIDExpansionRegionMapping[R.ExpandedFileID] = &R;
400dc707122SEaswaran Raman     }
401dc707122SEaswaran Raman     for (auto &R : MappingRegions) {
402dc707122SEaswaran Raman       if (FileIDExpansionRegionMapping[R.FileID]) {
403dc707122SEaswaran Raman         FileIDExpansionRegionMapping[R.FileID]->Count = R.Count;
404dc707122SEaswaran Raman         FileIDExpansionRegionMapping[R.FileID] = nullptr;
405dc707122SEaswaran Raman       }
406dc707122SEaswaran Raman     }
407dc707122SEaswaran Raman   }
408dc707122SEaswaran Raman 
4099152fd17SVedant Kumar   return Error::success();
410dc707122SEaswaran Raman }
411dc707122SEaswaran Raman 
412ac40e819SIgor Kudrin Expected<bool> RawCoverageMappingDummyChecker::isDummy() {
413ac40e819SIgor Kudrin   // A dummy coverage mapping data consists of just one region with zero count.
414ac40e819SIgor Kudrin   uint64_t NumFileMappings;
415ac40e819SIgor Kudrin   if (Error Err = readSize(NumFileMappings))
416c55cf4afSBill Wendling     return std::move(Err);
417ac40e819SIgor Kudrin   if (NumFileMappings != 1)
418ac40e819SIgor Kudrin     return false;
419ac40e819SIgor Kudrin   // We don't expect any specific value for the filename index, just skip it.
420ac40e819SIgor Kudrin   uint64_t FilenameIndex;
421ac40e819SIgor Kudrin   if (Error Err =
422ac40e819SIgor Kudrin           readIntMax(FilenameIndex, std::numeric_limits<unsigned>::max()))
423c55cf4afSBill Wendling     return std::move(Err);
424ac40e819SIgor Kudrin   uint64_t NumExpressions;
425ac40e819SIgor Kudrin   if (Error Err = readSize(NumExpressions))
426c55cf4afSBill Wendling     return std::move(Err);
427ac40e819SIgor Kudrin   if (NumExpressions != 0)
428ac40e819SIgor Kudrin     return false;
429ac40e819SIgor Kudrin   uint64_t NumRegions;
430ac40e819SIgor Kudrin   if (Error Err = readSize(NumRegions))
431c55cf4afSBill Wendling     return std::move(Err);
432ac40e819SIgor Kudrin   if (NumRegions != 1)
433ac40e819SIgor Kudrin     return false;
434ac40e819SIgor Kudrin   uint64_t EncodedCounterAndRegion;
435ac40e819SIgor Kudrin   if (Error Err = readIntMax(EncodedCounterAndRegion,
436ac40e819SIgor Kudrin                              std::numeric_limits<unsigned>::max()))
437c55cf4afSBill Wendling     return std::move(Err);
438ac40e819SIgor Kudrin   unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask;
439ac40e819SIgor Kudrin   return Tag == Counter::Zero;
440ac40e819SIgor Kudrin }
441ac40e819SIgor Kudrin 
4429152fd17SVedant Kumar Error InstrProfSymtab::create(SectionRef &Section) {
443e183340cSFangrui Song   Expected<StringRef> DataOrErr = Section.getContents();
444e183340cSFangrui Song   if (!DataOrErr)
445e183340cSFangrui Song     return DataOrErr.takeError();
446e183340cSFangrui Song   Data = *DataOrErr;
447dc707122SEaswaran Raman   Address = Section.getAddress();
4488b6af001SReid Kleckner 
4498b6af001SReid Kleckner   // If this is a linked PE/COFF file, then we have to skip over the null byte
4508b6af001SReid Kleckner   // that is allocated in the .lprfn$A section in the LLVM profiling runtime.
4518b6af001SReid Kleckner   const ObjectFile *Obj = Section.getObject();
4528b6af001SReid Kleckner   if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject())
4538b6af001SReid Kleckner     Data = Data.drop_front(1);
4548b6af001SReid Kleckner 
4559152fd17SVedant Kumar   return Error::success();
456dc707122SEaswaran Raman }
457dc707122SEaswaran Raman 
458dc707122SEaswaran Raman StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) {
459dc707122SEaswaran Raman   if (Pointer < Address)
460dc707122SEaswaran Raman     return StringRef();
461dc707122SEaswaran Raman   auto Offset = Pointer - Address;
462dc707122SEaswaran Raman   if (Offset + Size > Data.size())
463dc707122SEaswaran Raman     return StringRef();
464dc707122SEaswaran Raman   return Data.substr(Pointer - Address, Size);
465dc707122SEaswaran Raman }
466dc707122SEaswaran Raman 
467ac40e819SIgor Kudrin // Check if the mapping data is a dummy, i.e. is emitted for an unused function.
468ac40e819SIgor Kudrin static Expected<bool> isCoverageMappingDummy(uint64_t Hash, StringRef Mapping) {
469ac40e819SIgor Kudrin   // The hash value of dummy mapping records is always zero.
470ac40e819SIgor Kudrin   if (Hash)
471ac40e819SIgor Kudrin     return false;
472ac40e819SIgor Kudrin   return RawCoverageMappingDummyChecker(Mapping).isDummy();
473ac40e819SIgor Kudrin }
474ac40e819SIgor Kudrin 
475dd1ea9deSVedant Kumar /// A range of filename indices. Used to specify the location of a batch of
476dd1ea9deSVedant Kumar /// filenames in a vector-like container.
477dd1ea9deSVedant Kumar struct FilenameRange {
478dd1ea9deSVedant Kumar   unsigned StartingIndex;
479dd1ea9deSVedant Kumar   unsigned Length;
480dd1ea9deSVedant Kumar 
481dd1ea9deSVedant Kumar   FilenameRange(unsigned StartingIndex, unsigned Length)
482dd1ea9deSVedant Kumar       : StartingIndex(StartingIndex), Length(Length) {}
483dd1ea9deSVedant Kumar 
484dd1ea9deSVedant Kumar   void markInvalid() { Length = 0; }
485dd1ea9deSVedant Kumar   bool isInvalid() const { return Length == 0; }
486dd1ea9deSVedant Kumar };
487dd1ea9deSVedant Kumar 
488dc707122SEaswaran Raman namespace {
489e78d131aSEugene Zelenko 
490dd1ea9deSVedant Kumar /// The interface to read coverage mapping function records for a module.
491dc707122SEaswaran Raman struct CovMapFuncRecordReader {
492e78d131aSEugene Zelenko   virtual ~CovMapFuncRecordReader() = default;
493e78d131aSEugene Zelenko 
494dd1ea9deSVedant Kumar   // Read a coverage header.
4953739b95dSVedant Kumar   //
496dd1ea9deSVedant Kumar   // \p CovBuf points to the buffer containing the \c CovHeader of the coverage
4973739b95dSVedant Kumar   // mapping data associated with the module.
4983739b95dSVedant Kumar   //
499dd1ea9deSVedant Kumar   // Returns a pointer to the next \c CovHeader if it exists, or to an address
500dd1ea9deSVedant Kumar   // greater than \p CovEnd if not.
5015fbd1a33SPetr Hosek   virtual Expected<const char *> readCoverageHeader(const char *CovBuf,
5025fbd1a33SPetr Hosek                                                     const char *CovBufEnd) = 0;
503dd1ea9deSVedant Kumar 
504dd1ea9deSVedant Kumar   // Read function records.
505dd1ea9deSVedant Kumar   //
506dd1ea9deSVedant Kumar   // \p FuncRecBuf points to the buffer containing a batch of function records.
507dd1ea9deSVedant Kumar   // \p FuncRecBufEnd points past the end of the batch of records.
508dd1ea9deSVedant Kumar   //
509dd1ea9deSVedant Kumar   // Prior to Version4, \p OutOfLineFileRange points to a sequence of filenames
510dd1ea9deSVedant Kumar   // associated with the function records. It is unused in Version4.
511dd1ea9deSVedant Kumar   //
512dd1ea9deSVedant Kumar   // Prior to Version4, \p OutOfLineMappingBuf points to a sequence of coverage
513dd1ea9deSVedant Kumar   // mappings associated with the function records. It is unused in Version4.
514dd1ea9deSVedant Kumar   virtual Error readFunctionRecords(const char *FuncRecBuf,
515dd1ea9deSVedant Kumar                                     const char *FuncRecBufEnd,
516dd1ea9deSVedant Kumar                                     Optional<FilenameRange> OutOfLineFileRange,
517dd1ea9deSVedant Kumar                                     const char *OutOfLineMappingBuf,
518dd1ea9deSVedant Kumar                                     const char *OutOfLineMappingBufEnd) = 0;
519e78d131aSEugene Zelenko 
520dc707122SEaswaran Raman   template <class IntPtrT, support::endianness Endian>
5219152fd17SVedant Kumar   static Expected<std::unique_ptr<CovMapFuncRecordReader>>
522e78d131aSEugene Zelenko   get(CovMapVersion Version, InstrProfSymtab &P,
523dc707122SEaswaran Raman       std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
5245fbd1a33SPetr Hosek       std::vector<std::string> &F);
525dc707122SEaswaran Raman };
526dc707122SEaswaran Raman 
527dc707122SEaswaran Raman // A class for reading coverage mapping function records for a module.
528e78d131aSEugene Zelenko template <CovMapVersion Version, class IntPtrT, support::endianness Endian>
529dc707122SEaswaran Raman class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
53072208a82SEugene Zelenko   using FuncRecordType =
53172208a82SEugene Zelenko       typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType;
53272208a82SEugene Zelenko   using NameRefType = typename CovMapTraits<Version, IntPtrT>::NameRefType;
533dc707122SEaswaran Raman 
534ac40e819SIgor Kudrin   // Maps function's name references to the indexes of their records
535ac40e819SIgor Kudrin   // in \c Records.
536e78d131aSEugene Zelenko   DenseMap<NameRefType, size_t> FunctionRecords;
537dc707122SEaswaran Raman   InstrProfSymtab &ProfileNames;
5385fbd1a33SPetr Hosek   std::vector<std::string> &Filenames;
539dc707122SEaswaran Raman   std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records;
540dc707122SEaswaran Raman 
541dd1ea9deSVedant Kumar   // Maps a hash of the filenames in a TU to a \c FileRange. The range
542dd1ea9deSVedant Kumar   // specifies the location of the hashed filenames in \c Filenames.
543dd1ea9deSVedant Kumar   DenseMap<uint64_t, FilenameRange> FileRangeMap;
544dd1ea9deSVedant Kumar 
545ac40e819SIgor Kudrin   // Add the record to the collection if we don't already have a record that
546ac40e819SIgor Kudrin   // points to the same function name. This is useful to ignore the redundant
547ac40e819SIgor Kudrin   // records for the functions with ODR linkage.
548ac40e819SIgor Kudrin   // In addition, prefer records with real coverage mapping data to dummy
549ac40e819SIgor Kudrin   // records, which were emitted for inline functions which were seen but
550ac40e819SIgor Kudrin   // not used in the corresponding translation unit.
551ac40e819SIgor Kudrin   Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR,
552dd1ea9deSVedant Kumar                                      StringRef Mapping,
553dd1ea9deSVedant Kumar                                      FilenameRange FileRange) {
554dd1ea9deSVedant Kumar     ++CovMapNumRecords;
555ac40e819SIgor Kudrin     uint64_t FuncHash = CFR->template getFuncHash<Endian>();
556ac40e819SIgor Kudrin     NameRefType NameRef = CFR->template getFuncNameRef<Endian>();
557ac40e819SIgor Kudrin     auto InsertResult =
558ac40e819SIgor Kudrin         FunctionRecords.insert(std::make_pair(NameRef, Records.size()));
559ac40e819SIgor Kudrin     if (InsertResult.second) {
560ac40e819SIgor Kudrin       StringRef FuncName;
561ac40e819SIgor Kudrin       if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName))
562ac40e819SIgor Kudrin         return Err;
563b5794ca9SVedant Kumar       if (FuncName.empty())
564b5794ca9SVedant Kumar         return make_error<InstrProfError>(instrprof_error::malformed);
565dd1ea9deSVedant Kumar       ++CovMapNumUsedRecords;
566dd1ea9deSVedant Kumar       Records.emplace_back(Version, FuncName, FuncHash, Mapping,
567dd1ea9deSVedant Kumar                            FileRange.StartingIndex, FileRange.Length);
568ac40e819SIgor Kudrin       return Error::success();
569ac40e819SIgor Kudrin     }
570ac40e819SIgor Kudrin     // Update the existing record if it's a dummy and the new record is real.
571ac40e819SIgor Kudrin     size_t OldRecordIndex = InsertResult.first->second;
572ac40e819SIgor Kudrin     BinaryCoverageReader::ProfileMappingRecord &OldRecord =
573ac40e819SIgor Kudrin         Records[OldRecordIndex];
574ac40e819SIgor Kudrin     Expected<bool> OldIsDummyExpected = isCoverageMappingDummy(
575ac40e819SIgor Kudrin         OldRecord.FunctionHash, OldRecord.CoverageMapping);
576ac40e819SIgor Kudrin     if (Error Err = OldIsDummyExpected.takeError())
577ac40e819SIgor Kudrin       return Err;
578ac40e819SIgor Kudrin     if (!*OldIsDummyExpected)
579ac40e819SIgor Kudrin       return Error::success();
580ac40e819SIgor Kudrin     Expected<bool> NewIsDummyExpected =
581ac40e819SIgor Kudrin         isCoverageMappingDummy(FuncHash, Mapping);
582ac40e819SIgor Kudrin     if (Error Err = NewIsDummyExpected.takeError())
583ac40e819SIgor Kudrin       return Err;
584ac40e819SIgor Kudrin     if (*NewIsDummyExpected)
585ac40e819SIgor Kudrin       return Error::success();
586dd1ea9deSVedant Kumar     ++CovMapNumUsedRecords;
587ac40e819SIgor Kudrin     OldRecord.FunctionHash = FuncHash;
588ac40e819SIgor Kudrin     OldRecord.CoverageMapping = Mapping;
589dd1ea9deSVedant Kumar     OldRecord.FilenamesBegin = FileRange.StartingIndex;
590dd1ea9deSVedant Kumar     OldRecord.FilenamesSize = FileRange.Length;
591ac40e819SIgor Kudrin     return Error::success();
592ac40e819SIgor Kudrin   }
593ac40e819SIgor Kudrin 
594dc707122SEaswaran Raman public:
595dc707122SEaswaran Raman   VersionedCovMapFuncRecordReader(
596dc707122SEaswaran Raman       InstrProfSymtab &P,
597dc707122SEaswaran Raman       std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
5985fbd1a33SPetr Hosek       std::vector<std::string> &F)
599dc707122SEaswaran Raman       : ProfileNames(P), Filenames(F), Records(R) {}
600e78d131aSEugene Zelenko 
601e78d131aSEugene Zelenko   ~VersionedCovMapFuncRecordReader() override = default;
602dc707122SEaswaran Raman 
6035fbd1a33SPetr Hosek   Expected<const char *> readCoverageHeader(const char *CovBuf,
6045fbd1a33SPetr Hosek                                             const char *CovBufEnd) override {
605dc707122SEaswaran Raman     using namespace support;
606e78d131aSEugene Zelenko 
607dd1ea9deSVedant Kumar     if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)
6089152fd17SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
609dd1ea9deSVedant Kumar     auto CovHeader = reinterpret_cast<const CovMapHeader *>(CovBuf);
610dc707122SEaswaran Raman     uint32_t NRecords = CovHeader->getNRecords<Endian>();
611dc707122SEaswaran Raman     uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>();
612dc707122SEaswaran Raman     uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>();
613dc707122SEaswaran Raman     assert((CovMapVersion)CovHeader->getVersion<Endian>() == Version);
614dd1ea9deSVedant Kumar     CovBuf = reinterpret_cast<const char *>(CovHeader + 1);
615dc707122SEaswaran Raman 
616dc707122SEaswaran Raman     // Skip past the function records, saving the start and end for later.
617dd1ea9deSVedant Kumar     // This is a no-op in Version4 (function records are read after all headers
618dd1ea9deSVedant Kumar     // are read).
619dd1ea9deSVedant Kumar     const char *FuncRecBuf = nullptr;
620dd1ea9deSVedant Kumar     const char *FuncRecBufEnd = nullptr;
621dd1ea9deSVedant Kumar     if (Version < CovMapVersion::Version4)
622dd1ea9deSVedant Kumar       FuncRecBuf = CovBuf;
623dd1ea9deSVedant Kumar     CovBuf += NRecords * sizeof(FuncRecordType);
624dd1ea9deSVedant Kumar     if (Version < CovMapVersion::Version4)
625dd1ea9deSVedant Kumar       FuncRecBufEnd = CovBuf;
626dc707122SEaswaran Raman 
627dc707122SEaswaran Raman     // Get the filenames.
628dd1ea9deSVedant Kumar     if (CovBuf + FilenamesSize > CovBufEnd)
6299152fd17SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
630dc707122SEaswaran Raman     size_t FilenamesBegin = Filenames.size();
631dd1ea9deSVedant Kumar     StringRef FilenameRegion(CovBuf, FilenamesSize);
632dd1ea9deSVedant Kumar     RawCoverageFilenamesReader Reader(FilenameRegion, Filenames);
6335fbd1a33SPetr Hosek     if (auto Err = Reader.read(Version))
634c55cf4afSBill Wendling       return std::move(Err);
635dd1ea9deSVedant Kumar     CovBuf += FilenamesSize;
636dd1ea9deSVedant Kumar     FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin);
637dd1ea9deSVedant Kumar 
6389f2967bcSAlan Phipps     if (Version >= CovMapVersion::Version4) {
639dd1ea9deSVedant Kumar       // Map a hash of the filenames region to the filename range associated
640dd1ea9deSVedant Kumar       // with this coverage header.
641dd1ea9deSVedant Kumar       int64_t FilenamesRef =
642dd1ea9deSVedant Kumar           llvm::IndexedInstrProf::ComputeHash(FilenameRegion);
643dd1ea9deSVedant Kumar       auto Insert =
644dd1ea9deSVedant Kumar           FileRangeMap.insert(std::make_pair(FilenamesRef, FileRange));
645dd1ea9deSVedant Kumar       if (!Insert.second) {
646dd1ea9deSVedant Kumar         // The same filenames ref was encountered twice. It's possible that
647dd1ea9deSVedant Kumar         // the associated filenames are the same.
648dd1ea9deSVedant Kumar         auto It = Filenames.begin();
649dd1ea9deSVedant Kumar         FilenameRange &OrigRange = Insert.first->getSecond();
650dd1ea9deSVedant Kumar         if (std::equal(It + OrigRange.StartingIndex,
651dd1ea9deSVedant Kumar                        It + OrigRange.StartingIndex + OrigRange.Length,
652dd1ea9deSVedant Kumar                        It + FileRange.StartingIndex,
653dd1ea9deSVedant Kumar                        It + FileRange.StartingIndex + FileRange.Length))
654dd1ea9deSVedant Kumar           // Map the new range to the original one.
655dd1ea9deSVedant Kumar           FileRange = OrigRange;
656dd1ea9deSVedant Kumar         else
657dd1ea9deSVedant Kumar           // This is a hash collision. Mark the filenames ref invalid.
658dd1ea9deSVedant Kumar           OrigRange.markInvalid();
659dd1ea9deSVedant Kumar       }
660dd1ea9deSVedant Kumar     }
661dc707122SEaswaran Raman 
662dc707122SEaswaran Raman     // We'll read the coverage mapping records in the loop below.
663dd1ea9deSVedant Kumar     // This is a no-op in Version4 (coverage mappings are not affixed to the
664dd1ea9deSVedant Kumar     // coverage header).
665dd1ea9deSVedant Kumar     const char *MappingBuf = CovBuf;
6669f2967bcSAlan Phipps     if (Version >= CovMapVersion::Version4 && CoverageSize != 0)
6679152fd17SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
668dd1ea9deSVedant Kumar     CovBuf += CoverageSize;
669dd1ea9deSVedant Kumar     const char *MappingEnd = CovBuf;
670dd1ea9deSVedant Kumar 
671dd1ea9deSVedant Kumar     if (CovBuf > CovBufEnd)
672dd1ea9deSVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
673dd1ea9deSVedant Kumar 
674dd1ea9deSVedant Kumar     if (Version < CovMapVersion::Version4) {
675dd1ea9deSVedant Kumar       // Read each function record.
676dd1ea9deSVedant Kumar       if (Error E = readFunctionRecords(FuncRecBuf, FuncRecBufEnd, FileRange,
677dd1ea9deSVedant Kumar                                         MappingBuf, MappingEnd))
678dd1ea9deSVedant Kumar         return std::move(E);
679dd1ea9deSVedant Kumar     }
680dd1ea9deSVedant Kumar 
681dc707122SEaswaran Raman     // Each coverage map has an alignment of 8, so we need to adjust alignment
682dc707122SEaswaran Raman     // before reading the next map.
683dd1ea9deSVedant Kumar     CovBuf += offsetToAlignedAddr(CovBuf, Align(8));
684dc707122SEaswaran Raman 
685dd1ea9deSVedant Kumar     return CovBuf;
68699317124SVedant Kumar   }
687dd1ea9deSVedant Kumar 
688dd1ea9deSVedant Kumar   Error readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
689dd1ea9deSVedant Kumar                             Optional<FilenameRange> OutOfLineFileRange,
690dd1ea9deSVedant Kumar                             const char *OutOfLineMappingBuf,
691dd1ea9deSVedant Kumar                             const char *OutOfLineMappingBufEnd) override {
692dd1ea9deSVedant Kumar     auto CFR = reinterpret_cast<const FuncRecordType *>(FuncRecBuf);
693dd1ea9deSVedant Kumar     while ((const char *)CFR < FuncRecBufEnd) {
694dd1ea9deSVedant Kumar       // Validate the length of the coverage mapping for this function.
695dd1ea9deSVedant Kumar       const char *NextMappingBuf;
696dd1ea9deSVedant Kumar       const FuncRecordType *NextCFR;
697dd1ea9deSVedant Kumar       std::tie(NextMappingBuf, NextCFR) =
698dd1ea9deSVedant Kumar           CFR->template advanceByOne<Endian>(OutOfLineMappingBuf);
699dd1ea9deSVedant Kumar       if (Version < CovMapVersion::Version4)
700dd1ea9deSVedant Kumar         if (NextMappingBuf > OutOfLineMappingBufEnd)
701dd1ea9deSVedant Kumar           return make_error<CoverageMapError>(coveragemap_error::malformed);
702dd1ea9deSVedant Kumar 
703dd1ea9deSVedant Kumar       // Look up the set of filenames associated with this function record.
704dd1ea9deSVedant Kumar       Optional<FilenameRange> FileRange;
705dd1ea9deSVedant Kumar       if (Version < CovMapVersion::Version4) {
706dd1ea9deSVedant Kumar         FileRange = OutOfLineFileRange;
707dd1ea9deSVedant Kumar       } else {
708dd1ea9deSVedant Kumar         uint64_t FilenamesRef = CFR->template getFilenamesRef<Endian>();
709dd1ea9deSVedant Kumar         auto It = FileRangeMap.find(FilenamesRef);
710dd1ea9deSVedant Kumar         if (It == FileRangeMap.end())
711dd1ea9deSVedant Kumar           return make_error<CoverageMapError>(coveragemap_error::malformed);
712dd1ea9deSVedant Kumar         else
713dd1ea9deSVedant Kumar           FileRange = It->getSecond();
714dd1ea9deSVedant Kumar       }
715dd1ea9deSVedant Kumar 
716dd1ea9deSVedant Kumar       // Now, read the coverage data.
717dd1ea9deSVedant Kumar       if (FileRange && !FileRange->isInvalid()) {
718dd1ea9deSVedant Kumar         StringRef Mapping =
719dd1ea9deSVedant Kumar             CFR->template getCoverageMapping<Endian>(OutOfLineMappingBuf);
7209f2967bcSAlan Phipps         if (Version >= CovMapVersion::Version4 &&
721dd1ea9deSVedant Kumar             Mapping.data() + Mapping.size() > FuncRecBufEnd)
722dd1ea9deSVedant Kumar           return make_error<CoverageMapError>(coveragemap_error::malformed);
723dd1ea9deSVedant Kumar         if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange))
724dd1ea9deSVedant Kumar           return Err;
725dd1ea9deSVedant Kumar       }
726dd1ea9deSVedant Kumar 
727dd1ea9deSVedant Kumar       std::tie(OutOfLineMappingBuf, CFR) = std::tie(NextMappingBuf, NextCFR);
728dd1ea9deSVedant Kumar     }
729dd1ea9deSVedant Kumar     return Error::success();
730dc707122SEaswaran Raman   }
731dc707122SEaswaran Raman };
732e78d131aSEugene Zelenko 
733dc707122SEaswaran Raman } // end anonymous namespace
734dc707122SEaswaran Raman 
735dc707122SEaswaran Raman template <class IntPtrT, support::endianness Endian>
7369152fd17SVedant Kumar Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
737e78d131aSEugene Zelenko     CovMapVersion Version, InstrProfSymtab &P,
738dc707122SEaswaran Raman     std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
7395fbd1a33SPetr Hosek     std::vector<std::string> &F) {
740dc707122SEaswaran Raman   using namespace coverage;
741e78d131aSEugene Zelenko 
742dc707122SEaswaran Raman   switch (Version) {
743dc707122SEaswaran Raman   case CovMapVersion::Version1:
7440eaee545SJonas Devlieghere     return std::make_unique<VersionedCovMapFuncRecordReader<
745dc707122SEaswaran Raman         CovMapVersion::Version1, IntPtrT, Endian>>(P, R, F);
746dc707122SEaswaran Raman   case CovMapVersion::Version2:
747ad8f637bSVedant Kumar   case CovMapVersion::Version3:
748dd1ea9deSVedant Kumar   case CovMapVersion::Version4:
7499f2967bcSAlan Phipps   case CovMapVersion::Version5:
7505fbd1a33SPetr Hosek   case CovMapVersion::Version6:
751dc707122SEaswaran Raman     // Decompress the name data.
7529152fd17SVedant Kumar     if (Error E = P.create(P.getNameData()))
753c55cf4afSBill Wendling       return std::move(E);
754ad8f637bSVedant Kumar     if (Version == CovMapVersion::Version2)
7550eaee545SJonas Devlieghere       return std::make_unique<VersionedCovMapFuncRecordReader<
756dc707122SEaswaran Raman           CovMapVersion::Version2, IntPtrT, Endian>>(P, R, F);
757dd1ea9deSVedant Kumar     else if (Version == CovMapVersion::Version3)
7580eaee545SJonas Devlieghere       return std::make_unique<VersionedCovMapFuncRecordReader<
759ad8f637bSVedant Kumar           CovMapVersion::Version3, IntPtrT, Endian>>(P, R, F);
760dd1ea9deSVedant Kumar     else if (Version == CovMapVersion::Version4)
761dd1ea9deSVedant Kumar       return std::make_unique<VersionedCovMapFuncRecordReader<
762dd1ea9deSVedant Kumar           CovMapVersion::Version4, IntPtrT, Endian>>(P, R, F);
7639f2967bcSAlan Phipps     else if (Version == CovMapVersion::Version5)
7649f2967bcSAlan Phipps       return std::make_unique<VersionedCovMapFuncRecordReader<
7659f2967bcSAlan Phipps           CovMapVersion::Version5, IntPtrT, Endian>>(P, R, F);
7665fbd1a33SPetr Hosek     else if (Version == CovMapVersion::Version6)
7675fbd1a33SPetr Hosek       return std::make_unique<VersionedCovMapFuncRecordReader<
7685fbd1a33SPetr Hosek           CovMapVersion::Version6, IntPtrT, Endian>>(P, R, F);
769dc707122SEaswaran Raman   }
770dc707122SEaswaran Raman   llvm_unreachable("Unsupported version");
771dc707122SEaswaran Raman }
772dc707122SEaswaran Raman 
773dc707122SEaswaran Raman template <typename T, support::endianness Endian>
7749152fd17SVedant Kumar static Error readCoverageMappingData(
775dd1ea9deSVedant Kumar     InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
776dc707122SEaswaran Raman     std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
7775fbd1a33SPetr Hosek     std::vector<std::string> &Filenames) {
778dc707122SEaswaran Raman   using namespace coverage;
779e78d131aSEugene Zelenko 
780dc707122SEaswaran Raman   // Read the records in the coverage data section.
781dc707122SEaswaran Raman   auto CovHeader =
782dd1ea9deSVedant Kumar       reinterpret_cast<const CovMapHeader *>(CovMap.data());
783dc707122SEaswaran Raman   CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>();
784e78d131aSEugene Zelenko   if (Version > CovMapVersion::CurrentVersion)
7859152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::unsupported_version);
7869152fd17SVedant Kumar   Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected =
787dc707122SEaswaran Raman       CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records,
788dc707122SEaswaran Raman                                              Filenames);
7899152fd17SVedant Kumar   if (Error E = ReaderExpected.takeError())
7909152fd17SVedant Kumar     return E;
7919152fd17SVedant Kumar   auto Reader = std::move(ReaderExpected.get());
792dd1ea9deSVedant Kumar   const char *CovBuf = CovMap.data();
793dd1ea9deSVedant Kumar   const char *CovBufEnd = CovBuf + CovMap.size();
794dd1ea9deSVedant Kumar   const char *FuncRecBuf = FuncRecords.data();
795dd1ea9deSVedant Kumar   const char *FuncRecBufEnd = FuncRecords.data() + FuncRecords.size();
796dd1ea9deSVedant Kumar   while (CovBuf < CovBufEnd) {
797dd1ea9deSVedant Kumar     // Read the current coverage header & filename data.
798dd1ea9deSVedant Kumar     //
799dd1ea9deSVedant Kumar     // Prior to Version4, this also reads all function records affixed to the
800dd1ea9deSVedant Kumar     // header.
801dd1ea9deSVedant Kumar     //
802dd1ea9deSVedant Kumar     // Return a pointer to the next coverage header.
8035fbd1a33SPetr Hosek     auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd);
804dd1ea9deSVedant Kumar     if (auto E = NextOrErr.takeError())
8059152fd17SVedant Kumar       return E;
806dd1ea9deSVedant Kumar     CovBuf = NextOrErr.get();
807dc707122SEaswaran Raman   }
808dd1ea9deSVedant Kumar   // In Version4, function records are not affixed to coverage headers. Read
809dd1ea9deSVedant Kumar   // the records from their dedicated section.
8109f2967bcSAlan Phipps   if (Version >= CovMapVersion::Version4)
811dd1ea9deSVedant Kumar     return Reader->readFunctionRecords(FuncRecBuf, FuncRecBufEnd, None, nullptr,
812dd1ea9deSVedant Kumar                                        nullptr);
8139152fd17SVedant Kumar   return Error::success();
814dc707122SEaswaran Raman }
815e78d131aSEugene Zelenko 
816dc707122SEaswaran Raman static const char *TestingFormatMagic = "llvmcovmtestdata";
817dc707122SEaswaran Raman 
818901d04fcSVedant Kumar Expected<std::unique_ptr<BinaryCoverageReader>>
819901d04fcSVedant Kumar BinaryCoverageReader::createCoverageReaderFromBuffer(
82080cd518bSVedant Kumar     StringRef Coverage, std::string &&FuncRecords, InstrProfSymtab &&ProfileNames,
821dd1ea9deSVedant Kumar     uint8_t BytesInAddress, support::endianness Endian) {
82280cd518bSVedant Kumar   std::unique_ptr<BinaryCoverageReader> Reader(
82380cd518bSVedant Kumar       new BinaryCoverageReader(std::move(FuncRecords)));
824901d04fcSVedant Kumar   Reader->ProfileNames = std::move(ProfileNames);
82580cd518bSVedant Kumar   StringRef FuncRecordsRef = Reader->FuncRecords;
826901d04fcSVedant Kumar   if (BytesInAddress == 4 && Endian == support::endianness::little) {
827901d04fcSVedant Kumar     if (Error E =
828901d04fcSVedant Kumar             readCoverageMappingData<uint32_t, support::endianness::little>(
82980cd518bSVedant Kumar                 Reader->ProfileNames, Coverage, FuncRecordsRef,
8305fbd1a33SPetr Hosek                 Reader->MappingRecords, Reader->Filenames))
831c55cf4afSBill Wendling       return std::move(E);
832901d04fcSVedant Kumar   } else if (BytesInAddress == 4 && Endian == support::endianness::big) {
833901d04fcSVedant Kumar     if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>(
83480cd518bSVedant Kumar             Reader->ProfileNames, Coverage, FuncRecordsRef,
8355fbd1a33SPetr Hosek             Reader->MappingRecords, Reader->Filenames))
836c55cf4afSBill Wendling       return std::move(E);
837901d04fcSVedant Kumar   } else if (BytesInAddress == 8 && Endian == support::endianness::little) {
838901d04fcSVedant Kumar     if (Error E =
839901d04fcSVedant Kumar             readCoverageMappingData<uint64_t, support::endianness::little>(
84080cd518bSVedant Kumar                 Reader->ProfileNames, Coverage, FuncRecordsRef,
8415fbd1a33SPetr Hosek                 Reader->MappingRecords, Reader->Filenames))
842c55cf4afSBill Wendling       return std::move(E);
843901d04fcSVedant Kumar   } else if (BytesInAddress == 8 && Endian == support::endianness::big) {
844901d04fcSVedant Kumar     if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>(
84580cd518bSVedant Kumar             Reader->ProfileNames, Coverage, FuncRecordsRef,
8465fbd1a33SPetr Hosek             Reader->MappingRecords, Reader->Filenames))
847c55cf4afSBill Wendling       return std::move(E);
848901d04fcSVedant Kumar   } else
849901d04fcSVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
850c55cf4afSBill Wendling   return std::move(Reader);
851901d04fcSVedant Kumar }
852901d04fcSVedant Kumar 
853901d04fcSVedant Kumar static Expected<std::unique_ptr<BinaryCoverageReader>>
854901d04fcSVedant Kumar loadTestingFormat(StringRef Data) {
855901d04fcSVedant Kumar   uint8_t BytesInAddress = 8;
856901d04fcSVedant Kumar   support::endianness Endian = support::endianness::little;
857dc707122SEaswaran Raman 
858dc707122SEaswaran Raman   Data = Data.substr(StringRef(TestingFormatMagic).size());
85972208a82SEugene Zelenko   if (Data.empty())
8609152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::truncated);
861dc707122SEaswaran Raman   unsigned N = 0;
8626a0746a9SFangrui Song   uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N);
863dc707122SEaswaran Raman   if (N > Data.size())
8649152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
865dc707122SEaswaran Raman   Data = Data.substr(N);
86672208a82SEugene Zelenko   if (Data.empty())
8679152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::truncated);
868dc707122SEaswaran Raman   N = 0;
8696a0746a9SFangrui Song   uint64_t Address = decodeULEB128(Data.bytes_begin(), &N);
870dc707122SEaswaran Raman   if (N > Data.size())
8719152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
872dc707122SEaswaran Raman   Data = Data.substr(N);
873dc707122SEaswaran Raman   if (Data.size() < ProfileNamesSize)
8749152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
875901d04fcSVedant Kumar   InstrProfSymtab ProfileNames;
8769152fd17SVedant Kumar   if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address))
877c55cf4afSBill Wendling     return std::move(E);
878*489a3531SPetr Hosek   Data = Data.substr(ProfileNamesSize);
879eb103073SIgor Kudrin   // Skip the padding bytes because coverage map data has an alignment of 8.
880*489a3531SPetr Hosek   size_t Pad = offsetToAlignedAddr(Data.data(), Align(8));
881*489a3531SPetr Hosek   if (Data.size() < Pad)
882*489a3531SPetr Hosek     return make_error<CoverageMapError>(coveragemap_error::malformed);
883*489a3531SPetr Hosek   Data = Data.substr(Pad);
884*489a3531SPetr Hosek   if (Data.size() < sizeof(CovMapHeader))
885*489a3531SPetr Hosek     return make_error<CoverageMapError>(coveragemap_error::malformed);
886*489a3531SPetr Hosek   auto const *CovHeader = reinterpret_cast<const CovMapHeader *>(
887*489a3531SPetr Hosek       Data.substr(0, sizeof(CovMapHeader)).data());
888*489a3531SPetr Hosek   CovMapVersion Version =
889*489a3531SPetr Hosek       (CovMapVersion)CovHeader->getVersion<support::endianness::little>();
890*489a3531SPetr Hosek   StringRef CoverageMapping, CoverageRecords;
891*489a3531SPetr Hosek   if (Version < CovMapVersion::Version4) {
892*489a3531SPetr Hosek     CoverageMapping = Data;
89372208a82SEugene Zelenko     if (CoverageMapping.empty())
8949152fd17SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::truncated);
895*489a3531SPetr Hosek   } else {
896*489a3531SPetr Hosek     uint32_t FilenamesSize =
897*489a3531SPetr Hosek         CovHeader->getFilenamesSize<support::endianness::little>();
898*489a3531SPetr Hosek     uint32_t CoverageMappingSize = sizeof(CovMapHeader) + FilenamesSize;
899*489a3531SPetr Hosek     CoverageMapping = Data.substr(0, CoverageMappingSize);
900*489a3531SPetr Hosek     if (CoverageMapping.empty())
901*489a3531SPetr Hosek       return make_error<CoverageMapError>(coveragemap_error::truncated);
902*489a3531SPetr Hosek     Data = Data.substr(CoverageMappingSize);
903*489a3531SPetr Hosek     // Skip the padding bytes because coverage records data has an alignment
904*489a3531SPetr Hosek     // of 8.
905*489a3531SPetr Hosek     Pad = offsetToAlignedAddr(Data.data(), Align(8));
906*489a3531SPetr Hosek     if (Data.size() < Pad)
9079152fd17SVedant Kumar       return make_error<CoverageMapError>(coveragemap_error::malformed);
908*489a3531SPetr Hosek     CoverageRecords = Data.substr(Pad);
909*489a3531SPetr Hosek     if (CoverageRecords.empty())
910*489a3531SPetr Hosek       return make_error<CoverageMapError>(coveragemap_error::truncated);
911*489a3531SPetr Hosek   }
912901d04fcSVedant Kumar   return BinaryCoverageReader::createCoverageReaderFromBuffer(
913*489a3531SPetr Hosek       CoverageMapping, CoverageRecords.str(), std::move(ProfileNames),
914*489a3531SPetr Hosek       BytesInAddress, Endian);
915dc707122SEaswaran Raman }
916dc707122SEaswaran Raman 
91780cd518bSVedant Kumar /// Find all sections that match \p Name. There may be more than one if comdats
91880cd518bSVedant Kumar /// are in use, e.g. for the __llvm_covfun section on ELF.
91980cd518bSVedant Kumar static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF,
92080cd518bSVedant Kumar                                                         StringRef Name) {
9218b6af001SReid Kleckner   // On COFF, the object file section name may end in "$M". This tells the
9228b6af001SReid Kleckner   // linker to sort these sections between "$A" and "$Z". The linker removes the
9238b6af001SReid Kleckner   // dollar and everything after it in the final binary. Do the same to match.
9248b6af001SReid Kleckner   bool IsCOFF = isa<COFFObjectFile>(OF);
9258b6af001SReid Kleckner   auto stripSuffix = [IsCOFF](StringRef N) {
9268b6af001SReid Kleckner     return IsCOFF ? N.split('$').first : N;
9278b6af001SReid Kleckner   };
9288b6af001SReid Kleckner   Name = stripSuffix(Name);
9298b6af001SReid Kleckner 
93080cd518bSVedant Kumar   std::vector<SectionRef> Sections;
931dc707122SEaswaran Raman   for (const auto &Section : OF.sections()) {
932bcc00e1aSGeorge Rimar     Expected<StringRef> NameOrErr = Section.getName();
933bcc00e1aSGeorge Rimar     if (!NameOrErr)
934bcc00e1aSGeorge Rimar       return NameOrErr.takeError();
935bcc00e1aSGeorge Rimar     if (stripSuffix(*NameOrErr) == Name)
93680cd518bSVedant Kumar       Sections.push_back(Section);
937dc707122SEaswaran Raman   }
93880cd518bSVedant Kumar   if (Sections.empty())
9399152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::no_data_found);
94080cd518bSVedant Kumar   return Sections;
941dc707122SEaswaran Raman }
942dc707122SEaswaran Raman 
943901d04fcSVedant Kumar static Expected<std::unique_ptr<BinaryCoverageReader>>
944901d04fcSVedant Kumar loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) {
945dc707122SEaswaran Raman   std::unique_ptr<ObjectFile> OF;
946e78d131aSEugene Zelenko   if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {
947dc707122SEaswaran Raman     // If we have a universal binary, try to look up the object for the
948dc707122SEaswaran Raman     // appropriate architecture.
9494fd11c1eSAlexander Shaposhnikov     auto ObjectFileOrErr = Universal->getMachOObjectForArch(Arch);
9509acb1099SKevin Enderby     if (!ObjectFileOrErr)
9519acb1099SKevin Enderby       return ObjectFileOrErr.takeError();
952dc707122SEaswaran Raman     OF = std::move(ObjectFileOrErr.get());
953e78d131aSEugene Zelenko   } else if (isa<ObjectFile>(Bin.get())) {
954dc707122SEaswaran Raman     // For any other object file, upcast and take ownership.
955e78d131aSEugene Zelenko     OF.reset(cast<ObjectFile>(Bin.release()));
956dc707122SEaswaran Raman     // If we've asked for a particular arch, make sure they match.
957dc707122SEaswaran Raman     if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch())
9589152fd17SVedant Kumar       return errorCodeToError(object_error::arch_not_found);
959dc707122SEaswaran Raman   } else
960dc707122SEaswaran Raman     // We can only handle object files.
9619152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
962dc707122SEaswaran Raman 
963dc707122SEaswaran Raman   // The coverage uses native pointer sizes for the object it's written in.
964901d04fcSVedant Kumar   uint8_t BytesInAddress = OF->getBytesInAddress();
965901d04fcSVedant Kumar   support::endianness Endian = OF->isLittleEndian()
966901d04fcSVedant Kumar                                    ? support::endianness::little
967dc707122SEaswaran Raman                                    : support::endianness::big;
968dc707122SEaswaran Raman 
969dc707122SEaswaran Raman   // Look for the sections that we are interested in.
9701a6a2b64SVedant Kumar   auto ObjFormat = OF->getTripleObjectFormat();
9714a5ddf80SXinliang David Li   auto NamesSection =
97280cd518bSVedant Kumar       lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
9731a6a2b64SVedant Kumar                                                  /*AddSegmentInfo=*/false));
9749152fd17SVedant Kumar   if (auto E = NamesSection.takeError())
975c55cf4afSBill Wendling     return std::move(E);
9764a5ddf80SXinliang David Li   auto CoverageSection =
97780cd518bSVedant Kumar       lookupSections(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,
9781a6a2b64SVedant Kumar                                                   /*AddSegmentInfo=*/false));
9799152fd17SVedant Kumar   if (auto E = CoverageSection.takeError())
980c55cf4afSBill Wendling     return std::move(E);
98180cd518bSVedant Kumar   std::vector<SectionRef> CoverageSectionRefs = *CoverageSection;
98280cd518bSVedant Kumar   if (CoverageSectionRefs.size() != 1)
98380cd518bSVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
98480cd518bSVedant Kumar   auto CoverageMappingOrErr = CoverageSectionRefs.back().getContents();
985901d04fcSVedant Kumar   if (!CoverageMappingOrErr)
986901d04fcSVedant Kumar     return CoverageMappingOrErr.takeError();
987dd1ea9deSVedant Kumar   StringRef CoverageMapping = CoverageMappingOrErr.get();
988e183340cSFangrui Song 
989901d04fcSVedant Kumar   InstrProfSymtab ProfileNames;
99080cd518bSVedant Kumar   std::vector<SectionRef> NamesSectionRefs = *NamesSection;
99180cd518bSVedant Kumar   if (NamesSectionRefs.size() != 1)
99280cd518bSVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::malformed);
99380cd518bSVedant Kumar   if (Error E = ProfileNames.create(NamesSectionRefs.back()))
994c55cf4afSBill Wendling     return std::move(E);
995dc707122SEaswaran Raman 
996dd1ea9deSVedant Kumar   // Look for the coverage records section (Version4 only).
99780cd518bSVedant Kumar   std::string FuncRecords;
99880cd518bSVedant Kumar   auto CoverageRecordsSections =
99980cd518bSVedant Kumar       lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat,
1000dd1ea9deSVedant Kumar                                                   /*AddSegmentInfo=*/false));
100180cd518bSVedant Kumar   if (auto E = CoverageRecordsSections.takeError())
1002dd1ea9deSVedant Kumar     consumeError(std::move(E));
1003dd1ea9deSVedant Kumar   else {
100480cd518bSVedant Kumar     for (SectionRef Section : *CoverageRecordsSections) {
100580cd518bSVedant Kumar       auto CoverageRecordsOrErr = Section.getContents();
1006dd1ea9deSVedant Kumar       if (!CoverageRecordsOrErr)
1007dd1ea9deSVedant Kumar         return CoverageRecordsOrErr.takeError();
100880cd518bSVedant Kumar       FuncRecords += CoverageRecordsOrErr.get();
100980cd518bSVedant Kumar       while (FuncRecords.size() % 8 != 0)
101080cd518bSVedant Kumar         FuncRecords += '\0';
101180cd518bSVedant Kumar     }
1012dd1ea9deSVedant Kumar   }
1013dd1ea9deSVedant Kumar 
1014901d04fcSVedant Kumar   return BinaryCoverageReader::createCoverageReaderFromBuffer(
101580cd518bSVedant Kumar       CoverageMapping, std::move(FuncRecords), std::move(ProfileNames),
101680cd518bSVedant Kumar       BytesInAddress, Endian);
1017dc707122SEaswaran Raman }
1018dc707122SEaswaran Raman 
10197fafaa07SVedant Kumar /// Determine whether \p Arch is invalid or empty, given \p Bin.
10207fafaa07SVedant Kumar static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch) {
10217fafaa07SVedant Kumar   // If we have a universal binary and Arch doesn't identify any of its slices,
10227fafaa07SVedant Kumar   // it's user error.
10237fafaa07SVedant Kumar   if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin)) {
10247fafaa07SVedant Kumar     for (auto &ObjForArch : Universal->objects())
10257fafaa07SVedant Kumar       if (Arch == ObjForArch.getArchFlagName())
10267fafaa07SVedant Kumar         return false;
10277fafaa07SVedant Kumar     return true;
10287fafaa07SVedant Kumar   }
10297fafaa07SVedant Kumar   return false;
10307fafaa07SVedant Kumar }
10317fafaa07SVedant Kumar 
1032901d04fcSVedant Kumar Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
1033901d04fcSVedant Kumar BinaryCoverageReader::create(
1034901d04fcSVedant Kumar     MemoryBufferRef ObjectBuffer, StringRef Arch,
1035901d04fcSVedant Kumar     SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers) {
1036901d04fcSVedant Kumar   std::vector<std::unique_ptr<BinaryCoverageReader>> Readers;
1037dc707122SEaswaran Raman 
1038901d04fcSVedant Kumar   if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) {
1039dc707122SEaswaran Raman     // This is a special format used for testing.
1040901d04fcSVedant Kumar     auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer());
1041901d04fcSVedant Kumar     if (!ReaderOrErr)
1042901d04fcSVedant Kumar       return ReaderOrErr.takeError();
1043901d04fcSVedant Kumar     Readers.push_back(std::move(ReaderOrErr.get()));
1044c55cf4afSBill Wendling     return std::move(Readers);
1045901d04fcSVedant Kumar   }
1046dc707122SEaswaran Raman 
1047901d04fcSVedant Kumar   auto BinOrErr = createBinary(ObjectBuffer);
1048901d04fcSVedant Kumar   if (!BinOrErr)
1049901d04fcSVedant Kumar     return BinOrErr.takeError();
1050901d04fcSVedant Kumar   std::unique_ptr<Binary> Bin = std::move(BinOrErr.get());
1051901d04fcSVedant Kumar 
10527fafaa07SVedant Kumar   if (isArchSpecifierInvalidOrMissing(Bin.get(), Arch))
10537fafaa07SVedant Kumar     return make_error<CoverageMapError>(
10547fafaa07SVedant Kumar         coveragemap_error::invalid_or_missing_arch_specifier);
10557fafaa07SVedant Kumar 
1056901d04fcSVedant Kumar   // MachO universal binaries which contain archives need to be treated as
1057901d04fcSVedant Kumar   // archives, not as regular binaries.
1058901d04fcSVedant Kumar   if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {
1059901d04fcSVedant Kumar     for (auto &ObjForArch : Universal->objects()) {
1060901d04fcSVedant Kumar       // Skip slices within the universal binary which target the wrong arch.
1061901d04fcSVedant Kumar       std::string ObjArch = ObjForArch.getArchFlagName();
1062901d04fcSVedant Kumar       if (Arch != ObjArch)
1063901d04fcSVedant Kumar         continue;
1064901d04fcSVedant Kumar 
1065901d04fcSVedant Kumar       auto ArchiveOrErr = ObjForArch.getAsArchive();
1066901d04fcSVedant Kumar       if (!ArchiveOrErr) {
1067901d04fcSVedant Kumar         // If this is not an archive, try treating it as a regular object.
1068901d04fcSVedant Kumar         consumeError(ArchiveOrErr.takeError());
1069901d04fcSVedant Kumar         break;
1070901d04fcSVedant Kumar       }
1071901d04fcSVedant Kumar 
1072901d04fcSVedant Kumar       return BinaryCoverageReader::create(
1073901d04fcSVedant Kumar           ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers);
1074901d04fcSVedant Kumar     }
1075901d04fcSVedant Kumar   }
1076901d04fcSVedant Kumar 
1077901d04fcSVedant Kumar   // Load coverage out of archive members.
1078901d04fcSVedant Kumar   if (auto *Ar = dyn_cast<Archive>(Bin.get())) {
1079901d04fcSVedant Kumar     Error Err = Error::success();
1080901d04fcSVedant Kumar     for (auto &Child : Ar->children(Err)) {
1081901d04fcSVedant Kumar       Expected<MemoryBufferRef> ChildBufOrErr = Child.getMemoryBufferRef();
1082901d04fcSVedant Kumar       if (!ChildBufOrErr)
1083901d04fcSVedant Kumar         return ChildBufOrErr.takeError();
1084901d04fcSVedant Kumar 
1085901d04fcSVedant Kumar       auto ChildReadersOrErr = BinaryCoverageReader::create(
1086901d04fcSVedant Kumar           ChildBufOrErr.get(), Arch, ObjectFileBuffers);
1087901d04fcSVedant Kumar       if (!ChildReadersOrErr)
1088901d04fcSVedant Kumar         return ChildReadersOrErr.takeError();
1089901d04fcSVedant Kumar       for (auto &Reader : ChildReadersOrErr.get())
1090901d04fcSVedant Kumar         Readers.push_back(std::move(Reader));
1091901d04fcSVedant Kumar     }
1092901d04fcSVedant Kumar     if (Err)
1093c55cf4afSBill Wendling       return std::move(Err);
1094901d04fcSVedant Kumar 
1095901d04fcSVedant Kumar     // Thin archives reference object files outside of the archive file, i.e.
1096901d04fcSVedant Kumar     // files which reside in memory not owned by the caller. Transfer ownership
1097901d04fcSVedant Kumar     // to the caller.
1098901d04fcSVedant Kumar     if (Ar->isThin())
1099901d04fcSVedant Kumar       for (auto &Buffer : Ar->takeThinBuffers())
1100901d04fcSVedant Kumar         ObjectFileBuffers.push_back(std::move(Buffer));
1101901d04fcSVedant Kumar 
1102c55cf4afSBill Wendling     return std::move(Readers);
1103901d04fcSVedant Kumar   }
1104901d04fcSVedant Kumar 
1105901d04fcSVedant Kumar   auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch);
1106901d04fcSVedant Kumar   if (!ReaderOrErr)
1107901d04fcSVedant Kumar     return ReaderOrErr.takeError();
1108901d04fcSVedant Kumar   Readers.push_back(std::move(ReaderOrErr.get()));
1109c55cf4afSBill Wendling   return std::move(Readers);
1110dc707122SEaswaran Raman }
1111dc707122SEaswaran Raman 
11129152fd17SVedant Kumar Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
1113dc707122SEaswaran Raman   if (CurrentRecord >= MappingRecords.size())
11149152fd17SVedant Kumar     return make_error<CoverageMapError>(coveragemap_error::eof);
1115dc707122SEaswaran Raman 
1116dc707122SEaswaran Raman   FunctionsFilenames.clear();
1117dc707122SEaswaran Raman   Expressions.clear();
1118dc707122SEaswaran Raman   MappingRegions.clear();
1119dc707122SEaswaran Raman   auto &R = MappingRecords[CurrentRecord];
11205fbd1a33SPetr Hosek   auto F = makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize);
11215fbd1a33SPetr Hosek   RawCoverageMappingReader Reader(R.CoverageMapping, F, FunctionsFilenames,
11225fbd1a33SPetr Hosek                                   Expressions, MappingRegions);
1123dc707122SEaswaran Raman   if (auto Err = Reader.read())
1124dc707122SEaswaran Raman     return Err;
1125dc707122SEaswaran Raman 
1126dc707122SEaswaran Raman   Record.FunctionName = R.FunctionName;
1127dc707122SEaswaran Raman   Record.FunctionHash = R.FunctionHash;
1128dc707122SEaswaran Raman   Record.Filenames = FunctionsFilenames;
1129dc707122SEaswaran Raman   Record.Expressions = Expressions;
1130dc707122SEaswaran Raman   Record.MappingRegions = MappingRegions;
1131dc707122SEaswaran Raman 
1132dc707122SEaswaran Raman   ++CurrentRecord;
11339152fd17SVedant Kumar   return Error::success();
1134dc707122SEaswaran Raman }
1135