File: | lib/ProfileData/Coverage/CoverageMappingReader.cpp |
Warning: | line 723, column 22 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This file contains support for reading coverage mapping data for | |||
10 | // instrumentation based coverage. | |||
11 | // | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" | |||
15 | #include "llvm/ADT/ArrayRef.h" | |||
16 | #include "llvm/ADT/DenseMap.h" | |||
17 | #include "llvm/ADT/STLExtras.h" | |||
18 | #include "llvm/ADT/SmallVector.h" | |||
19 | #include "llvm/ADT/StringRef.h" | |||
20 | #include "llvm/ADT/Triple.h" | |||
21 | #include "llvm/Object/Binary.h" | |||
22 | #include "llvm/Object/Error.h" | |||
23 | #include "llvm/Object/MachOUniversal.h" | |||
24 | #include "llvm/Object/ObjectFile.h" | |||
25 | #include "llvm/Object/COFF.h" | |||
26 | #include "llvm/ProfileData/InstrProf.h" | |||
27 | #include "llvm/Support/Casting.h" | |||
28 | #include "llvm/Support/Debug.h" | |||
29 | #include "llvm/Support/Endian.h" | |||
30 | #include "llvm/Support/Error.h" | |||
31 | #include "llvm/Support/ErrorHandling.h" | |||
32 | #include "llvm/Support/LEB128.h" | |||
33 | #include "llvm/Support/MathExtras.h" | |||
34 | #include "llvm/Support/raw_ostream.h" | |||
35 | #include <vector> | |||
36 | ||||
37 | using namespace llvm; | |||
38 | using namespace coverage; | |||
39 | using namespace object; | |||
40 | ||||
41 | #define DEBUG_TYPE"coverage-mapping" "coverage-mapping" | |||
42 | ||||
43 | void CoverageMappingIterator::increment() { | |||
44 | if (ReadErr != coveragemap_error::success) | |||
45 | return; | |||
46 | ||||
47 | // Check if all the records were read or if an error occurred while reading | |||
48 | // the next record. | |||
49 | if (auto E = Reader->readNextRecord(Record)) | |||
50 | handleAllErrors(std::move(E), [&](const CoverageMapError &CME) { | |||
51 | if (CME.get() == coveragemap_error::eof) | |||
52 | *this = CoverageMappingIterator(); | |||
53 | else | |||
54 | ReadErr = CME.get(); | |||
55 | }); | |||
56 | } | |||
57 | ||||
58 | Error RawCoverageReader::readULEB128(uint64_t &Result) { | |||
59 | if (Data.empty()) | |||
60 | return make_error<CoverageMapError>(coveragemap_error::truncated); | |||
61 | unsigned N = 0; | |||
62 | Result = decodeULEB128(Data.bytes_begin(), &N); | |||
63 | if (N > Data.size()) | |||
64 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
65 | Data = Data.substr(N); | |||
66 | return Error::success(); | |||
67 | } | |||
68 | ||||
69 | Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) { | |||
70 | if (auto Err = readULEB128(Result)) | |||
71 | return Err; | |||
72 | if (Result >= MaxPlus1) | |||
73 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
74 | return Error::success(); | |||
75 | } | |||
76 | ||||
77 | Error RawCoverageReader::readSize(uint64_t &Result) { | |||
78 | if (auto Err = readULEB128(Result)) | |||
79 | return Err; | |||
80 | // Sanity check the number. | |||
81 | if (Result > Data.size()) | |||
82 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
83 | return Error::success(); | |||
84 | } | |||
85 | ||||
86 | Error RawCoverageReader::readString(StringRef &Result) { | |||
87 | uint64_t Length; | |||
88 | if (auto Err = readSize(Length)) | |||
89 | return Err; | |||
90 | Result = Data.substr(0, Length); | |||
91 | Data = Data.substr(Length); | |||
92 | return Error::success(); | |||
93 | } | |||
94 | ||||
95 | Error RawCoverageFilenamesReader::read() { | |||
96 | uint64_t NumFilenames; | |||
97 | if (auto Err = readSize(NumFilenames)) | |||
98 | return Err; | |||
99 | for (size_t I = 0; I < NumFilenames; ++I) { | |||
100 | StringRef Filename; | |||
101 | if (auto Err = readString(Filename)) | |||
102 | return Err; | |||
103 | Filenames.push_back(Filename); | |||
104 | } | |||
105 | return Error::success(); | |||
106 | } | |||
107 | ||||
108 | Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) { | |||
109 | auto Tag = Value & Counter::EncodingTagMask; | |||
110 | switch (Tag) { | |||
111 | case Counter::Zero: | |||
112 | C = Counter::getZero(); | |||
113 | return Error::success(); | |||
114 | case Counter::CounterValueReference: | |||
115 | C = Counter::getCounter(Value >> Counter::EncodingTagBits); | |||
116 | return Error::success(); | |||
117 | default: | |||
118 | break; | |||
119 | } | |||
120 | Tag -= Counter::Expression; | |||
121 | switch (Tag) { | |||
122 | case CounterExpression::Subtract: | |||
123 | case CounterExpression::Add: { | |||
124 | auto ID = Value >> Counter::EncodingTagBits; | |||
125 | if (ID >= Expressions.size()) | |||
126 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
127 | Expressions[ID].Kind = CounterExpression::ExprKind(Tag); | |||
128 | C = Counter::getExpression(ID); | |||
129 | break; | |||
130 | } | |||
131 | default: | |||
132 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
133 | } | |||
134 | return Error::success(); | |||
135 | } | |||
136 | ||||
137 | Error RawCoverageMappingReader::readCounter(Counter &C) { | |||
138 | uint64_t EncodedCounter; | |||
139 | if (auto Err = | |||
140 | readIntMax(EncodedCounter, std::numeric_limits<unsigned>::max())) | |||
141 | return Err; | |||
142 | if (auto Err = decodeCounter(EncodedCounter, C)) | |||
143 | return Err; | |||
144 | return Error::success(); | |||
145 | } | |||
146 | ||||
147 | static const unsigned EncodingExpansionRegionBit = 1 | |||
148 | << Counter::EncodingTagBits; | |||
149 | ||||
150 | /// Read the sub-array of regions for the given inferred file id. | |||
151 | /// \param NumFileIDs the number of file ids that are defined for this | |||
152 | /// function. | |||
153 | Error RawCoverageMappingReader::readMappingRegionsSubArray( | |||
154 | std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID, | |||
155 | size_t NumFileIDs) { | |||
156 | uint64_t NumRegions; | |||
157 | if (auto Err = readSize(NumRegions)) | |||
158 | return Err; | |||
159 | unsigned LineStart = 0; | |||
160 | for (size_t I = 0; I < NumRegions; ++I) { | |||
161 | Counter C; | |||
162 | CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion; | |||
163 | ||||
164 | // Read the combined counter + region kind. | |||
165 | uint64_t EncodedCounterAndRegion; | |||
166 | if (auto Err = readIntMax(EncodedCounterAndRegion, | |||
167 | std::numeric_limits<unsigned>::max())) | |||
168 | return Err; | |||
169 | unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask; | |||
170 | uint64_t ExpandedFileID = 0; | |||
171 | if (Tag != Counter::Zero) { | |||
172 | if (auto Err = decodeCounter(EncodedCounterAndRegion, C)) | |||
173 | return Err; | |||
174 | } else { | |||
175 | // Is it an expansion region? | |||
176 | if (EncodedCounterAndRegion & EncodingExpansionRegionBit) { | |||
177 | Kind = CounterMappingRegion::ExpansionRegion; | |||
178 | ExpandedFileID = EncodedCounterAndRegion >> | |||
179 | Counter::EncodingCounterTagAndExpansionRegionTagBits; | |||
180 | if (ExpandedFileID >= NumFileIDs) | |||
181 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
182 | } else { | |||
183 | switch (EncodedCounterAndRegion >> | |||
184 | Counter::EncodingCounterTagAndExpansionRegionTagBits) { | |||
185 | case CounterMappingRegion::CodeRegion: | |||
186 | // Don't do anything when we have a code region with a zero counter. | |||
187 | break; | |||
188 | case CounterMappingRegion::SkippedRegion: | |||
189 | Kind = CounterMappingRegion::SkippedRegion; | |||
190 | break; | |||
191 | default: | |||
192 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
193 | } | |||
194 | } | |||
195 | } | |||
196 | ||||
197 | // Read the source range. | |||
198 | uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd; | |||
199 | if (auto Err = | |||
200 | readIntMax(LineStartDelta, std::numeric_limits<unsigned>::max())) | |||
201 | return Err; | |||
202 | if (auto Err = readULEB128(ColumnStart)) | |||
203 | return Err; | |||
204 | if (ColumnStart > std::numeric_limits<unsigned>::max()) | |||
205 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
206 | if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max())) | |||
207 | return Err; | |||
208 | if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max())) | |||
209 | return Err; | |||
210 | LineStart += LineStartDelta; | |||
211 | ||||
212 | // If the high bit of ColumnEnd is set, this is a gap region. | |||
213 | if (ColumnEnd & (1U << 31)) { | |||
214 | Kind = CounterMappingRegion::GapRegion; | |||
215 | ColumnEnd &= ~(1U << 31); | |||
216 | } | |||
217 | ||||
218 | // Adjust the column locations for the empty regions that are supposed to | |||
219 | // cover whole lines. Those regions should be encoded with the | |||
220 | // column range (1 -> std::numeric_limits<unsigned>::max()), but because | |||
221 | // the encoded std::numeric_limits<unsigned>::max() is several bytes long, | |||
222 | // we set the column range to (0 -> 0) to ensure that the column start and | |||
223 | // column end take up one byte each. | |||
224 | // The std::numeric_limits<unsigned>::max() is used to represent a column | |||
225 | // position at the end of the line without knowing the length of that line. | |||
226 | if (ColumnStart == 0 && ColumnEnd == 0) { | |||
227 | ColumnStart = 1; | |||
228 | ColumnEnd = std::numeric_limits<unsigned>::max(); | |||
229 | } | |||
230 | ||||
231 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
232 | dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":"do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
233 | << ColumnStart << " -> " << (LineStart + NumLines) << ":"do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
234 | << ColumnEnd << ", ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
235 | if (Kind == CounterMappingRegion::ExpansionRegion)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
236 | dbgs() << "Expands to file " << ExpandedFileID;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
237 | elsedo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
238 | CounterMappingContext(Expressions).dump(C, dbgs());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
239 | dbgs() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false) | |||
240 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("coverage-mapping")) { { dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" << ColumnStart << " -> " << (LineStart + NumLines ) << ":" << ColumnEnd << ", "; if (Kind == CounterMappingRegion ::ExpansionRegion) dbgs() << "Expands to file " << ExpandedFileID; else CounterMappingContext(Expressions).dump (C, dbgs()); dbgs() << "\n"; }; } } while (false); | |||
241 | ||||
242 | auto CMR = CounterMappingRegion(C, InferredFileID, ExpandedFileID, | |||
243 | LineStart, ColumnStart, | |||
244 | LineStart + NumLines, ColumnEnd, Kind); | |||
245 | if (CMR.startLoc() > CMR.endLoc()) | |||
246 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
247 | MappingRegions.push_back(CMR); | |||
248 | } | |||
249 | return Error::success(); | |||
250 | } | |||
251 | ||||
252 | Error RawCoverageMappingReader::read() { | |||
253 | // Read the virtual file mapping. | |||
254 | SmallVector<unsigned, 8> VirtualFileMapping; | |||
255 | uint64_t NumFileMappings; | |||
256 | if (auto Err = readSize(NumFileMappings)) | |||
257 | return Err; | |||
258 | for (size_t I = 0; I < NumFileMappings; ++I) { | |||
259 | uint64_t FilenameIndex; | |||
260 | if (auto Err = readIntMax(FilenameIndex, TranslationUnitFilenames.size())) | |||
261 | return Err; | |||
262 | VirtualFileMapping.push_back(FilenameIndex); | |||
263 | } | |||
264 | ||||
265 | // Construct the files using unique filenames and virtual file mapping. | |||
266 | for (auto I : VirtualFileMapping) { | |||
267 | Filenames.push_back(TranslationUnitFilenames[I]); | |||
268 | } | |||
269 | ||||
270 | // Read the expressions. | |||
271 | uint64_t NumExpressions; | |||
272 | if (auto Err = readSize(NumExpressions)) | |||
273 | return Err; | |||
274 | // Create an array of dummy expressions that get the proper counters | |||
275 | // when the expressions are read, and the proper kinds when the counters | |||
276 | // are decoded. | |||
277 | Expressions.resize( | |||
278 | NumExpressions, | |||
279 | CounterExpression(CounterExpression::Subtract, Counter(), Counter())); | |||
280 | for (size_t I = 0; I < NumExpressions; ++I) { | |||
281 | if (auto Err = readCounter(Expressions[I].LHS)) | |||
282 | return Err; | |||
283 | if (auto Err = readCounter(Expressions[I].RHS)) | |||
284 | return Err; | |||
285 | } | |||
286 | ||||
287 | // Read the mapping regions sub-arrays. | |||
288 | for (unsigned InferredFileID = 0, S = VirtualFileMapping.size(); | |||
289 | InferredFileID < S; ++InferredFileID) { | |||
290 | if (auto Err = readMappingRegionsSubArray(MappingRegions, InferredFileID, | |||
291 | VirtualFileMapping.size())) | |||
292 | return Err; | |||
293 | } | |||
294 | ||||
295 | // Set the counters for the expansion regions. | |||
296 | // i.e. Counter of expansion region = counter of the first region | |||
297 | // from the expanded file. | |||
298 | // Perform multiple passes to correctly propagate the counters through | |||
299 | // all the nested expansion regions. | |||
300 | SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping; | |||
301 | FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr); | |||
302 | for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) { | |||
303 | for (auto &R : MappingRegions) { | |||
304 | if (R.Kind != CounterMappingRegion::ExpansionRegion) | |||
305 | continue; | |||
306 | assert(!FileIDExpansionRegionMapping[R.ExpandedFileID])((!FileIDExpansionRegionMapping[R.ExpandedFileID]) ? static_cast <void> (0) : __assert_fail ("!FileIDExpansionRegionMapping[R.ExpandedFileID]" , "/build/llvm-toolchain-snapshot-9~svn362543/lib/ProfileData/Coverage/CoverageMappingReader.cpp" , 306, __PRETTY_FUNCTION__)); | |||
307 | FileIDExpansionRegionMapping[R.ExpandedFileID] = &R; | |||
308 | } | |||
309 | for (auto &R : MappingRegions) { | |||
310 | if (FileIDExpansionRegionMapping[R.FileID]) { | |||
311 | FileIDExpansionRegionMapping[R.FileID]->Count = R.Count; | |||
312 | FileIDExpansionRegionMapping[R.FileID] = nullptr; | |||
313 | } | |||
314 | } | |||
315 | } | |||
316 | ||||
317 | return Error::success(); | |||
318 | } | |||
319 | ||||
320 | Expected<bool> RawCoverageMappingDummyChecker::isDummy() { | |||
321 | // A dummy coverage mapping data consists of just one region with zero count. | |||
322 | uint64_t NumFileMappings; | |||
323 | if (Error Err = readSize(NumFileMappings)) | |||
324 | return std::move(Err); | |||
325 | if (NumFileMappings != 1) | |||
326 | return false; | |||
327 | // We don't expect any specific value for the filename index, just skip it. | |||
328 | uint64_t FilenameIndex; | |||
329 | if (Error Err = | |||
330 | readIntMax(FilenameIndex, std::numeric_limits<unsigned>::max())) | |||
331 | return std::move(Err); | |||
332 | uint64_t NumExpressions; | |||
333 | if (Error Err = readSize(NumExpressions)) | |||
334 | return std::move(Err); | |||
335 | if (NumExpressions != 0) | |||
336 | return false; | |||
337 | uint64_t NumRegions; | |||
338 | if (Error Err = readSize(NumRegions)) | |||
339 | return std::move(Err); | |||
340 | if (NumRegions != 1) | |||
341 | return false; | |||
342 | uint64_t EncodedCounterAndRegion; | |||
343 | if (Error Err = readIntMax(EncodedCounterAndRegion, | |||
344 | std::numeric_limits<unsigned>::max())) | |||
345 | return std::move(Err); | |||
346 | unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask; | |||
347 | return Tag == Counter::Zero; | |||
348 | } | |||
349 | ||||
350 | Error InstrProfSymtab::create(SectionRef &Section) { | |||
351 | Expected<StringRef> DataOrErr = Section.getContents(); | |||
352 | if (!DataOrErr) | |||
353 | return DataOrErr.takeError(); | |||
354 | Data = *DataOrErr; | |||
355 | Address = Section.getAddress(); | |||
356 | ||||
357 | // If this is a linked PE/COFF file, then we have to skip over the null byte | |||
358 | // that is allocated in the .lprfn$A section in the LLVM profiling runtime. | |||
359 | const ObjectFile *Obj = Section.getObject(); | |||
360 | if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject()) | |||
361 | Data = Data.drop_front(1); | |||
362 | ||||
363 | return Error::success(); | |||
364 | } | |||
365 | ||||
366 | StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) { | |||
367 | if (Pointer < Address) | |||
368 | return StringRef(); | |||
369 | auto Offset = Pointer - Address; | |||
370 | if (Offset + Size > Data.size()) | |||
371 | return StringRef(); | |||
372 | return Data.substr(Pointer - Address, Size); | |||
373 | } | |||
374 | ||||
375 | // Check if the mapping data is a dummy, i.e. is emitted for an unused function. | |||
376 | static Expected<bool> isCoverageMappingDummy(uint64_t Hash, StringRef Mapping) { | |||
377 | // The hash value of dummy mapping records is always zero. | |||
378 | if (Hash) | |||
379 | return false; | |||
380 | return RawCoverageMappingDummyChecker(Mapping).isDummy(); | |||
381 | } | |||
382 | ||||
383 | namespace { | |||
384 | ||||
385 | struct CovMapFuncRecordReader { | |||
386 | virtual ~CovMapFuncRecordReader() = default; | |||
387 | ||||
388 | // The interface to read coverage mapping function records for a module. | |||
389 | // | |||
390 | // \p Buf points to the buffer containing the \c CovHeader of the coverage | |||
391 | // mapping data associated with the module. | |||
392 | // | |||
393 | // Returns a pointer to the next \c CovHeader if it exists, or a pointer | |||
394 | // greater than \p End if not. | |||
395 | virtual Expected<const char *> readFunctionRecords(const char *Buf, | |||
396 | const char *End) = 0; | |||
397 | ||||
398 | template <class IntPtrT, support::endianness Endian> | |||
399 | static Expected<std::unique_ptr<CovMapFuncRecordReader>> | |||
400 | get(CovMapVersion Version, InstrProfSymtab &P, | |||
401 | std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, | |||
402 | std::vector<StringRef> &F); | |||
403 | }; | |||
404 | ||||
405 | // A class for reading coverage mapping function records for a module. | |||
406 | template <CovMapVersion Version, class IntPtrT, support::endianness Endian> | |||
407 | class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { | |||
408 | using FuncRecordType = | |||
409 | typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType; | |||
410 | using NameRefType = typename CovMapTraits<Version, IntPtrT>::NameRefType; | |||
411 | ||||
412 | // Maps function's name references to the indexes of their records | |||
413 | // in \c Records. | |||
414 | DenseMap<NameRefType, size_t> FunctionRecords; | |||
415 | InstrProfSymtab &ProfileNames; | |||
416 | std::vector<StringRef> &Filenames; | |||
417 | std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records; | |||
418 | ||||
419 | // Add the record to the collection if we don't already have a record that | |||
420 | // points to the same function name. This is useful to ignore the redundant | |||
421 | // records for the functions with ODR linkage. | |||
422 | // In addition, prefer records with real coverage mapping data to dummy | |||
423 | // records, which were emitted for inline functions which were seen but | |||
424 | // not used in the corresponding translation unit. | |||
425 | Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR, | |||
426 | StringRef Mapping, size_t FilenamesBegin) { | |||
427 | uint64_t FuncHash = CFR->template getFuncHash<Endian>(); | |||
428 | NameRefType NameRef = CFR->template getFuncNameRef<Endian>(); | |||
429 | auto InsertResult = | |||
430 | FunctionRecords.insert(std::make_pair(NameRef, Records.size())); | |||
431 | if (InsertResult.second) { | |||
432 | StringRef FuncName; | |||
433 | if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName)) | |||
434 | return Err; | |||
435 | if (FuncName.empty()) | |||
436 | return make_error<InstrProfError>(instrprof_error::malformed); | |||
437 | Records.emplace_back(Version, FuncName, FuncHash, Mapping, FilenamesBegin, | |||
438 | Filenames.size() - FilenamesBegin); | |||
439 | return Error::success(); | |||
440 | } | |||
441 | // Update the existing record if it's a dummy and the new record is real. | |||
442 | size_t OldRecordIndex = InsertResult.first->second; | |||
443 | BinaryCoverageReader::ProfileMappingRecord &OldRecord = | |||
444 | Records[OldRecordIndex]; | |||
445 | Expected<bool> OldIsDummyExpected = isCoverageMappingDummy( | |||
446 | OldRecord.FunctionHash, OldRecord.CoverageMapping); | |||
447 | if (Error Err = OldIsDummyExpected.takeError()) | |||
448 | return Err; | |||
449 | if (!*OldIsDummyExpected) | |||
450 | return Error::success(); | |||
451 | Expected<bool> NewIsDummyExpected = | |||
452 | isCoverageMappingDummy(FuncHash, Mapping); | |||
453 | if (Error Err = NewIsDummyExpected.takeError()) | |||
454 | return Err; | |||
455 | if (*NewIsDummyExpected) | |||
456 | return Error::success(); | |||
457 | OldRecord.FunctionHash = FuncHash; | |||
458 | OldRecord.CoverageMapping = Mapping; | |||
459 | OldRecord.FilenamesBegin = FilenamesBegin; | |||
460 | OldRecord.FilenamesSize = Filenames.size() - FilenamesBegin; | |||
461 | return Error::success(); | |||
462 | } | |||
463 | ||||
464 | public: | |||
465 | VersionedCovMapFuncRecordReader( | |||
466 | InstrProfSymtab &P, | |||
467 | std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, | |||
468 | std::vector<StringRef> &F) | |||
469 | : ProfileNames(P), Filenames(F), Records(R) {} | |||
470 | ||||
471 | ~VersionedCovMapFuncRecordReader() override = default; | |||
472 | ||||
473 | Expected<const char *> readFunctionRecords(const char *Buf, | |||
474 | const char *End) override { | |||
475 | using namespace support; | |||
476 | ||||
477 | if (Buf + sizeof(CovMapHeader) > End) | |||
478 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
479 | auto CovHeader = reinterpret_cast<const CovMapHeader *>(Buf); | |||
480 | uint32_t NRecords = CovHeader->getNRecords<Endian>(); | |||
481 | uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>(); | |||
482 | uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>(); | |||
483 | assert((CovMapVersion)CovHeader->getVersion<Endian>() == Version)(((CovMapVersion)CovHeader->getVersion<Endian>() == Version ) ? static_cast<void> (0) : __assert_fail ("(CovMapVersion)CovHeader->getVersion<Endian>() == Version" , "/build/llvm-toolchain-snapshot-9~svn362543/lib/ProfileData/Coverage/CoverageMappingReader.cpp" , 483, __PRETTY_FUNCTION__)); | |||
484 | Buf = reinterpret_cast<const char *>(CovHeader + 1); | |||
485 | ||||
486 | // Skip past the function records, saving the start and end for later. | |||
487 | const char *FunBuf = Buf; | |||
488 | Buf += NRecords * sizeof(FuncRecordType); | |||
489 | const char *FunEnd = Buf; | |||
490 | ||||
491 | // Get the filenames. | |||
492 | if (Buf + FilenamesSize > End) | |||
493 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
494 | size_t FilenamesBegin = Filenames.size(); | |||
495 | RawCoverageFilenamesReader Reader(StringRef(Buf, FilenamesSize), Filenames); | |||
496 | if (auto Err = Reader.read()) | |||
497 | return std::move(Err); | |||
498 | Buf += FilenamesSize; | |||
499 | ||||
500 | // We'll read the coverage mapping records in the loop below. | |||
501 | const char *CovBuf = Buf; | |||
502 | Buf += CoverageSize; | |||
503 | const char *CovEnd = Buf; | |||
504 | ||||
505 | if (Buf > End) | |||
506 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
507 | // Each coverage map has an alignment of 8, so we need to adjust alignment | |||
508 | // before reading the next map. | |||
509 | Buf += alignmentAdjustment(Buf, 8); | |||
510 | ||||
511 | auto CFR = reinterpret_cast<const FuncRecordType *>(FunBuf); | |||
512 | while ((const char *)CFR < FunEnd) { | |||
513 | // Read the function information | |||
514 | uint32_t DataSize = CFR->template getDataSize<Endian>(); | |||
515 | ||||
516 | // Now use that to read the coverage data. | |||
517 | if (CovBuf + DataSize > CovEnd) | |||
518 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
519 | auto Mapping = StringRef(CovBuf, DataSize); | |||
520 | CovBuf += DataSize; | |||
521 | ||||
522 | if (Error Err = | |||
523 | insertFunctionRecordIfNeeded(CFR, Mapping, FilenamesBegin)) | |||
524 | return std::move(Err); | |||
525 | CFR++; | |||
526 | } | |||
527 | return Buf; | |||
528 | } | |||
529 | }; | |||
530 | ||||
531 | } // end anonymous namespace | |||
532 | ||||
533 | template <class IntPtrT, support::endianness Endian> | |||
534 | Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get( | |||
535 | CovMapVersion Version, InstrProfSymtab &P, | |||
536 | std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, | |||
537 | std::vector<StringRef> &F) { | |||
538 | using namespace coverage; | |||
539 | ||||
540 | switch (Version) { | |||
541 | case CovMapVersion::Version1: | |||
542 | return llvm::make_unique<VersionedCovMapFuncRecordReader< | |||
543 | CovMapVersion::Version1, IntPtrT, Endian>>(P, R, F); | |||
544 | case CovMapVersion::Version2: | |||
545 | case CovMapVersion::Version3: | |||
546 | // Decompress the name data. | |||
547 | if (Error E = P.create(P.getNameData())) | |||
548 | return std::move(E); | |||
549 | if (Version == CovMapVersion::Version2) | |||
550 | return llvm::make_unique<VersionedCovMapFuncRecordReader< | |||
551 | CovMapVersion::Version2, IntPtrT, Endian>>(P, R, F); | |||
552 | else | |||
553 | return llvm::make_unique<VersionedCovMapFuncRecordReader< | |||
554 | CovMapVersion::Version3, IntPtrT, Endian>>(P, R, F); | |||
555 | } | |||
556 | llvm_unreachable("Unsupported version")::llvm::llvm_unreachable_internal("Unsupported version", "/build/llvm-toolchain-snapshot-9~svn362543/lib/ProfileData/Coverage/CoverageMappingReader.cpp" , 556); | |||
557 | } | |||
558 | ||||
559 | template <typename T, support::endianness Endian> | |||
560 | static Error readCoverageMappingData( | |||
561 | InstrProfSymtab &ProfileNames, StringRef Data, | |||
562 | std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records, | |||
563 | std::vector<StringRef> &Filenames) { | |||
564 | using namespace coverage; | |||
565 | ||||
566 | // Read the records in the coverage data section. | |||
567 | auto CovHeader = | |||
568 | reinterpret_cast<const CovMapHeader *>(Data.data()); | |||
569 | CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>(); | |||
570 | if (Version > CovMapVersion::CurrentVersion) | |||
571 | return make_error<CoverageMapError>(coveragemap_error::unsupported_version); | |||
572 | Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected = | |||
573 | CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records, | |||
574 | Filenames); | |||
575 | if (Error E = ReaderExpected.takeError()) | |||
576 | return E; | |||
577 | auto Reader = std::move(ReaderExpected.get()); | |||
578 | for (const char *Buf = Data.data(), *End = Buf + Data.size(); Buf < End;) { | |||
579 | auto NextHeaderOrErr = Reader->readFunctionRecords(Buf, End); | |||
580 | if (auto E = NextHeaderOrErr.takeError()) | |||
581 | return E; | |||
582 | Buf = NextHeaderOrErr.get(); | |||
583 | } | |||
584 | return Error::success(); | |||
585 | } | |||
586 | ||||
587 | static const char *TestingFormatMagic = "llvmcovmtestdata"; | |||
588 | ||||
589 | static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, | |||
590 | StringRef &CoverageMapping, | |||
591 | uint8_t &BytesInAddress, | |||
592 | support::endianness &Endian) { | |||
593 | BytesInAddress = 8; | |||
594 | Endian = support::endianness::little; | |||
595 | ||||
596 | Data = Data.substr(StringRef(TestingFormatMagic).size()); | |||
597 | if (Data.empty()) | |||
598 | return make_error<CoverageMapError>(coveragemap_error::truncated); | |||
599 | unsigned N = 0; | |||
600 | uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N); | |||
601 | if (N > Data.size()) | |||
602 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
603 | Data = Data.substr(N); | |||
604 | if (Data.empty()) | |||
605 | return make_error<CoverageMapError>(coveragemap_error::truncated); | |||
606 | N = 0; | |||
607 | uint64_t Address = decodeULEB128(Data.bytes_begin(), &N); | |||
608 | if (N > Data.size()) | |||
609 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
610 | Data = Data.substr(N); | |||
611 | if (Data.size() < ProfileNamesSize) | |||
612 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
613 | if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address)) | |||
614 | return E; | |||
615 | CoverageMapping = Data.substr(ProfileNamesSize); | |||
616 | // Skip the padding bytes because coverage map data has an alignment of 8. | |||
617 | if (CoverageMapping.empty()) | |||
618 | return make_error<CoverageMapError>(coveragemap_error::truncated); | |||
619 | size_t Pad = alignmentAdjustment(CoverageMapping.data(), 8); | |||
620 | if (CoverageMapping.size() < Pad) | |||
621 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
622 | CoverageMapping = CoverageMapping.substr(Pad); | |||
623 | return Error::success(); | |||
624 | } | |||
625 | ||||
626 | static Expected<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) { | |||
627 | // On COFF, the object file section name may end in "$M". This tells the | |||
628 | // linker to sort these sections between "$A" and "$Z". The linker removes the | |||
629 | // dollar and everything after it in the final binary. Do the same to match. | |||
630 | bool IsCOFF = isa<COFFObjectFile>(OF); | |||
631 | auto stripSuffix = [IsCOFF](StringRef N) { | |||
632 | return IsCOFF ? N.split('$').first : N; | |||
633 | }; | |||
634 | Name = stripSuffix(Name); | |||
635 | ||||
636 | StringRef FoundName; | |||
637 | for (const auto &Section : OF.sections()) { | |||
638 | if (auto EC = Section.getName(FoundName)) | |||
639 | return errorCodeToError(EC); | |||
640 | if (stripSuffix(FoundName) == Name) | |||
641 | return Section; | |||
642 | } | |||
643 | return make_error<CoverageMapError>(coveragemap_error::no_data_found); | |||
644 | } | |||
645 | ||||
646 | static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, | |||
647 | InstrProfSymtab &ProfileNames, | |||
648 | StringRef &CoverageMapping, | |||
649 | uint8_t &BytesInAddress, | |||
650 | support::endianness &Endian, StringRef Arch) { | |||
651 | auto BinOrErr = createBinary(ObjectBuffer); | |||
652 | if (!BinOrErr) | |||
653 | return BinOrErr.takeError(); | |||
654 | auto Bin = std::move(BinOrErr.get()); | |||
655 | std::unique_ptr<ObjectFile> OF; | |||
656 | if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { | |||
657 | // If we have a universal binary, try to look up the object for the | |||
658 | // appropriate architecture. | |||
659 | auto ObjectFileOrErr = Universal->getObjectForArch(Arch); | |||
660 | if (!ObjectFileOrErr) | |||
661 | return ObjectFileOrErr.takeError(); | |||
662 | OF = std::move(ObjectFileOrErr.get()); | |||
663 | } else if (isa<ObjectFile>(Bin.get())) { | |||
664 | // For any other object file, upcast and take ownership. | |||
665 | OF.reset(cast<ObjectFile>(Bin.release())); | |||
666 | // If we've asked for a particular arch, make sure they match. | |||
667 | if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) | |||
668 | return errorCodeToError(object_error::arch_not_found); | |||
669 | } else | |||
670 | // We can only handle object files. | |||
671 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
672 | ||||
673 | // The coverage uses native pointer sizes for the object it's written in. | |||
674 | BytesInAddress = OF->getBytesInAddress(); | |||
675 | Endian = OF->isLittleEndian() ? support::endianness::little | |||
676 | : support::endianness::big; | |||
677 | ||||
678 | // Look for the sections that we are interested in. | |||
679 | auto ObjFormat = OF->getTripleObjectFormat(); | |||
680 | auto NamesSection = | |||
681 | lookupSection(*OF, getInstrProfSectionName(IPSK_name, ObjFormat, | |||
682 | /*AddSegmentInfo=*/false)); | |||
683 | if (auto E = NamesSection.takeError()) | |||
684 | return E; | |||
685 | auto CoverageSection = | |||
686 | lookupSection(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat, | |||
687 | /*AddSegmentInfo=*/false)); | |||
688 | if (auto E = CoverageSection.takeError()) | |||
689 | return E; | |||
690 | ||||
691 | // Get the contents of the given sections. | |||
692 | if (Expected<StringRef> E = CoverageSection->getContents()) | |||
693 | CoverageMapping = *E; | |||
694 | else | |||
695 | return E.takeError(); | |||
696 | ||||
697 | if (Error E = ProfileNames.create(*NamesSection)) | |||
698 | return E; | |||
699 | ||||
700 | return Error::success(); | |||
701 | } | |||
702 | ||||
703 | Expected<std::unique_ptr<BinaryCoverageReader>> | |||
704 | BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer, | |||
705 | StringRef Arch) { | |||
706 | std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader()); | |||
707 | ||||
708 | StringRef Coverage; | |||
709 | uint8_t BytesInAddress; | |||
| ||||
710 | support::endianness Endian; | |||
711 | Error E = Error::success(); | |||
712 | consumeError(std::move(E)); | |||
713 | if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) | |||
714 | // This is a special format used for testing. | |||
715 | E = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames, | |||
716 | Coverage, BytesInAddress, Endian); | |||
717 | else | |||
718 | E = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames, | |||
719 | Coverage, BytesInAddress, Endian, Arch); | |||
720 | if (E) | |||
721 | return std::move(E); | |||
722 | ||||
723 | if (BytesInAddress == 4 && Endian == support::endianness::little) | |||
| ||||
724 | E = readCoverageMappingData<uint32_t, support::endianness::little>( | |||
725 | Reader->ProfileNames, Coverage, Reader->MappingRecords, | |||
726 | Reader->Filenames); | |||
727 | else if (BytesInAddress == 4 && Endian == support::endianness::big) | |||
728 | E = readCoverageMappingData<uint32_t, support::endianness::big>( | |||
729 | Reader->ProfileNames, Coverage, Reader->MappingRecords, | |||
730 | Reader->Filenames); | |||
731 | else if (BytesInAddress == 8 && Endian == support::endianness::little) | |||
732 | E = readCoverageMappingData<uint64_t, support::endianness::little>( | |||
733 | Reader->ProfileNames, Coverage, Reader->MappingRecords, | |||
734 | Reader->Filenames); | |||
735 | else if (BytesInAddress == 8 && Endian == support::endianness::big) | |||
736 | E = readCoverageMappingData<uint64_t, support::endianness::big>( | |||
737 | Reader->ProfileNames, Coverage, Reader->MappingRecords, | |||
738 | Reader->Filenames); | |||
739 | else | |||
740 | return make_error<CoverageMapError>(coveragemap_error::malformed); | |||
741 | if (E) | |||
742 | return std::move(E); | |||
743 | return std::move(Reader); | |||
744 | } | |||
745 | ||||
746 | Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { | |||
747 | if (CurrentRecord >= MappingRecords.size()) | |||
748 | return make_error<CoverageMapError>(coveragemap_error::eof); | |||
749 | ||||
750 | FunctionsFilenames.clear(); | |||
751 | Expressions.clear(); | |||
752 | MappingRegions.clear(); | |||
753 | auto &R = MappingRecords[CurrentRecord]; | |||
754 | RawCoverageMappingReader Reader( | |||
755 | R.CoverageMapping, | |||
756 | makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize), | |||
757 | FunctionsFilenames, Expressions, MappingRegions); | |||
758 | if (auto Err = Reader.read()) | |||
759 | return Err; | |||
760 | ||||
761 | Record.FunctionName = R.FunctionName; | |||
762 | Record.FunctionHash = R.FunctionHash; | |||
763 | Record.Filenames = FunctionsFilenames; | |||
764 | Record.Expressions = Expressions; | |||
765 | Record.MappingRegions = MappingRegions; | |||
766 | ||||
767 | ++CurrentRecord; | |||
768 | return Error::success(); | |||
769 | } |