1 //=-- InstrProfReader.cpp - Instrumented profiling reader -------------------=//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains support for reading profiling data for clang's
11 // instrumentation based PGO and coverage.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/ProfileData/InstrProfReader.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include <cassert>
18 
19 using namespace llvm;
20 
21 static ErrorOr<std::unique_ptr<MemoryBuffer>>
22 setupMemoryBuffer(std::string Path) {
23   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
24       MemoryBuffer::getFileOrSTDIN(Path);
25   if (std::error_code EC = BufferOrErr.getError())
26     return EC;
27   return std::move(BufferOrErr.get());
28 }
29 
30 static std::error_code initializeReader(InstrProfReader &Reader) {
31   return Reader.readHeader();
32 }
33 
34 ErrorOr<std::unique_ptr<InstrProfReader>>
35 InstrProfReader::create(std::string Path) {
36   // Set up the buffer to read.
37   auto BufferOrError = setupMemoryBuffer(Path);
38   if (std::error_code EC = BufferOrError.getError())
39     return EC;
40   return InstrProfReader::create(std::move(BufferOrError.get()));
41 }
42 
43 ErrorOr<std::unique_ptr<InstrProfReader>>
44 InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
45   // Sanity check the buffer.
46   if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
47     return instrprof_error::too_large;
48 
49   std::unique_ptr<InstrProfReader> Result;
50   // Create the reader.
51   if (IndexedInstrProfReader::hasFormat(*Buffer))
52     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
53   else if (RawInstrProfReader64::hasFormat(*Buffer))
54     Result.reset(new RawInstrProfReader64(std::move(Buffer)));
55   else if (RawInstrProfReader32::hasFormat(*Buffer))
56     Result.reset(new RawInstrProfReader32(std::move(Buffer)));
57   else if (TextInstrProfReader::hasFormat(*Buffer))
58     Result.reset(new TextInstrProfReader(std::move(Buffer)));
59   else
60     return instrprof_error::unrecognized_format;
61 
62   // Initialize the reader and return the result.
63   if (std::error_code EC = initializeReader(*Result))
64     return EC;
65 
66   return std::move(Result);
67 }
68 
69 ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
70 IndexedInstrProfReader::create(std::string Path) {
71   // Set up the buffer to read.
72   auto BufferOrError = setupMemoryBuffer(Path);
73   if (std::error_code EC = BufferOrError.getError())
74     return EC;
75   return IndexedInstrProfReader::create(std::move(BufferOrError.get()));
76 }
77 
78 
79 ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
80 IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
81   // Sanity check the buffer.
82   if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
83     return instrprof_error::too_large;
84 
85   // Create the reader.
86   if (!IndexedInstrProfReader::hasFormat(*Buffer))
87     return instrprof_error::bad_magic;
88   auto Result = llvm::make_unique<IndexedInstrProfReader>(std::move(Buffer));
89 
90   // Initialize the reader and return the result.
91   if (std::error_code EC = initializeReader(*Result))
92     return EC;
93 
94   return std::move(Result);
95 }
96 
97 void InstrProfIterator::Increment() {
98   if (Reader->readNextRecord(Record))
99     *this = InstrProfIterator();
100 }
101 
102 bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
103   // Verify that this really looks like plain ASCII text by checking a
104   // 'reasonable' number of characters (up to profile magic size).
105   size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
106   StringRef buffer = Buffer.getBufferStart();
107   return count == 0 ||
108          std::all_of(buffer.begin(), buffer.begin() + count,
109                      [](char c) { return ::isprint(c) || ::isspace(c); });
110 }
111 
112 // Read the profile variant flag from the header: ":FE" means this is a FE
113 // generated profile. ":IR" means this is an IR level profile. Other strings
114 // with a leading ':' will be reported an error format.
115 std::error_code TextInstrProfReader::readHeader() {
116   Symtab.reset(new InstrProfSymtab());
117   bool IsIRInstr = false;
118   if (!Line->startswith(":")) {
119     IsIRLevelProfile = false;
120     return success();
121   }
122   StringRef Str = (Line)->substr(1);
123   if (Str.equals_lower("ir"))
124     IsIRInstr = true;
125   else if (Str.equals_lower("fe"))
126     IsIRInstr = false;
127   else
128     return instrprof_error::bad_header;
129 
130   ++Line;
131   IsIRLevelProfile = IsIRInstr;
132   return success();
133 }
134 
135 std::error_code
136 TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
137 
138 #define CHECK_LINE_END(Line)                                                   \
139   if (Line.is_at_end())                                                        \
140     return error(instrprof_error::truncated);
141 #define READ_NUM(Str, Dst)                                                     \
142   if ((Str).getAsInteger(10, (Dst)))                                           \
143     return error(instrprof_error::malformed);
144 #define VP_READ_ADVANCE(Val)                                                   \
145   CHECK_LINE_END(Line);                                                        \
146   uint32_t Val;                                                                \
147   READ_NUM((*Line), (Val));                                                    \
148   Line++;
149 
150   if (Line.is_at_end())
151     return success();
152 
153   uint32_t NumValueKinds;
154   if (Line->getAsInteger(10, NumValueKinds)) {
155     // No value profile data
156     return success();
157   }
158   if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
159     return error(instrprof_error::malformed);
160   Line++;
161 
162   for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
163     VP_READ_ADVANCE(ValueKind);
164     if (ValueKind > IPVK_Last)
165       return error(instrprof_error::malformed);
166     VP_READ_ADVANCE(NumValueSites);
167     if (!NumValueSites)
168       continue;
169 
170     Record.reserveSites(VK, NumValueSites);
171     for (uint32_t S = 0; S < NumValueSites; S++) {
172       VP_READ_ADVANCE(NumValueData);
173 
174       std::vector<InstrProfValueData> CurrentValues;
175       for (uint32_t V = 0; V < NumValueData; V++) {
176         CHECK_LINE_END(Line);
177         std::pair<StringRef, StringRef> VD = Line->rsplit(':');
178         uint64_t TakenCount, Value;
179         if (VK == IPVK_IndirectCallTarget) {
180           Symtab->addFuncName(VD.first);
181           Value = IndexedInstrProf::ComputeHash(VD.first);
182         } else {
183           READ_NUM(VD.first, Value);
184         }
185         READ_NUM(VD.second, TakenCount);
186         CurrentValues.push_back({Value, TakenCount});
187         Line++;
188       }
189       Record.addValueData(VK, S, CurrentValues.data(), NumValueData, nullptr);
190     }
191   }
192   return success();
193 
194 #undef CHECK_LINE_END
195 #undef READ_NUM
196 #undef VP_READ_ADVANCE
197 }
198 
199 std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
200   // Skip empty lines and comments.
201   while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
202     ++Line;
203   // If we hit EOF while looking for a name, we're done.
204   if (Line.is_at_end()) {
205     Symtab->finalizeSymtab();
206     return error(instrprof_error::eof);
207   }
208 
209   // Read the function name.
210   Record.Name = *Line++;
211   Symtab->addFuncName(Record.Name);
212 
213   // Read the function hash.
214   if (Line.is_at_end())
215     return error(instrprof_error::truncated);
216   if ((Line++)->getAsInteger(0, Record.Hash))
217     return error(instrprof_error::malformed);
218 
219   // Read the number of counters.
220   uint64_t NumCounters;
221   if (Line.is_at_end())
222     return error(instrprof_error::truncated);
223   if ((Line++)->getAsInteger(10, NumCounters))
224     return error(instrprof_error::malformed);
225   if (NumCounters == 0)
226     return error(instrprof_error::malformed);
227 
228   // Read each counter and fill our internal storage with the values.
229   Record.Counts.clear();
230   Record.Counts.reserve(NumCounters);
231   for (uint64_t I = 0; I < NumCounters; ++I) {
232     if (Line.is_at_end())
233       return error(instrprof_error::truncated);
234     uint64_t Count;
235     if ((Line++)->getAsInteger(10, Count))
236       return error(instrprof_error::malformed);
237     Record.Counts.push_back(Count);
238   }
239 
240   // Check if value profile data exists and read it if so.
241   if (std::error_code EC = readValueProfileData(Record))
242     return EC;
243 
244   // This is needed to avoid two pass parsing because llvm-profdata
245   // does dumping while reading.
246   Symtab->finalizeSymtab();
247   return success();
248 }
249 
250 template <class IntPtrT>
251 bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
252   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
253     return false;
254   uint64_t Magic =
255     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
256   return RawInstrProf::getMagic<IntPtrT>() == Magic ||
257          sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic;
258 }
259 
260 template <class IntPtrT>
261 std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
262   if (!hasFormat(*DataBuffer))
263     return error(instrprof_error::bad_magic);
264   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
265     return error(instrprof_error::bad_header);
266   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
267       DataBuffer->getBufferStart());
268   ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
269   return readHeader(*Header);
270 }
271 
272 template <class IntPtrT>
273 std::error_code
274 RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
275   const char *End = DataBuffer->getBufferEnd();
276   // Skip zero padding between profiles.
277   while (CurrentPos != End && *CurrentPos == 0)
278     ++CurrentPos;
279   // If there's nothing left, we're done.
280   if (CurrentPos == End)
281     return instrprof_error::eof;
282   // If there isn't enough space for another header, this is probably just
283   // garbage at the end of the file.
284   if (CurrentPos + sizeof(RawInstrProf::Header) > End)
285     return instrprof_error::malformed;
286   // The writer ensures each profile is padded to start at an aligned address.
287   if (reinterpret_cast<size_t>(CurrentPos) % alignOf<uint64_t>())
288     return instrprof_error::malformed;
289   // The magic should have the same byte order as in the previous header.
290   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
291   if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
292     return instrprof_error::bad_magic;
293 
294   // There's another profile to read, so we need to process the header.
295   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
296   return readHeader(*Header);
297 }
298 
299 template <class IntPtrT>
300 std::error_code
301 RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
302   std::error_code EC = Symtab.create(StringRef(NamesStart, NamesSize));
303   if (EC)
304     return EC;
305   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
306     const IntPtrT FPtr = swap(I->FunctionPointer);
307     if (!FPtr)
308       continue;
309     Symtab.mapAddress(FPtr, I->NameRef);
310   }
311   Symtab.finalizeSymtab();
312   return success();
313 }
314 
315 template <class IntPtrT>
316 std::error_code
317 RawInstrProfReader<IntPtrT>::readHeader(const RawInstrProf::Header &Header) {
318   Version = swap(Header.Version);
319   if (GET_VERSION(Version) != RawInstrProf::Version)
320     return error(instrprof_error::unsupported_version);
321 
322   CountersDelta = swap(Header.CountersDelta);
323   NamesDelta = swap(Header.NamesDelta);
324   auto DataSize = swap(Header.DataSize);
325   auto CountersSize = swap(Header.CountersSize);
326   NamesSize = swap(Header.NamesSize);
327   ValueKindLast = swap(Header.ValueKindLast);
328 
329   auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>);
330   auto PaddingSize = getNumPaddingBytes(NamesSize);
331 
332   ptrdiff_t DataOffset = sizeof(RawInstrProf::Header);
333   ptrdiff_t CountersOffset = DataOffset + DataSizeInBytes;
334   ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
335   ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
336 
337   auto *Start = reinterpret_cast<const char *>(&Header);
338   if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
339     return error(instrprof_error::bad_header);
340 
341   Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
342       Start + DataOffset);
343   DataEnd = Data + DataSize;
344   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
345   NamesStart = Start + NamesOffset;
346   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
347 
348   std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>();
349   if (auto EC = createSymtab(*NewSymtab.get()))
350     return EC;
351 
352   Symtab = std::move(NewSymtab);
353   return success();
354 }
355 
356 template <class IntPtrT>
357 std::error_code RawInstrProfReader<IntPtrT>::readName(InstrProfRecord &Record) {
358   Record.Name = getName(Data->NameRef);
359   return success();
360 }
361 
362 template <class IntPtrT>
363 std::error_code RawInstrProfReader<IntPtrT>::readFuncHash(
364     InstrProfRecord &Record) {
365   Record.Hash = swap(Data->FuncHash);
366   return success();
367 }
368 
369 template <class IntPtrT>
370 std::error_code RawInstrProfReader<IntPtrT>::readRawCounts(
371     InstrProfRecord &Record) {
372   uint32_t NumCounters = swap(Data->NumCounters);
373   IntPtrT CounterPtr = Data->CounterPtr;
374   if (NumCounters == 0)
375     return error(instrprof_error::malformed);
376 
377   auto RawCounts = makeArrayRef(getCounter(CounterPtr), NumCounters);
378   auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
379 
380   // Check bounds.
381   if (RawCounts.data() < CountersStart ||
382       RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
383     return error(instrprof_error::malformed);
384 
385   if (ShouldSwapBytes) {
386     Record.Counts.clear();
387     Record.Counts.reserve(RawCounts.size());
388     for (uint64_t Count : RawCounts)
389       Record.Counts.push_back(swap(Count));
390   } else
391     Record.Counts = RawCounts;
392 
393   return success();
394 }
395 
396 template <class IntPtrT>
397 std::error_code
398 RawInstrProfReader<IntPtrT>::readValueProfilingData(InstrProfRecord &Record) {
399 
400   Record.clearValueData();
401   CurValueDataSize = 0;
402   // Need to match the logic in value profile dumper code in compiler-rt:
403   uint32_t NumValueKinds = 0;
404   for (uint32_t I = 0; I < IPVK_Last + 1; I++)
405     NumValueKinds += (Data->NumValueSites[I] != 0);
406 
407   if (!NumValueKinds)
408     return success();
409 
410   ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
411       ValueProfData::getValueProfData(
412           ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
413           getDataEndianness());
414 
415   if (VDataPtrOrErr.getError())
416     return VDataPtrOrErr.getError();
417 
418   // Note that besides deserialization, this also performs the conversion for
419   // indirect call targets.  The function pointers from the raw profile are
420   // remapped into function name hashes.
421   VDataPtrOrErr.get()->deserializeTo(Record, &Symtab->getAddrHashMap());
422   CurValueDataSize = VDataPtrOrErr.get()->getSize();
423   return success();
424 }
425 
426 template <class IntPtrT>
427 std::error_code
428 RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
429   if (atEnd())
430     // At this point, ValueDataStart field points to the next header.
431     if (std::error_code EC = readNextHeader(getNextHeaderPos()))
432       return EC;
433 
434   // Read name ad set it in Record.
435   if (std::error_code EC = readName(Record))
436     return EC;
437 
438   // Read FuncHash and set it in Record.
439   if (std::error_code EC = readFuncHash(Record))
440     return EC;
441 
442   // Read raw counts and set Record.
443   if (std::error_code EC = readRawCounts(Record))
444     return EC;
445 
446   // Read value data and set Record.
447   if (std::error_code EC = readValueProfilingData(Record))
448     return EC;
449 
450   // Iterate.
451   advanceData();
452   return success();
453 }
454 
455 namespace llvm {
456 template class RawInstrProfReader<uint32_t>;
457 template class RawInstrProfReader<uint64_t>;
458 }
459 
460 InstrProfLookupTrait::hash_value_type
461 InstrProfLookupTrait::ComputeHash(StringRef K) {
462   return IndexedInstrProf::ComputeHash(HashType, K);
463 }
464 
465 typedef InstrProfLookupTrait::data_type data_type;
466 typedef InstrProfLookupTrait::offset_type offset_type;
467 
468 bool InstrProfLookupTrait::readValueProfilingData(
469     const unsigned char *&D, const unsigned char *const End) {
470   ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
471       ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
472 
473   if (VDataPtrOrErr.getError())
474     return false;
475 
476   VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
477   D += VDataPtrOrErr.get()->TotalSize;
478 
479   return true;
480 }
481 
482 data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
483                                          offset_type N) {
484   // Check if the data is corrupt. If so, don't try to read it.
485   if (N % sizeof(uint64_t))
486     return data_type();
487 
488   DataBuffer.clear();
489   std::vector<uint64_t> CounterBuffer;
490 
491   using namespace support;
492   const unsigned char *End = D + N;
493   while (D < End) {
494     // Read hash.
495     if (D + sizeof(uint64_t) >= End)
496       return data_type();
497     uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
498 
499     // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
500     uint64_t CountsSize = N / sizeof(uint64_t) - 1;
501     // If format version is different then read the number of counters.
502     if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
503       if (D + sizeof(uint64_t) > End)
504         return data_type();
505       CountsSize = endian::readNext<uint64_t, little, unaligned>(D);
506     }
507     // Read counter values.
508     if (D + CountsSize * sizeof(uint64_t) > End)
509       return data_type();
510 
511     CounterBuffer.clear();
512     CounterBuffer.reserve(CountsSize);
513     for (uint64_t J = 0; J < CountsSize; ++J)
514       CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
515 
516     DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
517 
518     // Read value profiling data.
519     if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
520         !readValueProfilingData(D, End)) {
521       DataBuffer.clear();
522       return data_type();
523     }
524   }
525   return DataBuffer;
526 }
527 
528 template <typename HashTableImpl>
529 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
530     StringRef FuncName, ArrayRef<InstrProfRecord> &Data) {
531   auto Iter = HashTable->find(FuncName);
532   if (Iter == HashTable->end())
533     return instrprof_error::unknown_function;
534 
535   Data = (*Iter);
536   if (Data.empty())
537     return instrprof_error::malformed;
538 
539   return instrprof_error::success;
540 }
541 
542 template <typename HashTableImpl>
543 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
544     ArrayRef<InstrProfRecord> &Data) {
545   if (atEnd())
546     return instrprof_error::eof;
547 
548   Data = *RecordIterator;
549 
550   if (Data.empty())
551     return instrprof_error::malformed;
552 
553   return instrprof_error::success;
554 }
555 
556 template <typename HashTableImpl>
557 InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
558     const unsigned char *Buckets, const unsigned char *const Payload,
559     const unsigned char *const Base, IndexedInstrProf::HashT HashType,
560     uint64_t Version) {
561   FormatVersion = Version;
562   HashTable.reset(HashTableImpl::Create(
563       Buckets, Payload, Base,
564       typename HashTableImpl::InfoType(HashType, Version)));
565   RecordIterator = HashTable->data_begin();
566 }
567 
568 bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
569   if (DataBuffer.getBufferSize() < 8)
570     return false;
571   using namespace support;
572   uint64_t Magic =
573       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
574   // Verify that it's magical.
575   return Magic == IndexedInstrProf::Magic;
576 }
577 
578 const unsigned char *
579 IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
580                                     const unsigned char *Cur) {
581   using namespace support;
582   if (Version >= IndexedInstrProf::Version4) {
583     const IndexedInstrProf::Summary *SummaryInLE =
584         reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
585     uint64_t NFields =
586         endian::byte_swap<uint64_t, little>(SummaryInLE->NumSummaryFields);
587     uint64_t NEntries =
588         endian::byte_swap<uint64_t, little>(SummaryInLE->NumCutoffEntries);
589     uint32_t SummarySize =
590         IndexedInstrProf::Summary::getSize(NFields, NEntries);
591     std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
592         IndexedInstrProf::allocSummary(SummarySize);
593 
594     const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
595     uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
596     for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
597       Dst[I] = endian::byte_swap<uint64_t, little>(Src[I]);
598 
599     // initialize InstrProfSummary using the SummaryData from disk.
600     this->Summary = llvm::make_unique<InstrProfSummary>(*(SummaryData.get()));
601     return Cur + SummarySize;
602   } else {
603     // For older version of profile data, we need to compute on the fly:
604     using namespace IndexedInstrProf;
605     this->Summary =
606         llvm::make_unique<InstrProfSummary>(ProfileSummary::DefaultCutoffs);
607     this->Summary->computeDetailedSummary();
608     return Cur;
609   }
610 }
611 
612 std::error_code IndexedInstrProfReader::readHeader() {
613   const unsigned char *Start =
614       (const unsigned char *)DataBuffer->getBufferStart();
615   const unsigned char *Cur = Start;
616   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
617     return error(instrprof_error::truncated);
618 
619   using namespace support;
620 
621   auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur);
622   Cur += sizeof(IndexedInstrProf::Header);
623 
624   // Check the magic number.
625   uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic);
626   if (Magic != IndexedInstrProf::Magic)
627     return error(instrprof_error::bad_magic);
628 
629   // Read the version.
630   uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version);
631   if (GET_VERSION(FormatVersion) >
632       IndexedInstrProf::ProfVersion::CurrentVersion)
633     return error(instrprof_error::unsupported_version);
634 
635   Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur);
636 
637   // Read the hash type and start offset.
638   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
639       endian::byte_swap<uint64_t, little>(Header->HashType));
640   if (HashType > IndexedInstrProf::HashT::Last)
641     return error(instrprof_error::unsupported_hash_type);
642 
643   uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset);
644 
645   // The rest of the file is an on disk hash table.
646   InstrProfReaderIndexBase *IndexPtr = nullptr;
647   IndexPtr = new InstrProfReaderIndex<OnDiskHashTableImplV3>(
648       Start + HashOffset, Cur, Start, HashType, FormatVersion);
649   Index.reset(IndexPtr);
650   return success();
651 }
652 
653 InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
654   if (Symtab.get())
655     return *Symtab.get();
656 
657   std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>();
658   Index->populateSymtab(*NewSymtab.get());
659 
660   Symtab = std::move(NewSymtab);
661   return *Symtab.get();
662 }
663 
664 ErrorOr<InstrProfRecord>
665 IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName,
666                                            uint64_t FuncHash) {
667   ArrayRef<InstrProfRecord> Data;
668   std::error_code EC = Index->getRecords(FuncName, Data);
669   if (EC != instrprof_error::success)
670     return EC;
671   // Found it. Look for counters with the right hash.
672   for (unsigned I = 0, E = Data.size(); I < E; ++I) {
673     // Check for a match and fill the vector if there is one.
674     if (Data[I].Hash == FuncHash) {
675       return std::move(Data[I]);
676     }
677   }
678   return error(instrprof_error::hash_mismatch);
679 }
680 
681 std::error_code
682 IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
683                                           std::vector<uint64_t> &Counts) {
684   ErrorOr<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
685   if (std::error_code EC = Record.getError())
686     return EC;
687 
688   Counts = Record.get().Counts;
689   return success();
690 }
691 
692 std::error_code IndexedInstrProfReader::readNextRecord(
693     InstrProfRecord &Record) {
694   static unsigned RecordIndex = 0;
695 
696   ArrayRef<InstrProfRecord> Data;
697 
698   std::error_code EC = Index->getRecords(Data);
699   if (EC != instrprof_error::success)
700     return error(EC);
701 
702   Record = Data[RecordIndex++];
703   if (RecordIndex >= Data.size()) {
704     Index->advanceToNextKey();
705     RecordIndex = 0;
706   }
707   return success();
708 }
709