]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | //===- GCOV.cpp - LLVM coverage tool --------------------------------------===// |
223e47cc LB |
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 | // | |
1a4d82fc | 10 | // GCOV implements the interface to read and write coverage files that use |
223e47cc LB |
11 | // 'gcov' format. |
12 | // | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
15 | #include "llvm/Support/GCOV.h" | |
223e47cc | 16 | #include "llvm/ADT/STLExtras.h" |
1a4d82fc JJ |
17 | #include "llvm/Support/Debug.h" |
18 | #include "llvm/Support/FileSystem.h" | |
19 | #include "llvm/Support/Format.h" | |
223e47cc | 20 | #include "llvm/Support/MemoryObject.h" |
1a4d82fc JJ |
21 | #include "llvm/Support/Path.h" |
22 | #include <algorithm> | |
23 | #include <system_error> | |
223e47cc LB |
24 | using namespace llvm; |
25 | ||
26 | //===----------------------------------------------------------------------===// | |
27 | // GCOVFile implementation. | |
28 | ||
1a4d82fc JJ |
29 | /// readGCNO - Read GCNO buffer. |
30 | bool GCOVFile::readGCNO(GCOVBuffer &Buffer) { | |
31 | if (!Buffer.readGCNOFormat()) return false; | |
32 | if (!Buffer.readGCOVVersion(Version)) return false; | |
33 | ||
34 | if (!Buffer.readInt(Checksum)) return false; | |
35 | while (true) { | |
36 | if (!Buffer.readFunctionTag()) break; | |
37 | auto GFun = make_unique<GCOVFunction>(*this); | |
38 | if (!GFun->readGCNO(Buffer, Version)) | |
39 | return false; | |
40 | Functions.push_back(std::move(GFun)); | |
41 | } | |
223e47cc | 42 | |
1a4d82fc JJ |
43 | GCNOInitialized = true; |
44 | return true; | |
223e47cc LB |
45 | } |
46 | ||
1a4d82fc JJ |
47 | /// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be |
48 | /// called after readGCNO(). | |
49 | bool GCOVFile::readGCDA(GCOVBuffer &Buffer) { | |
50 | assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()"); | |
51 | if (!Buffer.readGCDAFormat()) return false; | |
52 | GCOV::GCOVVersion GCDAVersion; | |
53 | if (!Buffer.readGCOVVersion(GCDAVersion)) return false; | |
54 | if (Version != GCDAVersion) { | |
55 | errs() << "GCOV versions do not match.\n"; | |
223e47cc | 56 | return false; |
1a4d82fc | 57 | } |
223e47cc | 58 | |
1a4d82fc JJ |
59 | uint32_t GCDAChecksum; |
60 | if (!Buffer.readInt(GCDAChecksum)) return false; | |
61 | if (Checksum != GCDAChecksum) { | |
62 | errs() << "File checksums do not match: " << Checksum << " != " | |
63 | << GCDAChecksum << ".\n"; | |
64 | return false; | |
65 | } | |
66 | for (size_t i = 0, e = Functions.size(); i < e; ++i) { | |
67 | if (!Buffer.readFunctionTag()) { | |
68 | errs() << "Unexpected number of functions.\n"; | |
69 | return false; | |
223e47cc | 70 | } |
1a4d82fc JJ |
71 | if (!Functions[i]->readGCDA(Buffer, Version)) |
72 | return false; | |
73 | } | |
74 | if (Buffer.readObjectTag()) { | |
75 | uint32_t Length; | |
76 | uint32_t Dummy; | |
77 | if (!Buffer.readInt(Length)) return false; | |
78 | if (!Buffer.readInt(Dummy)) return false; // checksum | |
79 | if (!Buffer.readInt(Dummy)) return false; // num | |
80 | if (!Buffer.readInt(RunCount)) return false; | |
81 | Buffer.advanceCursor(Length-3); | |
82 | } | |
83 | while (Buffer.readProgramTag()) { | |
84 | uint32_t Length; | |
85 | if (!Buffer.readInt(Length)) return false; | |
86 | Buffer.advanceCursor(Length); | |
87 | ++ProgramCount; | |
223e47cc | 88 | } |
1a4d82fc | 89 | |
223e47cc LB |
90 | return true; |
91 | } | |
92 | ||
1a4d82fc JJ |
93 | /// dump - Dump GCOVFile content to dbgs() for debugging purposes. |
94 | void GCOVFile::dump() const { | |
95 | for (const auto &FPtr : Functions) | |
96 | FPtr->dump(); | |
223e47cc LB |
97 | } |
98 | ||
99 | /// collectLineCounts - Collect line counts. This must be used after | |
100 | /// reading .gcno and .gcda files. | |
101 | void GCOVFile::collectLineCounts(FileInfo &FI) { | |
1a4d82fc JJ |
102 | for (const auto &FPtr : Functions) |
103 | FPtr->collectLineCounts(FI); | |
104 | FI.setRunCount(RunCount); | |
105 | FI.setProgramCount(ProgramCount); | |
223e47cc LB |
106 | } |
107 | ||
108 | //===----------------------------------------------------------------------===// | |
109 | // GCOVFunction implementation. | |
110 | ||
1a4d82fc JJ |
111 | /// readGCNO - Read a function from the GCNO buffer. Return false if an error |
112 | /// occurs. | |
113 | bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { | |
114 | uint32_t Dummy; | |
115 | if (!Buff.readInt(Dummy)) return false; // Function header length | |
116 | if (!Buff.readInt(Ident)) return false; | |
117 | if (!Buff.readInt(Checksum)) return false; | |
118 | if (Version != GCOV::V402) { | |
119 | uint32_t CfgChecksum; | |
120 | if (!Buff.readInt(CfgChecksum)) return false; | |
121 | if (Parent.getChecksum() != CfgChecksum) { | |
122 | errs() << "File checksums do not match: " << Parent.getChecksum() | |
123 | << " != " << CfgChecksum << " in (" << Name << ").\n"; | |
124 | return false; | |
223e47cc | 125 | } |
223e47cc | 126 | } |
1a4d82fc JJ |
127 | if (!Buff.readString(Name)) return false; |
128 | if (!Buff.readString(Filename)) return false; | |
129 | if (!Buff.readInt(LineNumber)) return false; | |
223e47cc LB |
130 | |
131 | // read blocks. | |
1a4d82fc JJ |
132 | if (!Buff.readBlockTag()) { |
133 | errs() << "Block tag not found.\n"; | |
134 | return false; | |
135 | } | |
136 | uint32_t BlockCount; | |
137 | if (!Buff.readInt(BlockCount)) return false; | |
138 | for (uint32_t i = 0, e = BlockCount; i != e; ++i) { | |
139 | if (!Buff.readInt(Dummy)) return false; // Block flags; | |
140 | Blocks.push_back(make_unique<GCOVBlock>(*this, i)); | |
223e47cc LB |
141 | } |
142 | ||
143 | // read edges. | |
144 | while (Buff.readEdgeTag()) { | |
1a4d82fc JJ |
145 | uint32_t EdgeCount; |
146 | if (!Buff.readInt(EdgeCount)) return false; | |
147 | EdgeCount = (EdgeCount - 1) / 2; | |
148 | uint32_t BlockNo; | |
149 | if (!Buff.readInt(BlockNo)) return false; | |
150 | if (BlockNo >= BlockCount) { | |
151 | errs() << "Unexpected block number: " << BlockNo << " (in " << Name | |
152 | << ").\n"; | |
153 | return false; | |
154 | } | |
155 | for (uint32_t i = 0, e = EdgeCount; i != e; ++i) { | |
156 | uint32_t Dst; | |
157 | if (!Buff.readInt(Dst)) return false; | |
158 | Edges.push_back(make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst])); | |
159 | GCOVEdge *Edge = Edges.back().get(); | |
160 | Blocks[BlockNo]->addDstEdge(Edge); | |
161 | Blocks[Dst]->addSrcEdge(Edge); | |
162 | if (!Buff.readInt(Dummy)) return false; // Edge flag | |
223e47cc LB |
163 | } |
164 | } | |
165 | ||
166 | // read line table. | |
167 | while (Buff.readLineTag()) { | |
1a4d82fc JJ |
168 | uint32_t LineTableLength; |
169 | // Read the length of this line table. | |
170 | if (!Buff.readInt(LineTableLength)) return false; | |
171 | uint32_t EndPos = Buff.getCursor() + LineTableLength*4; | |
172 | uint32_t BlockNo; | |
173 | // Read the block number this table is associated with. | |
174 | if (!Buff.readInt(BlockNo)) return false; | |
175 | if (BlockNo >= BlockCount) { | |
176 | errs() << "Unexpected block number: " << BlockNo << " (in " << Name | |
177 | << ").\n"; | |
178 | return false; | |
179 | } | |
180 | GCOVBlock &Block = *Blocks[BlockNo]; | |
181 | // Read the word that pads the beginning of the line table. This may be a | |
182 | // flag of some sort, but seems to always be zero. | |
183 | if (!Buff.readInt(Dummy)) return false; | |
184 | ||
185 | // Line information starts here and continues up until the last word. | |
186 | if (Buff.getCursor() != (EndPos - sizeof(uint32_t))) { | |
187 | StringRef F; | |
188 | // Read the source file name. | |
189 | if (!Buff.readString(F)) return false; | |
190 | if (Filename != F) { | |
191 | errs() << "Multiple sources for a single basic block: " << Filename | |
192 | << " != " << F << " (in " << Name << ").\n"; | |
193 | return false; | |
194 | } | |
195 | // Read lines up to, but not including, the null terminator. | |
196 | while (Buff.getCursor() < (EndPos - 2 * sizeof(uint32_t))) { | |
197 | uint32_t Line; | |
198 | if (!Buff.readInt(Line)) return false; | |
199 | // Line 0 means this instruction was injected by the compiler. Skip it. | |
200 | if (!Line) continue; | |
201 | Block.addLine(Line); | |
202 | } | |
203 | // Read the null terminator. | |
204 | if (!Buff.readInt(Dummy)) return false; | |
205 | } | |
206 | // The last word is either a flag or padding, it isn't clear which. Skip | |
207 | // over it. | |
208 | if (!Buff.readInt(Dummy)) return false; | |
209 | } | |
210 | return true; | |
211 | } | |
212 | ||
213 | /// readGCDA - Read a function from the GCDA buffer. Return false if an error | |
214 | /// occurs. | |
215 | bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { | |
216 | uint32_t Dummy; | |
217 | if (!Buff.readInt(Dummy)) return false; // Function header length | |
218 | ||
219 | uint32_t GCDAIdent; | |
220 | if (!Buff.readInt(GCDAIdent)) return false; | |
221 | if (Ident != GCDAIdent) { | |
222 | errs() << "Function identifiers do not match: " << Ident << " != " | |
223 | << GCDAIdent << " (in " << Name << ").\n"; | |
224 | return false; | |
225 | } | |
226 | ||
227 | uint32_t GCDAChecksum; | |
228 | if (!Buff.readInt(GCDAChecksum)) return false; | |
229 | if (Checksum != GCDAChecksum) { | |
230 | errs() << "Function checksums do not match: " << Checksum << " != " | |
231 | << GCDAChecksum << " (in " << Name << ").\n"; | |
232 | return false; | |
233 | } | |
234 | ||
235 | uint32_t CfgChecksum; | |
236 | if (Version != GCOV::V402) { | |
237 | if (!Buff.readInt(CfgChecksum)) return false; | |
238 | if (Parent.getChecksum() != CfgChecksum) { | |
239 | errs() << "File checksums do not match: " << Parent.getChecksum() | |
240 | << " != " << CfgChecksum << " (in " << Name << ").\n"; | |
241 | return false; | |
242 | } | |
243 | } | |
244 | ||
245 | StringRef GCDAName; | |
246 | if (!Buff.readString(GCDAName)) return false; | |
247 | if (Name != GCDAName) { | |
248 | errs() << "Function names do not match: " << Name << " != " << GCDAName | |
249 | << ".\n"; | |
250 | return false; | |
251 | } | |
252 | ||
253 | if (!Buff.readArcTag()) { | |
254 | errs() << "Arc tag not found (in " << Name << ").\n"; | |
255 | return false; | |
256 | } | |
257 | ||
258 | uint32_t Count; | |
259 | if (!Buff.readInt(Count)) return false; | |
260 | Count /= 2; | |
261 | ||
262 | // This for loop adds the counts for each block. A second nested loop is | |
263 | // required to combine the edge counts that are contained in the GCDA file. | |
264 | for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) { | |
265 | // The last block is always reserved for exit block | |
266 | if (BlockNo >= Blocks.size()-1) { | |
267 | errs() << "Unexpected number of edges (in " << Name << ").\n"; | |
268 | return false; | |
269 | } | |
270 | GCOVBlock &Block = *Blocks[BlockNo]; | |
271 | for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End; | |
272 | ++EdgeNo) { | |
273 | if (Count == 0) { | |
274 | errs() << "Unexpected number of edges (in " << Name << ").\n"; | |
275 | return false; | |
276 | } | |
277 | uint64_t ArcCount; | |
278 | if (!Buff.readInt64(ArcCount)) return false; | |
279 | Block.addCount(EdgeNo, ArcCount); | |
280 | --Count; | |
223e47cc | 281 | } |
1a4d82fc | 282 | Block.sortDstEdges(); |
223e47cc LB |
283 | } |
284 | return true; | |
285 | } | |
286 | ||
1a4d82fc JJ |
287 | /// getEntryCount - Get the number of times the function was called by |
288 | /// retrieving the entry block's count. | |
289 | uint64_t GCOVFunction::getEntryCount() const { | |
290 | return Blocks.front()->getCount(); | |
291 | } | |
292 | ||
293 | /// getExitCount - Get the number of times the function returned by retrieving | |
294 | /// the exit block's count. | |
295 | uint64_t GCOVFunction::getExitCount() const { | |
296 | return Blocks.back()->getCount(); | |
297 | } | |
298 | ||
299 | /// dump - Dump GCOVFunction content to dbgs() for debugging purposes. | |
300 | void GCOVFunction::dump() const { | |
85aaf69f SL |
301 | dbgs() << "===== " << Name << " (" << Ident << ") @ " << Filename << ":" |
302 | << LineNumber << "\n"; | |
1a4d82fc JJ |
303 | for (const auto &Block : Blocks) |
304 | Block->dump(); | |
223e47cc LB |
305 | } |
306 | ||
307 | /// collectLineCounts - Collect line counts. This must be used after | |
308 | /// reading .gcno and .gcda files. | |
309 | void GCOVFunction::collectLineCounts(FileInfo &FI) { | |
1a4d82fc JJ |
310 | // If the line number is zero, this is a function that doesn't actually appear |
311 | // in the source file, so there isn't anything we can do with it. | |
312 | if (LineNumber == 0) | |
313 | return; | |
314 | ||
315 | for (const auto &Block : Blocks) | |
316 | Block->collectLineCounts(FI); | |
317 | FI.addFunctionLine(Filename, LineNumber, this); | |
223e47cc LB |
318 | } |
319 | ||
320 | //===----------------------------------------------------------------------===// | |
321 | // GCOVBlock implementation. | |
322 | ||
323 | /// ~GCOVBlock - Delete GCOVBlock and its content. | |
324 | GCOVBlock::~GCOVBlock() { | |
1a4d82fc JJ |
325 | SrcEdges.clear(); |
326 | DstEdges.clear(); | |
327 | Lines.clear(); | |
328 | } | |
329 | ||
330 | /// addCount - Add to block counter while storing the edge count. If the | |
331 | /// destination has no outgoing edges, also update that block's count too. | |
332 | void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) { | |
333 | assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid | |
334 | DstEdges[DstEdgeNo]->Count = N; | |
335 | Counter += N; | |
336 | if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges()) | |
337 | DstEdges[DstEdgeNo]->Dst.Counter += N; | |
223e47cc LB |
338 | } |
339 | ||
1a4d82fc JJ |
340 | /// sortDstEdges - Sort destination edges by block number, nop if already |
341 | /// sorted. This is required for printing branch info in the correct order. | |
342 | void GCOVBlock::sortDstEdges() { | |
343 | if (!DstEdgesAreSorted) { | |
344 | SortDstEdgesFunctor SortEdges; | |
345 | std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges); | |
346 | } | |
223e47cc LB |
347 | } |
348 | ||
349 | /// collectLineCounts - Collect line counts. This must be used after | |
350 | /// reading .gcno and .gcda files. | |
351 | void GCOVBlock::collectLineCounts(FileInfo &FI) { | |
1a4d82fc | 352 | for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), |
223e47cc | 353 | E = Lines.end(); I != E; ++I) |
1a4d82fc | 354 | FI.addBlockLine(Parent.getFilename(), *I, this); |
223e47cc LB |
355 | } |
356 | ||
1a4d82fc JJ |
357 | /// dump - Dump GCOVBlock content to dbgs() for debugging purposes. |
358 | void GCOVBlock::dump() const { | |
359 | dbgs() << "Block : " << Number << " Counter : " << Counter << "\n"; | |
360 | if (!SrcEdges.empty()) { | |
361 | dbgs() << "\tSource Edges : "; | |
362 | for (EdgeIterator I = SrcEdges.begin(), E = SrcEdges.end(); I != E; ++I) { | |
363 | const GCOVEdge *Edge = *I; | |
364 | dbgs() << Edge->Src.Number << " (" << Edge->Count << "), "; | |
365 | } | |
366 | dbgs() << "\n"; | |
223e47cc | 367 | } |
1a4d82fc JJ |
368 | if (!DstEdges.empty()) { |
369 | dbgs() << "\tDestination Edges : "; | |
370 | for (EdgeIterator I = DstEdges.begin(), E = DstEdges.end(); I != E; ++I) { | |
371 | const GCOVEdge *Edge = *I; | |
372 | dbgs() << Edge->Dst.Number << " (" << Edge->Count << "), "; | |
223e47cc | 373 | } |
1a4d82fc JJ |
374 | dbgs() << "\n"; |
375 | } | |
376 | if (!Lines.empty()) { | |
377 | dbgs() << "\tLines : "; | |
378 | for (SmallVectorImpl<uint32_t>::const_iterator I = Lines.begin(), | |
379 | E = Lines.end(); I != E; ++I) | |
380 | dbgs() << (*I) << ","; | |
381 | dbgs() << "\n"; | |
223e47cc LB |
382 | } |
383 | } | |
384 | ||
385 | //===----------------------------------------------------------------------===// | |
1a4d82fc | 386 | // FileInfo implementation. |
223e47cc | 387 | |
1a4d82fc JJ |
388 | // Safe integer division, returns 0 if numerator is 0. |
389 | static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) { | |
390 | if (!Numerator) | |
391 | return 0; | |
392 | return Numerator/Divisor; | |
223e47cc LB |
393 | } |
394 | ||
1a4d82fc JJ |
395 | // This custom division function mimics gcov's branch ouputs: |
396 | // - Round to closest whole number | |
397 | // - Only output 0% or 100% if it's exactly that value | |
398 | static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) { | |
399 | if (!Numerator) | |
400 | return 0; | |
401 | if (Numerator == Divisor) | |
402 | return 100; | |
403 | ||
404 | uint8_t Res = (Numerator*100+Divisor/2) / Divisor; | |
405 | if (Res == 0) | |
406 | return 1; | |
407 | if (Res == 100) | |
408 | return 99; | |
409 | return Res; | |
223e47cc LB |
410 | } |
411 | ||
1a4d82fc JJ |
412 | struct formatBranchInfo { |
413 | formatBranchInfo(const GCOVOptions &Options, uint64_t Count, | |
414 | uint64_t Total) : | |
415 | Options(Options), Count(Count), Total(Total) {} | |
416 | ||
417 | void print(raw_ostream &OS) const { | |
418 | if (!Total) | |
419 | OS << "never executed"; | |
420 | else if (Options.BranchCount) | |
421 | OS << "taken " << Count; | |
422 | else | |
423 | OS << "taken " << branchDiv(Count, Total) << "%"; | |
424 | } | |
425 | ||
426 | const GCOVOptions &Options; | |
427 | uint64_t Count; | |
428 | uint64_t Total; | |
429 | }; | |
430 | ||
431 | static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) { | |
432 | FBI.print(OS); | |
433 | return OS; | |
434 | } | |
223e47cc | 435 | |
1a4d82fc JJ |
436 | namespace { |
437 | class LineConsumer { | |
438 | std::unique_ptr<MemoryBuffer> Buffer; | |
439 | StringRef Remaining; | |
440 | public: | |
441 | LineConsumer(StringRef Filename) { | |
442 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = | |
443 | MemoryBuffer::getFileOrSTDIN(Filename); | |
444 | if (std::error_code EC = BufferOrErr.getError()) { | |
445 | errs() << Filename << ": " << EC.message() << "\n"; | |
446 | Remaining = ""; | |
447 | } else { | |
448 | Buffer = std::move(BufferOrErr.get()); | |
449 | Remaining = Buffer->getBuffer(); | |
223e47cc | 450 | } |
223e47cc | 451 | } |
1a4d82fc JJ |
452 | bool empty() { return Remaining.empty(); } |
453 | void printNext(raw_ostream &OS, uint32_t LineNum) { | |
454 | StringRef Line; | |
455 | if (empty()) | |
456 | Line = "/*EOF*/"; | |
457 | else | |
458 | std::tie(Line, Remaining) = Remaining.split("\n"); | |
459 | OS << format("%5u:", LineNum) << Line << "\n"; | |
460 | } | |
461 | }; | |
462 | } | |
463 | ||
464 | /// Convert a path to a gcov filename. If PreservePaths is true, this | |
465 | /// translates "/" to "#", ".." to "^", and drops ".", to match gcov. | |
466 | static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) { | |
467 | if (!PreservePaths) | |
468 | return sys::path::filename(Filename).str(); | |
469 | ||
470 | // This behaviour is defined by gcov in terms of text replacements, so it's | |
471 | // not likely to do anything useful on filesystems with different textual | |
472 | // conventions. | |
473 | llvm::SmallString<256> Result(""); | |
474 | StringRef::iterator I, S, E; | |
475 | for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) { | |
476 | if (*I != '/') | |
477 | continue; | |
478 | ||
479 | if (I - S == 1 && *S == '.') { | |
480 | // ".", the current directory, is skipped. | |
481 | } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') { | |
482 | // "..", the parent directory, is replaced with "^". | |
483 | Result.append("^#"); | |
484 | } else { | |
485 | if (S < I) | |
486 | // Leave other components intact, | |
487 | Result.append(S, I); | |
488 | // And separate with "#". | |
489 | Result.push_back('#'); | |
490 | } | |
491 | S = I + 1; | |
492 | } | |
493 | ||
494 | if (S < I) | |
495 | Result.append(S, I); | |
496 | return Result.str(); | |
497 | } | |
498 | ||
499 | std::string FileInfo::getCoveragePath(StringRef Filename, | |
500 | StringRef MainFilename) { | |
501 | if (Options.NoOutput) | |
502 | // This is probably a bug in gcov, but when -n is specified, paths aren't | |
503 | // mangled at all, and the -l and -p options are ignored. Here, we do the | |
504 | // same. | |
505 | return Filename; | |
506 | ||
507 | std::string CoveragePath; | |
508 | if (Options.LongFileNames && !Filename.equals(MainFilename)) | |
509 | CoveragePath = | |
510 | mangleCoveragePath(MainFilename, Options.PreservePaths) + "##"; | |
511 | CoveragePath += | |
512 | mangleCoveragePath(Filename, Options.PreservePaths) + ".gcov"; | |
513 | return CoveragePath; | |
514 | } | |
515 | ||
516 | std::unique_ptr<raw_ostream> | |
517 | FileInfo::openCoveragePath(StringRef CoveragePath) { | |
518 | if (Options.NoOutput) | |
519 | return llvm::make_unique<raw_null_ostream>(); | |
520 | ||
521 | std::error_code EC; | |
522 | auto OS = llvm::make_unique<raw_fd_ostream>(CoveragePath.str(), EC, | |
523 | sys::fs::F_Text); | |
524 | if (EC) { | |
525 | errs() << EC.message() << "\n"; | |
526 | return llvm::make_unique<raw_null_ostream>(); | |
527 | } | |
528 | return std::move(OS); | |
223e47cc LB |
529 | } |
530 | ||
531 | /// print - Print source files with collected line count information. | |
1a4d82fc JJ |
532 | void FileInfo::print(StringRef MainFilename, StringRef GCNOFile, |
533 | StringRef GCDAFile) { | |
534 | for (StringMap<LineData>::const_iterator I = LineInfo.begin(), | |
535 | E = LineInfo.end(); I != E; ++I) { | |
223e47cc | 536 | StringRef Filename = I->first(); |
1a4d82fc JJ |
537 | auto AllLines = LineConsumer(Filename); |
538 | ||
539 | std::string CoveragePath = getCoveragePath(Filename, MainFilename); | |
540 | std::unique_ptr<raw_ostream> S = openCoveragePath(CoveragePath); | |
541 | raw_ostream &OS = *S; | |
542 | ||
543 | OS << " -: 0:Source:" << Filename << "\n"; | |
544 | OS << " -: 0:Graph:" << GCNOFile << "\n"; | |
545 | OS << " -: 0:Data:" << GCDAFile << "\n"; | |
546 | OS << " -: 0:Runs:" << RunCount << "\n"; | |
547 | OS << " -: 0:Programs:" << ProgramCount << "\n"; | |
548 | ||
549 | const LineData &Line = I->second; | |
550 | GCOVCoverage FileCoverage(Filename); | |
551 | for (uint32_t LineIndex = 0; | |
552 | LineIndex < Line.LastLine || !AllLines.empty(); ++LineIndex) { | |
553 | if (Options.BranchInfo) { | |
554 | FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex); | |
555 | if (FuncsIt != Line.Functions.end()) | |
556 | printFunctionSummary(OS, FuncsIt->second); | |
557 | } | |
558 | ||
559 | BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex); | |
560 | if (BlocksIt == Line.Blocks.end()) { | |
561 | // No basic blocks are on this line. Not an executable line of code. | |
562 | OS << " -:"; | |
563 | AllLines.printNext(OS, LineIndex + 1); | |
564 | } else { | |
565 | const BlockVector &Blocks = BlocksIt->second; | |
566 | ||
567 | // Add up the block counts to form line counts. | |
568 | DenseMap<const GCOVFunction *, bool> LineExecs; | |
569 | uint64_t LineCount = 0; | |
570 | for (BlockVector::const_iterator I = Blocks.begin(), E = Blocks.end(); | |
571 | I != E; ++I) { | |
572 | const GCOVBlock *Block = *I; | |
573 | if (Options.AllBlocks) { | |
574 | // Only take the highest block count for that line. | |
575 | uint64_t BlockCount = Block->getCount(); | |
576 | LineCount = LineCount > BlockCount ? LineCount : BlockCount; | |
577 | } else { | |
578 | // Sum up all of the block counts. | |
579 | LineCount += Block->getCount(); | |
580 | } | |
581 | ||
582 | if (Options.FuncCoverage) { | |
583 | // This is a slightly convoluted way to most accurately gather line | |
584 | // statistics for functions. Basically what is happening is that we | |
585 | // don't want to count a single line with multiple blocks more than | |
586 | // once. However, we also don't simply want to give the total line | |
587 | // count to every function that starts on the line. Thus, what is | |
588 | // happening here are two things: | |
589 | // 1) Ensure that the number of logical lines is only incremented | |
590 | // once per function. | |
591 | // 2) If there are multiple blocks on the same line, ensure that the | |
592 | // number of lines executed is incremented as long as at least | |
593 | // one of the blocks are executed. | |
594 | const GCOVFunction *Function = &Block->getParent(); | |
595 | if (FuncCoverages.find(Function) == FuncCoverages.end()) { | |
596 | std::pair<const GCOVFunction *, GCOVCoverage> | |
597 | KeyValue(Function, GCOVCoverage(Function->getName())); | |
598 | FuncCoverages.insert(KeyValue); | |
599 | } | |
600 | GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; | |
601 | ||
602 | if (LineExecs.find(Function) == LineExecs.end()) { | |
603 | if (Block->getCount()) { | |
604 | ++FuncCoverage.LinesExec; | |
605 | LineExecs[Function] = true; | |
606 | } else { | |
607 | LineExecs[Function] = false; | |
608 | } | |
609 | ++FuncCoverage.LogicalLines; | |
610 | } else if (!LineExecs[Function] && Block->getCount()) { | |
611 | ++FuncCoverage.LinesExec; | |
612 | LineExecs[Function] = true; | |
613 | } | |
614 | } | |
615 | } | |
616 | ||
617 | if (LineCount == 0) | |
618 | OS << " #####:"; | |
619 | else { | |
620 | OS << format("%9" PRIu64 ":", LineCount); | |
621 | ++FileCoverage.LinesExec; | |
622 | } | |
623 | ++FileCoverage.LogicalLines; | |
624 | ||
625 | AllLines.printNext(OS, LineIndex + 1); | |
626 | ||
627 | uint32_t BlockNo = 0; | |
628 | uint32_t EdgeNo = 0; | |
629 | for (BlockVector::const_iterator I = Blocks.begin(), E = Blocks.end(); | |
630 | I != E; ++I) { | |
631 | const GCOVBlock *Block = *I; | |
632 | ||
633 | // Only print block and branch information at the end of the block. | |
634 | if (Block->getLastLine() != LineIndex+1) | |
635 | continue; | |
636 | if (Options.AllBlocks) | |
637 | printBlockInfo(OS, *Block, LineIndex, BlockNo); | |
638 | if (Options.BranchInfo) { | |
639 | size_t NumEdges = Block->getNumDstEdges(); | |
640 | if (NumEdges > 1) | |
641 | printBranchInfo(OS, *Block, FileCoverage, EdgeNo); | |
642 | else if (Options.UncondBranch && NumEdges == 1) | |
643 | printUncondBranchInfo(OS, EdgeNo, (*Block->dst_begin())->Count); | |
644 | } | |
645 | } | |
646 | } | |
223e47cc | 647 | } |
1a4d82fc JJ |
648 | FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage)); |
649 | } | |
650 | ||
651 | // FIXME: There is no way to detect calls given current instrumentation. | |
652 | if (Options.FuncCoverage) | |
653 | printFuncCoverage(); | |
654 | printFileCoverage(); | |
655 | return; | |
656 | } | |
657 | ||
658 | /// printFunctionSummary - Print function and block summary. | |
659 | void FileInfo::printFunctionSummary(raw_ostream &OS, | |
660 | const FunctionVector &Funcs) const { | |
661 | for (FunctionVector::const_iterator I = Funcs.begin(), E = Funcs.end(); | |
662 | I != E; ++I) { | |
663 | const GCOVFunction *Func = *I; | |
664 | uint64_t EntryCount = Func->getEntryCount(); | |
665 | uint32_t BlocksExec = 0; | |
666 | for (GCOVFunction::BlockIterator I = Func->block_begin(), | |
667 | E = Func->block_end(); I != E; ++I) { | |
668 | const GCOVBlock &Block = **I; | |
669 | if (Block.getNumDstEdges() && Block.getCount()) | |
670 | ++BlocksExec; | |
223e47cc | 671 | } |
1a4d82fc JJ |
672 | |
673 | OS << "function " << Func->getName() << " called " << EntryCount | |
674 | << " returned " << safeDiv(Func->getExitCount()*100, EntryCount) | |
675 | << "% blocks executed " | |
676 | << safeDiv(BlocksExec*100, Func->getNumBlocks()-1) << "%\n"; | |
223e47cc LB |
677 | } |
678 | } | |
679 | ||
1a4d82fc JJ |
680 | /// printBlockInfo - Output counts for each block. |
681 | void FileInfo::printBlockInfo(raw_ostream &OS, const GCOVBlock &Block, | |
682 | uint32_t LineIndex, uint32_t &BlockNo) const { | |
683 | if (Block.getCount() == 0) | |
684 | OS << " $$$$$:"; | |
685 | else | |
686 | OS << format("%9" PRIu64 ":", Block.getCount()); | |
687 | OS << format("%5u-block %2u\n", LineIndex+1, BlockNo++); | |
688 | } | |
223e47cc | 689 | |
1a4d82fc JJ |
690 | /// printBranchInfo - Print conditional branch probabilities. |
691 | void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block, | |
692 | GCOVCoverage &Coverage, uint32_t &EdgeNo) { | |
693 | SmallVector<uint64_t, 16> BranchCounts; | |
694 | uint64_t TotalCounts = 0; | |
695 | for (GCOVBlock::EdgeIterator I = Block.dst_begin(), E = Block.dst_end(); | |
696 | I != E; ++I) { | |
697 | const GCOVEdge *Edge = *I; | |
698 | BranchCounts.push_back(Edge->Count); | |
699 | TotalCounts += Edge->Count; | |
700 | if (Block.getCount()) ++Coverage.BranchesExec; | |
701 | if (Edge->Count) ++Coverage.BranchesTaken; | |
702 | ++Coverage.Branches; | |
703 | ||
704 | if (Options.FuncCoverage) { | |
705 | const GCOVFunction *Function = &Block.getParent(); | |
706 | GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; | |
707 | if (Block.getCount()) ++FuncCoverage.BranchesExec; | |
708 | if (Edge->Count) ++FuncCoverage.BranchesTaken; | |
709 | ++FuncCoverage.Branches; | |
710 | } | |
711 | } | |
712 | ||
713 | for (SmallVectorImpl<uint64_t>::const_iterator I = BranchCounts.begin(), | |
714 | E = BranchCounts.end(); I != E; ++I) { | |
715 | OS << format("branch %2u ", EdgeNo++) | |
716 | << formatBranchInfo(Options, *I, TotalCounts) << "\n"; | |
717 | } | |
718 | } | |
719 | ||
720 | /// printUncondBranchInfo - Print unconditional branch probabilities. | |
721 | void FileInfo::printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo, | |
722 | uint64_t Count) const { | |
723 | OS << format("unconditional %2u ", EdgeNo++) | |
724 | << formatBranchInfo(Options, Count, Count) << "\n"; | |
725 | } | |
726 | ||
727 | // printCoverage - Print generic coverage info used by both printFuncCoverage | |
728 | // and printFileCoverage. | |
729 | void FileInfo::printCoverage(const GCOVCoverage &Coverage) const { | |
730 | outs() << format("Lines executed:%.2f%% of %u\n", | |
731 | double(Coverage.LinesExec)*100/Coverage.LogicalLines, | |
732 | Coverage.LogicalLines); | |
733 | if (Options.BranchInfo) { | |
734 | if (Coverage.Branches) { | |
735 | outs() << format("Branches executed:%.2f%% of %u\n", | |
736 | double(Coverage.BranchesExec)*100/Coverage.Branches, | |
737 | Coverage.Branches); | |
738 | outs() << format("Taken at least once:%.2f%% of %u\n", | |
739 | double(Coverage.BranchesTaken)*100/Coverage.Branches, | |
740 | Coverage.Branches); | |
741 | } else { | |
742 | outs() << "No branches\n"; | |
743 | } | |
744 | outs() << "No calls\n"; // to be consistent with gcov | |
745 | } | |
746 | } | |
747 | ||
748 | // printFuncCoverage - Print per-function coverage info. | |
749 | void FileInfo::printFuncCoverage() const { | |
750 | for (FuncCoverageMap::const_iterator I = FuncCoverages.begin(), | |
751 | E = FuncCoverages.end(); I != E; ++I) { | |
752 | const GCOVCoverage &Coverage = I->second; | |
753 | outs() << "Function '" << Coverage.Name << "'\n"; | |
754 | printCoverage(Coverage); | |
755 | outs() << "\n"; | |
756 | } | |
757 | } | |
758 | ||
759 | // printFileCoverage - Print per-file coverage info. | |
760 | void FileInfo::printFileCoverage() const { | |
761 | for (FileCoverageList::const_iterator I = FileCoverages.begin(), | |
762 | E = FileCoverages.end(); I != E; ++I) { | |
763 | const std::string &Filename = I->first; | |
764 | const GCOVCoverage &Coverage = I->second; | |
765 | outs() << "File '" << Coverage.Name << "'\n"; | |
766 | printCoverage(Coverage); | |
767 | if (!Options.NoOutput) | |
768 | outs() << Coverage.Name << ":creating '" << Filename << "'\n"; | |
769 | outs() << "\n"; | |
770 | } | |
771 | } |