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/ProfileData/InstrProf.h" 17 18 #include <cassert> 19 20 using namespace llvm; 21 22 error_code InstrProfReader::create(std::string Path, 23 std::unique_ptr<InstrProfReader> &Result) { 24 std::unique_ptr<MemoryBuffer> Buffer; 25 if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer)) 26 return EC; 27 28 // Sanity check the file. 29 if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max()) 30 return instrprof_error::too_large; 31 32 // Create the reader. 33 if (RawInstrProfReader64::hasFormat(*Buffer)) 34 Result.reset(new RawInstrProfReader64(std::move(Buffer))); 35 else if (RawInstrProfReader32::hasFormat(*Buffer)) 36 Result.reset(new RawInstrProfReader32(std::move(Buffer))); 37 else 38 Result.reset(new TextInstrProfReader(std::move(Buffer))); 39 40 // Read the header and return the result. 41 return Result->readHeader(); 42 } 43 44 void InstrProfIterator::Increment() { 45 if (Reader->readNextRecord(Record)) 46 *this = InstrProfIterator(); 47 } 48 49 error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { 50 // Skip empty lines. 51 while (!Line.is_at_end() && Line->empty()) 52 ++Line; 53 // If we hit EOF while looking for a name, we're done. 54 if (Line.is_at_end()) 55 return error(instrprof_error::eof); 56 57 // Read the function name. 58 Record.Name = *Line++; 59 60 // Read the function hash. 61 if (Line.is_at_end()) 62 return error(instrprof_error::truncated); 63 if ((Line++)->getAsInteger(10, Record.Hash)) 64 return error(instrprof_error::malformed); 65 66 // Read the number of counters. 67 uint64_t NumCounters; 68 if (Line.is_at_end()) 69 return error(instrprof_error::truncated); 70 if ((Line++)->getAsInteger(10, NumCounters)) 71 return error(instrprof_error::malformed); 72 73 // Read each counter and fill our internal storage with the values. 74 Counts.clear(); 75 Counts.reserve(NumCounters); 76 for (uint64_t I = 0; I < NumCounters; ++I) { 77 if (Line.is_at_end()) 78 return error(instrprof_error::truncated); 79 uint64_t Count; 80 if ((Line++)->getAsInteger(10, Count)) 81 return error(instrprof_error::malformed); 82 Counts.push_back(Count); 83 } 84 // Give the record a reference to our internal counter storage. 85 Record.Counts = Counts; 86 87 return success(); 88 } 89 90 template <class IntPtrT> 91 static uint64_t getRawMagic(); 92 93 template <> 94 uint64_t getRawMagic<uint64_t>() { 95 return 96 uint64_t(255) << 56 | 97 uint64_t('l') << 48 | 98 uint64_t('p') << 40 | 99 uint64_t('r') << 32 | 100 uint64_t('o') << 24 | 101 uint64_t('f') << 16 | 102 uint64_t('r') << 8 | 103 uint64_t(129); 104 } 105 106 template <> 107 uint64_t getRawMagic<uint32_t>() { 108 return 109 uint64_t(255) << 56 | 110 uint64_t('l') << 48 | 111 uint64_t('p') << 40 | 112 uint64_t('r') << 32 | 113 uint64_t('o') << 24 | 114 uint64_t('f') << 16 | 115 uint64_t('R') << 8 | 116 uint64_t(129); 117 } 118 119 template <class IntPtrT> 120 bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { 121 if (DataBuffer.getBufferSize() < sizeof(uint64_t)) 122 return false; 123 uint64_t Magic = 124 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); 125 return getRawMagic<IntPtrT>() == Magic || 126 sys::SwapByteOrder(getRawMagic<IntPtrT>()) == Magic; 127 } 128 129 template <class IntPtrT> 130 error_code RawInstrProfReader<IntPtrT>::readHeader() { 131 if (!hasFormat(*DataBuffer)) 132 return error(instrprof_error::bad_magic); 133 if (DataBuffer->getBufferSize() < sizeof(RawHeader)) 134 return error(instrprof_error::bad_header); 135 auto *Header = 136 reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart()); 137 ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>(); 138 return readHeader(*Header); 139 } 140 141 static uint64_t getRawVersion() { 142 return 1; 143 } 144 145 template <class IntPtrT> 146 error_code RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) { 147 if (swap(Header.Version) != getRawVersion()) 148 return error(instrprof_error::unsupported_version); 149 150 CountersDelta = swap(Header.CountersDelta); 151 NamesDelta = swap(Header.NamesDelta); 152 auto DataSize = swap(Header.DataSize); 153 auto CountersSize = swap(Header.CountersSize); 154 auto NamesSize = swap(Header.NamesSize); 155 156 ptrdiff_t DataOffset = sizeof(RawHeader); 157 ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize; 158 ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize; 159 size_t FileSize = NamesOffset + sizeof(char) * NamesSize; 160 161 if (FileSize != DataBuffer->getBufferSize()) 162 return error(instrprof_error::bad_header); 163 164 const char *Start = DataBuffer->getBufferStart(); 165 Data = reinterpret_cast<const ProfileData *>(Start + DataOffset); 166 DataEnd = Data + DataSize; 167 CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset); 168 NamesStart = Start + NamesOffset; 169 170 return success(); 171 } 172 173 template <class IntPtrT> 174 error_code 175 RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) { 176 if (Data == DataEnd) 177 return error(instrprof_error::eof); 178 179 // Get the raw data. 180 StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize)); 181 auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), 182 swap(Data->NumCounters)); 183 184 // Check bounds. 185 auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); 186 if (RawName.data() < NamesStart || 187 RawName.data() + RawName.size() > DataBuffer->getBufferEnd() || 188 RawCounts.data() < CountersStart || 189 RawCounts.data() + RawCounts.size() > NamesStartAsCounter) 190 return error(instrprof_error::malformed); 191 192 // Store the data in Record, byte-swapping as necessary. 193 Record.Hash = swap(Data->FuncHash); 194 Record.Name = RawName; 195 if (ShouldSwapBytes) { 196 Counts.clear(); 197 Counts.reserve(RawCounts.size()); 198 for (uint64_t Count : RawCounts) 199 Counts.push_back(swap(Count)); 200 Record.Counts = Counts; 201 } else 202 Record.Counts = RawCounts; 203 204 // Iterate. 205 ++Data; 206 return success(); 207 } 208 209 namespace llvm { 210 template class RawInstrProfReader<uint32_t>; 211 template class RawInstrProfReader<uint64_t>; 212 } 213