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 std::error_code TextInstrProfReader::readHeader() {
113   Symtab.reset(new InstrProfSymtab());
114   return success();
115 }
116 
117 std::error_code
118 TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
119 
120 #define CHECK_LINE_END(Line)                                                   \
121   if (Line.is_at_end())                                                        \
122     return error(instrprof_error::truncated);
123 #define READ_NUM(Str, Dst)                                                     \
124   if ((Str).getAsInteger(10, (Dst)))                                           \
125     return error(instrprof_error::malformed);
126 #define VP_READ_ADVANCE(Val)                                                   \
127   CHECK_LINE_END(Line);                                                        \
128   uint32_t Val;                                                                \
129   READ_NUM((*Line), (Val));                                                    \
130   Line++;
131 
132   if (Line.is_at_end())
133     return success();
134 
135   uint32_t NumValueKinds;
136   if (Line->getAsInteger(10, NumValueKinds)) {
137     // No value profile data
138     return success();
139   }
140   if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
141     return error(instrprof_error::malformed);
142   Line++;
143 
144   for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
145     VP_READ_ADVANCE(ValueKind);
146     if (ValueKind > IPVK_Last)
147       return error(instrprof_error::malformed);
148     VP_READ_ADVANCE(NumValueSites);
149     if (!NumValueSites)
150       continue;
151 
152     Record.reserveSites(VK, NumValueSites);
153     for (uint32_t S = 0; S < NumValueSites; S++) {
154       VP_READ_ADVANCE(NumValueData);
155 
156       std::vector<InstrProfValueData> CurrentValues;
157       for (uint32_t V = 0; V < NumValueData; V++) {
158         CHECK_LINE_END(Line);
159         std::pair<StringRef, StringRef> VD = Line->split(':');
160         uint64_t TakenCount, Value;
161         if (VK == IPVK_IndirectCallTarget) {
162           Symtab->addFuncName(VD.first);
163           Value = IndexedInstrProf::ComputeHash(VD.first);
164         } else {
165           READ_NUM(VD.first, Value);
166         }
167         READ_NUM(VD.second, TakenCount);
168         CurrentValues.push_back({Value, TakenCount});
169         Line++;
170       }
171       Record.addValueData(VK, S, CurrentValues.data(), NumValueData, nullptr);
172     }
173   }
174   return success();
175 
176 #undef CHECK_LINE_END
177 #undef READ_NUM
178 #undef VP_READ_ADVANCE
179 }
180 
181 std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
182   // Skip empty lines and comments.
183   while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
184     ++Line;
185   // If we hit EOF while looking for a name, we're done.
186   if (Line.is_at_end()) {
187     Symtab->finalizeSymtab();
188     return error(instrprof_error::eof);
189   }
190 
191   // Read the function name.
192   Record.Name = *Line++;
193   Symtab->addFuncName(Record.Name);
194 
195   // Read the function hash.
196   if (Line.is_at_end())
197     return error(instrprof_error::truncated);
198   if ((Line++)->getAsInteger(0, Record.Hash))
199     return error(instrprof_error::malformed);
200 
201   // Read the number of counters.
202   uint64_t NumCounters;
203   if (Line.is_at_end())
204     return error(instrprof_error::truncated);
205   if ((Line++)->getAsInteger(10, NumCounters))
206     return error(instrprof_error::malformed);
207   if (NumCounters == 0)
208     return error(instrprof_error::malformed);
209 
210   // Read each counter and fill our internal storage with the values.
211   Record.Counts.clear();
212   Record.Counts.reserve(NumCounters);
213   for (uint64_t I = 0; I < NumCounters; ++I) {
214     if (Line.is_at_end())
215       return error(instrprof_error::truncated);
216     uint64_t Count;
217     if ((Line++)->getAsInteger(10, Count))
218       return error(instrprof_error::malformed);
219     Record.Counts.push_back(Count);
220   }
221 
222   // Check if value profile data exists and read it if so.
223   if (std::error_code EC = readValueProfileData(Record))
224     return EC;
225 
226   // This is needed to avoid two pass parsing because llvm-profdata
227   // does dumping while reading.
228   Symtab->finalizeSymtab();
229   return success();
230 }
231 
232 template <class IntPtrT>
233 bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
234   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
235     return false;
236   uint64_t Magic =
237     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
238   return RawInstrProf::getMagic<IntPtrT>() == Magic ||
239          sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic;
240 }
241 
242 template <class IntPtrT>
243 std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
244   if (!hasFormat(*DataBuffer))
245     return error(instrprof_error::bad_magic);
246   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
247     return error(instrprof_error::bad_header);
248   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
249       DataBuffer->getBufferStart());
250   ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
251   return readHeader(*Header);
252 }
253 
254 template <class IntPtrT>
255 std::error_code
256 RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
257   const char *End = DataBuffer->getBufferEnd();
258   // Skip zero padding between profiles.
259   while (CurrentPos != End && *CurrentPos == 0)
260     ++CurrentPos;
261   // If there's nothing left, we're done.
262   if (CurrentPos == End)
263     return instrprof_error::eof;
264   // If there isn't enough space for another header, this is probably just
265   // garbage at the end of the file.
266   if (CurrentPos + sizeof(RawInstrProf::Header) > End)
267     return instrprof_error::malformed;
268   // The writer ensures each profile is padded to start at an aligned address.
269   if (reinterpret_cast<size_t>(CurrentPos) % alignOf<uint64_t>())
270     return instrprof_error::malformed;
271   // The magic should have the same byte order as in the previous header.
272   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
273   if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
274     return instrprof_error::bad_magic;
275 
276   // There's another profile to read, so we need to process the header.
277   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
278   return readHeader(*Header);
279 }
280 
281 template <class IntPtrT>
282 void RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
283   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
284     StringRef FunctionName(getName(I->NamePtr), swap(I->NameSize));
285     Symtab.addFuncName(FunctionName);
286     const IntPtrT FPtr = swap(I->FunctionPointer);
287     if (!FPtr)
288       continue;
289     Symtab.mapAddress(FPtr, IndexedInstrProf::ComputeHash(FunctionName));
290   }
291   Symtab.finalizeSymtab();
292 }
293 
294 template <class IntPtrT>
295 std::error_code
296 RawInstrProfReader<IntPtrT>::readHeader(const RawInstrProf::Header &Header) {
297   if (swap(Header.Version) != RawInstrProf::Version)
298     return error(instrprof_error::unsupported_version);
299 
300   CountersDelta = swap(Header.CountersDelta);
301   NamesDelta = swap(Header.NamesDelta);
302   auto DataSize = swap(Header.DataSize);
303   auto CountersSize = swap(Header.CountersSize);
304   auto NamesSize = swap(Header.NamesSize);
305   auto ValueDataSize = swap(Header.ValueDataSize);
306   ValueKindLast = swap(Header.ValueKindLast);
307 
308   auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>);
309   auto PaddingSize = getNumPaddingBytes(NamesSize);
310 
311   ptrdiff_t DataOffset = sizeof(RawInstrProf::Header);
312   ptrdiff_t CountersOffset = DataOffset + DataSizeInBytes;
313   ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
314   ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
315   size_t ProfileSize = ValueDataOffset + ValueDataSize;
316 
317   auto *Start = reinterpret_cast<const char *>(&Header);
318   if (Start + ProfileSize > DataBuffer->getBufferEnd())
319     return error(instrprof_error::bad_header);
320 
321   Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
322       Start + DataOffset);
323   DataEnd = Data + DataSize;
324   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
325   NamesStart = Start + NamesOffset;
326   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
327   ProfileEnd = Start + ProfileSize;
328 
329   std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>();
330   createSymtab(*NewSymtab.get());
331   Symtab = std::move(NewSymtab);
332   return success();
333 }
334 
335 template <class IntPtrT>
336 std::error_code RawInstrProfReader<IntPtrT>::readName(InstrProfRecord &Record) {
337   Record.Name = StringRef(getName(Data->NamePtr), swap(Data->NameSize));
338   if (Record.Name.data() < NamesStart ||
339       Record.Name.data() + Record.Name.size() >
340           reinterpret_cast<const char *>(ValueDataStart))
341     return error(instrprof_error::malformed);
342   return success();
343 }
344 
345 template <class IntPtrT>
346 std::error_code RawInstrProfReader<IntPtrT>::readFuncHash(
347     InstrProfRecord &Record) {
348   Record.Hash = swap(Data->FuncHash);
349   return success();
350 }
351 
352 template <class IntPtrT>
353 std::error_code RawInstrProfReader<IntPtrT>::readRawCounts(
354     InstrProfRecord &Record) {
355   uint32_t NumCounters = swap(Data->NumCounters);
356   IntPtrT CounterPtr = Data->CounterPtr;
357   if (NumCounters == 0)
358     return error(instrprof_error::malformed);
359 
360   auto RawCounts = makeArrayRef(getCounter(CounterPtr), NumCounters);
361   auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
362 
363   // Check bounds.
364   if (RawCounts.data() < CountersStart ||
365       RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
366     return error(instrprof_error::malformed);
367 
368   if (ShouldSwapBytes) {
369     Record.Counts.clear();
370     Record.Counts.reserve(RawCounts.size());
371     for (uint64_t Count : RawCounts)
372       Record.Counts.push_back(swap(Count));
373   } else
374     Record.Counts = RawCounts;
375 
376   return success();
377 }
378 
379 template <class IntPtrT>
380 std::error_code
381 RawInstrProfReader<IntPtrT>::readValueProfilingData(InstrProfRecord &Record) {
382 
383   Record.clearValueData();
384   CurValueDataSize = 0;
385   // Need to match the logic in value profile dumper code in compiler-rt:
386   uint32_t NumValueKinds = 0;
387   for (uint32_t I = 0; I < IPVK_Last + 1; I++)
388     NumValueKinds += (Data->NumValueSites[I] != 0);
389 
390   if (!NumValueKinds)
391     return success();
392 
393   ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
394       ValueProfData::getValueProfData(ValueDataStart,
395                                       (const unsigned char *)ProfileEnd,
396                                       getDataEndianness());
397 
398   if (VDataPtrOrErr.getError())
399     return VDataPtrOrErr.getError();
400 
401   VDataPtrOrErr.get()->deserializeTo(Record, &Symtab->getAddrHashMap());
402   CurValueDataSize = VDataPtrOrErr.get()->getSize();
403   return success();
404 }
405 
406 template <class IntPtrT>
407 std::error_code
408 RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
409   if (atEnd())
410     if (std::error_code EC = readNextHeader(ProfileEnd))
411       return EC;
412 
413   // Read name ad set it in Record.
414   if (std::error_code EC = readName(Record))
415     return EC;
416 
417   // Read FuncHash and set it in Record.
418   if (std::error_code EC = readFuncHash(Record))
419     return EC;
420 
421   // Read raw counts and set Record.
422   if (std::error_code EC = readRawCounts(Record))
423     return EC;
424 
425   // Read value data and set Record.
426   if (std::error_code EC = readValueProfilingData(Record))
427     return EC;
428 
429   // Iterate.
430   advanceData();
431   return success();
432 }
433 
434 namespace llvm {
435 template class RawInstrProfReader<uint32_t>;
436 template class RawInstrProfReader<uint64_t>;
437 }
438 
439 InstrProfLookupTrait::hash_value_type
440 InstrProfLookupTrait::ComputeHash(StringRef K) {
441   return IndexedInstrProf::ComputeHash(HashType, K);
442 }
443 
444 typedef InstrProfLookupTrait::data_type data_type;
445 typedef InstrProfLookupTrait::offset_type offset_type;
446 
447 bool InstrProfLookupTrait::readValueProfilingData(
448     const unsigned char *&D, const unsigned char *const End) {
449   ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
450       ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
451 
452   if (VDataPtrOrErr.getError())
453     return false;
454 
455   VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
456   D += VDataPtrOrErr.get()->TotalSize;
457 
458   return true;
459 }
460 
461 data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
462                                          offset_type N) {
463   // Check if the data is corrupt. If so, don't try to read it.
464   if (N % sizeof(uint64_t))
465     return data_type();
466 
467   DataBuffer.clear();
468   std::vector<uint64_t> CounterBuffer;
469 
470   using namespace support;
471   const unsigned char *End = D + N;
472   while (D < End) {
473     // Read hash.
474     if (D + sizeof(uint64_t) >= End)
475       return data_type();
476     uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
477 
478     // Initialize number of counters for FormatVersion == 1.
479     uint64_t CountsSize = N / sizeof(uint64_t) - 1;
480     // If format version is different then read the number of counters.
481     if (FormatVersion != IndexedInstrProf::ProfVersion::Version1) {
482       if (D + sizeof(uint64_t) > End)
483         return data_type();
484       CountsSize = endian::readNext<uint64_t, little, unaligned>(D);
485     }
486     // Read counter values.
487     if (D + CountsSize * sizeof(uint64_t) > End)
488       return data_type();
489 
490     CounterBuffer.clear();
491     CounterBuffer.reserve(CountsSize);
492     for (uint64_t J = 0; J < CountsSize; ++J)
493       CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
494 
495     DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
496 
497     // Read value profiling data.
498     if (FormatVersion > IndexedInstrProf::ProfVersion::Version2 &&
499         !readValueProfilingData(D, End)) {
500       DataBuffer.clear();
501       return data_type();
502     }
503   }
504   return DataBuffer;
505 }
506 
507 template <typename HashTableImpl>
508 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
509     StringRef FuncName, ArrayRef<InstrProfRecord> &Data) {
510   auto Iter = HashTable->find(FuncName);
511   if (Iter == HashTable->end())
512     return instrprof_error::unknown_function;
513 
514   Data = (*Iter);
515   if (Data.empty())
516     return instrprof_error::malformed;
517 
518   return instrprof_error::success;
519 }
520 
521 template <typename HashTableImpl>
522 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
523     ArrayRef<InstrProfRecord> &Data) {
524   if (atEnd())
525     return instrprof_error::eof;
526 
527   Data = *RecordIterator;
528 
529   if (Data.empty())
530     return instrprof_error::malformed;
531 
532   return instrprof_error::success;
533 }
534 
535 template <typename HashTableImpl>
536 InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
537     const unsigned char *Buckets, const unsigned char *const Payload,
538     const unsigned char *const Base, IndexedInstrProf::HashT HashType,
539     uint64_t Version) {
540   FormatVersion = Version;
541   HashTable.reset(HashTableImpl::Create(
542       Buckets, Payload, Base,
543       typename HashTableImpl::InfoType(HashType, Version)));
544   RecordIterator = HashTable->data_begin();
545 }
546 
547 bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
548   if (DataBuffer.getBufferSize() < 8)
549     return false;
550   using namespace support;
551   uint64_t Magic =
552       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
553   // Verify that it's magical.
554   return Magic == IndexedInstrProf::Magic;
555 }
556 
557 std::error_code IndexedInstrProfReader::readHeader() {
558   const unsigned char *Start =
559       (const unsigned char *)DataBuffer->getBufferStart();
560   const unsigned char *Cur = Start;
561   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
562     return error(instrprof_error::truncated);
563 
564   using namespace support;
565 
566   auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur);
567   Cur += sizeof(IndexedInstrProf::Header);
568 
569   // Check the magic number.
570   uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic);
571   if (Magic != IndexedInstrProf::Magic)
572     return error(instrprof_error::bad_magic);
573 
574   // Read the version.
575   uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version);
576   if (FormatVersion > IndexedInstrProf::ProfVersion::CurrentVersion)
577     return error(instrprof_error::unsupported_version);
578 
579   // Read the maximal function count.
580   MaxFunctionCount =
581       endian::byte_swap<uint64_t, little>(Header->MaxFunctionCount);
582 
583   // Read the hash type and start offset.
584   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
585       endian::byte_swap<uint64_t, little>(Header->HashType));
586   if (HashType > IndexedInstrProf::HashT::Last)
587     return error(instrprof_error::unsupported_hash_type);
588 
589   uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset);
590 
591   // The rest of the file is an on disk hash table.
592   InstrProfReaderIndexBase *IndexPtr = nullptr;
593   IndexPtr = new InstrProfReaderIndex<OnDiskHashTableImplV3>(
594       Start + HashOffset, Cur, Start, HashType, FormatVersion);
595   Index.reset(IndexPtr);
596   return success();
597 }
598 
599 InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
600   if (Symtab.get())
601     return *Symtab.get();
602 
603   std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>();
604   Index->populateSymtab(*NewSymtab.get());
605 
606   Symtab = std::move(NewSymtab);
607   return *Symtab.get();
608 }
609 
610 ErrorOr<InstrProfRecord>
611 IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName,
612                                            uint64_t FuncHash) {
613   ArrayRef<InstrProfRecord> Data;
614   std::error_code EC = Index->getRecords(FuncName, Data);
615   if (EC != instrprof_error::success)
616     return EC;
617   // Found it. Look for counters with the right hash.
618   for (unsigned I = 0, E = Data.size(); I < E; ++I) {
619     // Check for a match and fill the vector if there is one.
620     if (Data[I].Hash == FuncHash) {
621       return std::move(Data[I]);
622     }
623   }
624   return error(instrprof_error::hash_mismatch);
625 }
626 
627 std::error_code
628 IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
629                                           std::vector<uint64_t> &Counts) {
630   ErrorOr<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
631   if (std::error_code EC = Record.getError())
632     return EC;
633 
634   Counts = Record.get().Counts;
635   return success();
636 }
637 
638 std::error_code IndexedInstrProfReader::readNextRecord(
639     InstrProfRecord &Record) {
640   static unsigned RecordIndex = 0;
641 
642   ArrayRef<InstrProfRecord> Data;
643 
644   std::error_code EC = Index->getRecords(Data);
645   if (EC != instrprof_error::success)
646     return error(EC);
647 
648   Record = Data[RecordIndex++];
649   if (RecordIndex >= Data.size()) {
650     Index->advanceToNextKey();
651     RecordIndex = 0;
652   }
653   return success();
654 }
655