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>>
setupMemoryBuffer(std::string Path)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 
initializeReader(InstrProfReader & Reader)30 static std::error_code initializeReader(InstrProfReader &Reader) {
31   return Reader.readHeader();
32 }
33 
34 ErrorOr<std::unique_ptr<InstrProfReader>>
create(std::string Path)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>>
create(std::unique_ptr<MemoryBuffer> Buffer)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>>
create(std::string Path)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>>
create(std::unique_ptr<MemoryBuffer> Buffer)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 
Increment()97 void InstrProfIterator::Increment() {
98   if (Reader->readNextRecord(Record))
99     *this = InstrProfIterator();
100 }
101 
hasFormat(const MemoryBuffer & Buffer)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 
readHeader()112 std::error_code TextInstrProfReader::readHeader() {
113   Symtab.reset(new InstrProfSymtab());
114   return success();
115 }
116 
117 std::error_code
readValueProfileData(InstrProfRecord & Record)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 
readNextRecord(InstrProfRecord & Record)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>
hasFormat(const MemoryBuffer & DataBuffer)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>
readHeader()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
readNextHeader(const char * CurrentPos)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>
createSymtab(InstrProfSymtab & Symtab)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
readHeader(const RawInstrProf::Header & Header)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>
readName(InstrProfRecord & Record)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>
readFuncHash(InstrProfRecord & Record)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>
readRawCounts(InstrProfRecord & Record)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
readValueProfilingData(InstrProfRecord & Record)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
readNextRecord(InstrProfRecord & Record)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
ComputeHash(StringRef K)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 
readValueProfilingData(const unsigned char * & D,const unsigned char * const End)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 
ReadData(StringRef K,const unsigned char * D,offset_type N)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 != 1) {
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 > 2 && !readValueProfilingData(D, End)) {
499       DataBuffer.clear();
500       return data_type();
501     }
502   }
503   return DataBuffer;
504 }
505 
506 template <typename HashTableImpl>
getRecords(StringRef FuncName,ArrayRef<InstrProfRecord> & Data)507 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
508     StringRef FuncName, ArrayRef<InstrProfRecord> &Data) {
509   auto Iter = HashTable->find(FuncName);
510   if (Iter == HashTable->end())
511     return instrprof_error::unknown_function;
512 
513   Data = (*Iter);
514   if (Data.empty())
515     return instrprof_error::malformed;
516 
517   return instrprof_error::success;
518 }
519 
520 template <typename HashTableImpl>
getRecords(ArrayRef<InstrProfRecord> & Data)521 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
522     ArrayRef<InstrProfRecord> &Data) {
523   if (atEnd())
524     return instrprof_error::eof;
525 
526   Data = *RecordIterator;
527 
528   if (Data.empty())
529     return instrprof_error::malformed;
530 
531   return instrprof_error::success;
532 }
533 
534 template <typename HashTableImpl>
InstrProfReaderIndex(const unsigned char * Buckets,const unsigned char * const Payload,const unsigned char * const Base,IndexedInstrProf::HashT HashType,uint64_t Version)535 InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
536     const unsigned char *Buckets, const unsigned char *const Payload,
537     const unsigned char *const Base, IndexedInstrProf::HashT HashType,
538     uint64_t Version) {
539   FormatVersion = Version;
540   HashTable.reset(HashTableImpl::Create(
541       Buckets, Payload, Base,
542       typename HashTableImpl::InfoType(HashType, Version)));
543   RecordIterator = HashTable->data_begin();
544 }
545 
hasFormat(const MemoryBuffer & DataBuffer)546 bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
547   if (DataBuffer.getBufferSize() < 8)
548     return false;
549   using namespace support;
550   uint64_t Magic =
551       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
552   // Verify that it's magical.
553   return Magic == IndexedInstrProf::Magic;
554 }
555 
readHeader()556 std::error_code IndexedInstrProfReader::readHeader() {
557   const unsigned char *Start =
558       (const unsigned char *)DataBuffer->getBufferStart();
559   const unsigned char *Cur = Start;
560   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
561     return error(instrprof_error::truncated);
562 
563   using namespace support;
564 
565   auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur);
566   Cur += sizeof(IndexedInstrProf::Header);
567 
568   // Check the magic number.
569   uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic);
570   if (Magic != IndexedInstrProf::Magic)
571     return error(instrprof_error::bad_magic);
572 
573   // Read the version.
574   uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version);
575   if (FormatVersion > IndexedInstrProf::Version)
576     return error(instrprof_error::unsupported_version);
577 
578   // Read the maximal function count.
579   MaxFunctionCount =
580       endian::byte_swap<uint64_t, little>(Header->MaxFunctionCount);
581 
582   // Read the hash type and start offset.
583   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
584       endian::byte_swap<uint64_t, little>(Header->HashType));
585   if (HashType > IndexedInstrProf::HashT::Last)
586     return error(instrprof_error::unsupported_hash_type);
587 
588   uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset);
589 
590   // The rest of the file is an on disk hash table.
591   InstrProfReaderIndexBase *IndexPtr = nullptr;
592   IndexPtr = new InstrProfReaderIndex<OnDiskHashTableImplV3>(
593       Start + HashOffset, Cur, Start, HashType, FormatVersion);
594   Index.reset(IndexPtr);
595   return success();
596 }
597 
getSymtab()598 InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
599   if (Symtab.get())
600     return *Symtab.get();
601 
602   std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>();
603   Index->populateSymtab(*NewSymtab.get());
604 
605   Symtab = std::move(NewSymtab);
606   return *Symtab.get();
607 }
608 
609 ErrorOr<InstrProfRecord>
getInstrProfRecord(StringRef FuncName,uint64_t FuncHash)610 IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName,
611                                            uint64_t FuncHash) {
612   ArrayRef<InstrProfRecord> Data;
613   std::error_code EC = Index->getRecords(FuncName, Data);
614   if (EC != instrprof_error::success)
615     return EC;
616   // Found it. Look for counters with the right hash.
617   for (unsigned I = 0, E = Data.size(); I < E; ++I) {
618     // Check for a match and fill the vector if there is one.
619     if (Data[I].Hash == FuncHash) {
620       return std::move(Data[I]);
621     }
622   }
623   return error(instrprof_error::hash_mismatch);
624 }
625 
626 std::error_code
getFunctionCounts(StringRef FuncName,uint64_t FuncHash,std::vector<uint64_t> & Counts)627 IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
628                                           std::vector<uint64_t> &Counts) {
629   ErrorOr<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
630   if (std::error_code EC = Record.getError())
631     return EC;
632 
633   Counts = Record.get().Counts;
634   return success();
635 }
636 
readNextRecord(InstrProfRecord & Record)637 std::error_code IndexedInstrProfReader::readNextRecord(
638     InstrProfRecord &Record) {
639   static unsigned RecordIndex = 0;
640 
641   ArrayRef<InstrProfRecord> Data;
642 
643   std::error_code EC = Index->getRecords(Data);
644   if (EC != instrprof_error::success)
645     return error(EC);
646 
647   Record = Data[RecordIndex++];
648   if (RecordIndex >= Data.size()) {
649     Index->advanceToNextKey();
650     RecordIndex = 0;
651   }
652   return success();
653 }
654