1 //===- GCOV.cpp - LLVM coverage tool --------------------------------------===// 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 // GCOV implements the interface to read and write coverage files that use 10 // 'gcov' format. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ProfileData/GCOV.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/Config/llvm-config.h" 17 #include "llvm/Support/Debug.h" 18 #include "llvm/Support/FileSystem.h" 19 #include "llvm/Support/Format.h" 20 #include "llvm/Support/Path.h" 21 #include "llvm/Support/MD5.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <algorithm> 24 #include <system_error> 25 26 using namespace llvm; 27 28 enum : uint32_t { 29 GCOV_ARC_ON_TREE = 1 << 0, 30 GCOV_ARC_FALLTHROUGH = 1 << 2, 31 32 GCOV_TAG_FUNCTION = 0x01000000, 33 GCOV_TAG_BLOCKS = 0x01410000, 34 GCOV_TAG_ARCS = 0x01430000, 35 GCOV_TAG_LINES = 0x01450000, 36 GCOV_TAG_COUNTER_ARCS = 0x01a10000, 37 // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9. 38 GCOV_TAG_OBJECT_SUMMARY = 0xa1000000, 39 GCOV_TAG_PROGRAM_SUMMARY = 0xa3000000, 40 }; 41 42 //===----------------------------------------------------------------------===// 43 // GCOVFile implementation. 44 45 /// readGCNO - Read GCNO buffer. 46 bool GCOVFile::readGCNO(GCOVBuffer &buf) { 47 if (!buf.readGCNOFormat()) 48 return false; 49 if (!buf.readGCOVVersion(Version)) 50 return false; 51 52 Checksum = buf.getWord(); 53 if (Version >= GCOV::V900) 54 cwd = buf.getString(); 55 if (Version >= GCOV::V800) 56 buf.getWord(); // hasUnexecutedBlocks 57 58 uint32_t tag, length; 59 GCOVFunction *fn; 60 while ((tag = buf.getWord())) { 61 if (!buf.readInt(length)) 62 return false; 63 if (tag == GCOV_TAG_FUNCTION) { 64 Functions.push_back(std::make_unique<GCOVFunction>(*this)); 65 fn = Functions.back().get(); 66 fn->ident = buf.getWord(); 67 fn->linenoChecksum = buf.getWord(); 68 if (Version >= GCOV::V407) 69 fn->cfgChecksum = buf.getWord(); 70 buf.readString(fn->Name); 71 if (Version < GCOV::V800) { 72 buf.readString(fn->Filename); 73 fn->startLine = buf.getWord(); 74 } else { 75 fn->artificial = buf.getWord(); 76 fn->Filename = buf.getString(); 77 fn->startLine = buf.getWord(); 78 fn->startColumn = buf.getWord(); 79 fn->endLine = buf.getWord(); 80 if (Version >= GCOV::V900) 81 fn->endColumn = buf.getWord(); 82 } 83 IdentToFunction[fn->ident] = fn; 84 } else if (tag == GCOV_TAG_BLOCKS && fn) { 85 if (Version < GCOV::V800) { 86 for (uint32_t i = 0; i != length; ++i) { 87 buf.getWord(); // Ignored block flags 88 fn->Blocks.push_back(std::make_unique<GCOVBlock>(*fn, i)); 89 } 90 } else { 91 uint32_t num = buf.getWord(); 92 for (uint32_t i = 0; i != num; ++i) 93 fn->Blocks.push_back(std::make_unique<GCOVBlock>(*fn, i)); 94 } 95 } else if (tag == GCOV_TAG_ARCS && fn) { 96 uint32_t srcNo = buf.getWord(); 97 if (srcNo >= fn->Blocks.size()) { 98 errs() << "unexpected block number: " << srcNo << " (in " 99 << fn->Blocks.size() << ")\n"; 100 return false; 101 } 102 GCOVBlock *src = fn->Blocks[srcNo].get(); 103 for (uint32_t i = 0, e = (length - 1) / 2; i != e; ++i) { 104 uint32_t dstNo = buf.getWord(), flags = buf.getWord(); 105 GCOVBlock *dst = fn->Blocks[dstNo].get(); 106 auto arc = 107 std::make_unique<GCOVArc>(*src, *dst, flags & GCOV_ARC_FALLTHROUGH); 108 src->addDstEdge(arc.get()); 109 dst->addSrcEdge(arc.get()); 110 if (flags & GCOV_ARC_ON_TREE) 111 fn->treeArcs.push_back(std::move(arc)); 112 else 113 fn->arcs.push_back(std::move(arc)); 114 } 115 } else if (tag == GCOV_TAG_LINES && fn) { 116 uint32_t srcNo = buf.getWord(); 117 if (srcNo >= fn->Blocks.size()) { 118 errs() << "unexpected block number: " << srcNo << " (in " 119 << fn->Blocks.size() << ")\n"; 120 return false; 121 } 122 GCOVBlock &Block = *fn->Blocks[srcNo]; 123 for (;;) { 124 uint32_t line = buf.getWord(); 125 if (line) 126 Block.addLine(line); 127 else { 128 StringRef filename = buf.getString(); 129 if (filename.empty()) 130 break; 131 // TODO Unhandled 132 } 133 } 134 } 135 } 136 137 GCNOInitialized = true; 138 return true; 139 } 140 141 /// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be 142 /// called after readGCNO(). 143 bool GCOVFile::readGCDA(GCOVBuffer &buf) { 144 assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()"); 145 if (!buf.readGCDAFormat()) 146 return false; 147 GCOV::GCOVVersion GCDAVersion; 148 if (!buf.readGCOVVersion(GCDAVersion)) 149 return false; 150 if (Version != GCDAVersion) { 151 errs() << "GCOV versions do not match.\n"; 152 return false; 153 } 154 155 uint32_t GCDAChecksum; 156 if (!buf.readInt(GCDAChecksum)) 157 return false; 158 if (Checksum != GCDAChecksum) { 159 errs() << "File checksums do not match: " << Checksum 160 << " != " << GCDAChecksum << ".\n"; 161 return false; 162 } 163 uint32_t dummy, tag, length; 164 uint32_t ident; 165 GCOVFunction *fn = nullptr; 166 while ((tag = buf.getWord())) { 167 if (!buf.readInt(length)) 168 return false; 169 uint32_t pos = buf.cursor.tell(); 170 if (tag == GCOV_TAG_OBJECT_SUMMARY) { 171 buf.readInt(RunCount); 172 buf.readInt(dummy); 173 } else if (tag == GCOV_TAG_PROGRAM_SUMMARY) { 174 buf.readInt(dummy); 175 buf.readInt(dummy); 176 buf.readInt(RunCount); 177 ++ProgramCount; 178 } else if (tag == GCOV_TAG_FUNCTION) { 179 if (length == 0) // Placeholder 180 continue; 181 // As of GCC 10, GCOV_TAG_FUNCTION_LENGTH has never been larger than 3. 182 if ((length != 2 && length != 3) || !buf.readInt(ident)) 183 return false; 184 auto It = IdentToFunction.find(ident); 185 uint32_t linenoChecksum, cfgChecksum = 0; 186 buf.readInt(linenoChecksum); 187 if (Version >= GCOV::V407) 188 buf.readInt(cfgChecksum); 189 if (It != IdentToFunction.end()) { 190 fn = It->second; 191 if (linenoChecksum != fn->linenoChecksum || 192 cfgChecksum != fn->cfgChecksum) { 193 errs() << fn->Name 194 << format(": checksum mismatch, (%u, %u) != (%u, %u)\n", 195 linenoChecksum, cfgChecksum, fn->linenoChecksum, 196 fn->cfgChecksum); 197 return false; 198 } 199 } 200 } else if (tag == GCOV_TAG_COUNTER_ARCS && fn) { 201 if (length != 2 * fn->arcs.size()) { 202 errs() << fn->Name 203 << format( 204 ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n", 205 length, unsigned(2 * fn->arcs.size())); 206 return false; 207 } 208 for (std::unique_ptr<GCOVArc> &arc : fn->arcs) { 209 if (!buf.readInt64(arc->Count)) 210 return false; 211 // FIXME Fix counters 212 arc->src.Counter += arc->Count; 213 if (arc->dst.succ.empty()) 214 arc->dst.Counter += arc->Count; 215 } 216 } 217 pos += 4 * length; 218 if (pos < buf.cursor.tell()) 219 return false; 220 buf.de.skip(buf.cursor, pos - buf.cursor.tell()); 221 } 222 223 return true; 224 } 225 226 void GCOVFile::print(raw_ostream &OS) const { 227 for (const auto &FPtr : Functions) 228 FPtr->print(OS); 229 } 230 231 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 232 /// dump - Dump GCOVFile content to dbgs() for debugging purposes. 233 LLVM_DUMP_METHOD void GCOVFile::dump() const { print(dbgs()); } 234 #endif 235 236 /// collectLineCounts - Collect line counts. This must be used after 237 /// reading .gcno and .gcda files. 238 void GCOVFile::collectLineCounts(FileInfo &FI) { 239 for (const auto &FPtr : Functions) 240 FPtr->collectLineCounts(FI); 241 FI.setRunCount(RunCount); 242 FI.setProgramCount(ProgramCount); 243 } 244 245 //===----------------------------------------------------------------------===// 246 // GCOVFunction implementation. 247 248 /// getEntryCount - Get the number of times the function was called by 249 /// retrieving the entry block's count. 250 uint64_t GCOVFunction::getEntryCount() const { 251 return Blocks.front()->getCount(); 252 } 253 254 /// getExitCount - Get the number of times the function returned by retrieving 255 /// the exit block's count. 256 uint64_t GCOVFunction::getExitCount() const { 257 return Blocks.back()->getCount(); 258 } 259 260 void GCOVFunction::print(raw_ostream &OS) const { 261 OS << "===== " << Name << " (" << ident << ") @ " << Filename << ":" 262 << startLine << "\n"; 263 for (const auto &Block : Blocks) 264 Block->print(OS); 265 } 266 267 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 268 /// dump - Dump GCOVFunction content to dbgs() for debugging purposes. 269 LLVM_DUMP_METHOD void GCOVFunction::dump() const { print(dbgs()); } 270 #endif 271 272 /// collectLineCounts - Collect line counts. This must be used after 273 /// reading .gcno and .gcda files. 274 void GCOVFunction::collectLineCounts(FileInfo &FI) { 275 // If the line number is zero, this is a function that doesn't actually appear 276 // in the source file, so there isn't anything we can do with it. 277 if (startLine == 0) 278 return; 279 280 for (const auto &Block : Blocks) 281 Block->collectLineCounts(FI); 282 FI.addFunctionLine(Filename, startLine, this); 283 } 284 285 //===----------------------------------------------------------------------===// 286 // GCOVBlock implementation. 287 288 /// collectLineCounts - Collect line counts. This must be used after 289 /// reading .gcno and .gcda files. 290 void GCOVBlock::collectLineCounts(FileInfo &FI) { 291 for (uint32_t N : Lines) 292 FI.addBlockLine(Parent.getFilename(), N, this); 293 } 294 295 void GCOVBlock::print(raw_ostream &OS) const { 296 OS << "Block : " << Number << " Counter : " << Counter << "\n"; 297 if (!pred.empty()) { 298 OS << "\tSource Edges : "; 299 for (const GCOVArc *Edge : pred) 300 OS << Edge->src.Number << " (" << Edge->Count << "), "; 301 OS << "\n"; 302 } 303 if (!succ.empty()) { 304 OS << "\tDestination Edges : "; 305 for (const GCOVArc *Edge : succ) 306 OS << Edge->dst.Number << " (" << Edge->Count << "), "; 307 OS << "\n"; 308 } 309 if (!Lines.empty()) { 310 OS << "\tLines : "; 311 for (uint32_t N : Lines) 312 OS << (N) << ","; 313 OS << "\n"; 314 } 315 } 316 317 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 318 /// dump - Dump GCOVBlock content to dbgs() for debugging purposes. 319 LLVM_DUMP_METHOD void GCOVBlock::dump() const { print(dbgs()); } 320 #endif 321 322 //===----------------------------------------------------------------------===// 323 // Cycles detection 324 // 325 // The algorithm in GCC is based on the algorithm by Hawick & James: 326 // "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs" 327 // http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf. 328 329 /// Get the count for the detected cycle. 330 uint64_t GCOVBlock::getCycleCount(const Edges &Path) { 331 uint64_t CycleCount = std::numeric_limits<uint64_t>::max(); 332 for (auto E : Path) { 333 CycleCount = std::min(E->CyclesCount, CycleCount); 334 } 335 for (auto E : Path) { 336 E->CyclesCount -= CycleCount; 337 } 338 return CycleCount; 339 } 340 341 /// Unblock a vertex previously marked as blocked. 342 void GCOVBlock::unblock(const GCOVBlock *U, BlockVector &Blocked, 343 BlockVectorLists &BlockLists) { 344 auto it = find(Blocked, U); 345 if (it == Blocked.end()) { 346 return; 347 } 348 349 const size_t index = it - Blocked.begin(); 350 Blocked.erase(it); 351 352 const BlockVector ToUnblock(BlockLists[index]); 353 BlockLists.erase(BlockLists.begin() + index); 354 for (auto GB : ToUnblock) { 355 GCOVBlock::unblock(GB, Blocked, BlockLists); 356 } 357 } 358 359 bool GCOVBlock::lookForCircuit(const GCOVBlock *V, const GCOVBlock *Start, 360 Edges &Path, BlockVector &Blocked, 361 BlockVectorLists &BlockLists, 362 const BlockVector &Blocks, uint64_t &Count) { 363 Blocked.push_back(V); 364 BlockLists.emplace_back(BlockVector()); 365 bool FoundCircuit = false; 366 367 for (auto E : V->dsts()) { 368 const GCOVBlock *W = &E->dst; 369 if (W < Start || find(Blocks, W) == Blocks.end()) { 370 continue; 371 } 372 373 Path.push_back(E); 374 375 if (W == Start) { 376 // We've a cycle. 377 Count += GCOVBlock::getCycleCount(Path); 378 FoundCircuit = true; 379 } else if (find(Blocked, W) == Blocked.end() && // W is not blocked. 380 GCOVBlock::lookForCircuit(W, Start, Path, Blocked, BlockLists, 381 Blocks, Count)) { 382 FoundCircuit = true; 383 } 384 385 Path.pop_back(); 386 } 387 388 if (FoundCircuit) { 389 GCOVBlock::unblock(V, Blocked, BlockLists); 390 } else { 391 for (auto E : V->dsts()) { 392 const GCOVBlock *W = &E->dst; 393 if (W < Start || find(Blocks, W) == Blocks.end()) { 394 continue; 395 } 396 const size_t index = find(Blocked, W) - Blocked.begin(); 397 BlockVector &List = BlockLists[index]; 398 if (find(List, V) == List.end()) { 399 List.push_back(V); 400 } 401 } 402 } 403 404 return FoundCircuit; 405 } 406 407 /// Get the count for the list of blocks which lie on the same line. 408 void GCOVBlock::getCyclesCount(const BlockVector &Blocks, uint64_t &Count) { 409 for (auto Block : Blocks) { 410 Edges Path; 411 BlockVector Blocked; 412 BlockVectorLists BlockLists; 413 414 GCOVBlock::lookForCircuit(Block, Block, Path, Blocked, BlockLists, Blocks, 415 Count); 416 } 417 } 418 419 /// Get the count for the list of blocks which lie on the same line. 420 uint64_t GCOVBlock::getLineCount(const BlockVector &Blocks) { 421 uint64_t Count = 0; 422 423 for (auto Block : Blocks) { 424 if (Block->getNumSrcEdges() == 0) { 425 // The block has no predecessors and a non-null counter 426 // (can be the case with entry block in functions). 427 Count += Block->getCount(); 428 } else { 429 // Add counts from predecessors that are not on the same line. 430 for (auto E : Block->srcs()) { 431 const GCOVBlock *W = &E->src; 432 if (find(Blocks, W) == Blocks.end()) { 433 Count += E->Count; 434 } 435 } 436 } 437 for (auto E : Block->dsts()) { 438 E->CyclesCount = E->Count; 439 } 440 } 441 442 GCOVBlock::getCyclesCount(Blocks, Count); 443 444 return Count; 445 } 446 447 //===----------------------------------------------------------------------===// 448 // FileInfo implementation. 449 450 // Safe integer division, returns 0 if numerator is 0. 451 static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) { 452 if (!Numerator) 453 return 0; 454 return Numerator / Divisor; 455 } 456 457 // This custom division function mimics gcov's branch ouputs: 458 // - Round to closest whole number 459 // - Only output 0% or 100% if it's exactly that value 460 static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) { 461 if (!Numerator) 462 return 0; 463 if (Numerator == Divisor) 464 return 100; 465 466 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor; 467 if (Res == 0) 468 return 1; 469 if (Res == 100) 470 return 99; 471 return Res; 472 } 473 474 namespace { 475 struct formatBranchInfo { 476 formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total) 477 : Options(Options), Count(Count), Total(Total) {} 478 479 void print(raw_ostream &OS) const { 480 if (!Total) 481 OS << "never executed"; 482 else if (Options.BranchCount) 483 OS << "taken " << Count; 484 else 485 OS << "taken " << branchDiv(Count, Total) << "%"; 486 } 487 488 const GCOV::Options &Options; 489 uint64_t Count; 490 uint64_t Total; 491 }; 492 493 static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) { 494 FBI.print(OS); 495 return OS; 496 } 497 498 class LineConsumer { 499 std::unique_ptr<MemoryBuffer> Buffer; 500 StringRef Remaining; 501 502 public: 503 LineConsumer(StringRef Filename) { 504 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 505 MemoryBuffer::getFileOrSTDIN(Filename); 506 if (std::error_code EC = BufferOrErr.getError()) { 507 errs() << Filename << ": " << EC.message() << "\n"; 508 Remaining = ""; 509 } else { 510 Buffer = std::move(BufferOrErr.get()); 511 Remaining = Buffer->getBuffer(); 512 } 513 } 514 bool empty() { return Remaining.empty(); } 515 void printNext(raw_ostream &OS, uint32_t LineNum) { 516 StringRef Line; 517 if (empty()) 518 Line = "/*EOF*/"; 519 else 520 std::tie(Line, Remaining) = Remaining.split("\n"); 521 OS << format("%5u:", LineNum) << Line << "\n"; 522 } 523 }; 524 } // end anonymous namespace 525 526 /// Convert a path to a gcov filename. If PreservePaths is true, this 527 /// translates "/" to "#", ".." to "^", and drops ".", to match gcov. 528 static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) { 529 if (!PreservePaths) 530 return sys::path::filename(Filename).str(); 531 532 // This behaviour is defined by gcov in terms of text replacements, so it's 533 // not likely to do anything useful on filesystems with different textual 534 // conventions. 535 llvm::SmallString<256> Result(""); 536 StringRef::iterator I, S, E; 537 for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) { 538 if (*I != '/') 539 continue; 540 541 if (I - S == 1 && *S == '.') { 542 // ".", the current directory, is skipped. 543 } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') { 544 // "..", the parent directory, is replaced with "^". 545 Result.append("^#"); 546 } else { 547 if (S < I) 548 // Leave other components intact, 549 Result.append(S, I); 550 // And separate with "#". 551 Result.push_back('#'); 552 } 553 S = I + 1; 554 } 555 556 if (S < I) 557 Result.append(S, I); 558 return std::string(Result.str()); 559 } 560 561 std::string FileInfo::getCoveragePath(StringRef Filename, 562 StringRef MainFilename) { 563 if (Options.NoOutput) 564 // This is probably a bug in gcov, but when -n is specified, paths aren't 565 // mangled at all, and the -l and -p options are ignored. Here, we do the 566 // same. 567 return std::string(Filename); 568 569 std::string CoveragePath; 570 if (Options.LongFileNames && !Filename.equals(MainFilename)) 571 CoveragePath = 572 mangleCoveragePath(MainFilename, Options.PreservePaths) + "##"; 573 CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths); 574 if (Options.HashFilenames) { 575 MD5 Hasher; 576 MD5::MD5Result Result; 577 Hasher.update(Filename.str()); 578 Hasher.final(Result); 579 CoveragePath += "##" + std::string(Result.digest()); 580 } 581 CoveragePath += ".gcov"; 582 return CoveragePath; 583 } 584 585 std::unique_ptr<raw_ostream> 586 FileInfo::openCoveragePath(StringRef CoveragePath) { 587 std::error_code EC; 588 auto OS = 589 std::make_unique<raw_fd_ostream>(CoveragePath, EC, sys::fs::OF_Text); 590 if (EC) { 591 errs() << EC.message() << "\n"; 592 return std::make_unique<raw_null_ostream>(); 593 } 594 return std::move(OS); 595 } 596 597 /// print - Print source files with collected line count information. 598 void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename, 599 StringRef GCNOFile, StringRef GCDAFile, 600 GCOV::GCOVVersion Version) { 601 SmallVector<StringRef, 4> Filenames; 602 for (const auto &LI : LineInfo) 603 Filenames.push_back(LI.first()); 604 llvm::sort(Filenames); 605 606 for (StringRef Filename : Filenames) { 607 auto AllLines = LineConsumer(Filename); 608 609 std::string CoveragePath = getCoveragePath(Filename, MainFilename); 610 std::unique_ptr<raw_ostream> CovStream; 611 if (Options.NoOutput) 612 CovStream = std::make_unique<raw_null_ostream>(); 613 else if (!Options.UseStdout) 614 CovStream = openCoveragePath(CoveragePath); 615 raw_ostream &CovOS = 616 !Options.NoOutput && Options.UseStdout ? llvm::outs() : *CovStream; 617 618 CovOS << " -: 0:Source:" << Filename << "\n"; 619 CovOS << " -: 0:Graph:" << GCNOFile << "\n"; 620 CovOS << " -: 0:Data:" << GCDAFile << "\n"; 621 CovOS << " -: 0:Runs:" << RunCount << "\n"; 622 if (Version < GCOV::V900) 623 CovOS << " -: 0:Programs:" << ProgramCount << "\n"; 624 625 const LineData &Line = LineInfo[Filename]; 626 GCOVCoverage FileCoverage(Filename); 627 for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty(); 628 ++LineIndex) { 629 if (Options.BranchInfo) { 630 FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex); 631 if (FuncsIt != Line.Functions.end()) 632 printFunctionSummary(CovOS, FuncsIt->second); 633 } 634 635 BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex); 636 if (BlocksIt == Line.Blocks.end()) { 637 // No basic blocks are on this line. Not an executable line of code. 638 CovOS << " -:"; 639 AllLines.printNext(CovOS, LineIndex + 1); 640 } else { 641 const BlockVector &Blocks = BlocksIt->second; 642 643 // Add up the block counts to form line counts. 644 DenseMap<const GCOVFunction *, bool> LineExecs; 645 for (const GCOVBlock *Block : Blocks) { 646 if (Options.FuncCoverage) { 647 // This is a slightly convoluted way to most accurately gather line 648 // statistics for functions. Basically what is happening is that we 649 // don't want to count a single line with multiple blocks more than 650 // once. However, we also don't simply want to give the total line 651 // count to every function that starts on the line. Thus, what is 652 // happening here are two things: 653 // 1) Ensure that the number of logical lines is only incremented 654 // once per function. 655 // 2) If there are multiple blocks on the same line, ensure that the 656 // number of lines executed is incremented as long as at least 657 // one of the blocks are executed. 658 const GCOVFunction *Function = &Block->getParent(); 659 if (FuncCoverages.find(Function) == FuncCoverages.end()) { 660 std::pair<const GCOVFunction *, GCOVCoverage> KeyValue( 661 Function, GCOVCoverage(Function->getName())); 662 FuncCoverages.insert(KeyValue); 663 } 664 GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; 665 666 if (LineExecs.find(Function) == LineExecs.end()) { 667 if (Block->getCount()) { 668 ++FuncCoverage.LinesExec; 669 LineExecs[Function] = true; 670 } else { 671 LineExecs[Function] = false; 672 } 673 ++FuncCoverage.LogicalLines; 674 } else if (!LineExecs[Function] && Block->getCount()) { 675 ++FuncCoverage.LinesExec; 676 LineExecs[Function] = true; 677 } 678 } 679 } 680 681 const uint64_t LineCount = GCOVBlock::getLineCount(Blocks); 682 if (LineCount == 0) 683 CovOS << " #####:"; 684 else { 685 CovOS << format("%9" PRIu64 ":", LineCount); 686 ++FileCoverage.LinesExec; 687 } 688 ++FileCoverage.LogicalLines; 689 690 AllLines.printNext(CovOS, LineIndex + 1); 691 692 uint32_t BlockNo = 0; 693 uint32_t EdgeNo = 0; 694 for (const GCOVBlock *Block : Blocks) { 695 // Only print block and branch information at the end of the block. 696 if (Block->getLastLine() != LineIndex + 1) 697 continue; 698 if (Options.AllBlocks) 699 printBlockInfo(CovOS, *Block, LineIndex, BlockNo); 700 if (Options.BranchInfo) { 701 size_t NumEdges = Block->getNumDstEdges(); 702 if (NumEdges > 1) 703 printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo); 704 else if (Options.UncondBranch && NumEdges == 1) 705 printUncondBranchInfo(CovOS, EdgeNo, Block->succ[0]->Count); 706 } 707 } 708 } 709 } 710 FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage)); 711 } 712 713 if (!Options.UseStdout) { 714 // FIXME: There is no way to detect calls given current instrumentation. 715 if (Options.FuncCoverage) 716 printFuncCoverage(InfoOS); 717 printFileCoverage(InfoOS); 718 } 719 } 720 721 /// printFunctionSummary - Print function and block summary. 722 void FileInfo::printFunctionSummary(raw_ostream &OS, 723 const FunctionVector &Funcs) const { 724 for (const GCOVFunction *Func : Funcs) { 725 uint64_t EntryCount = Func->getEntryCount(); 726 uint32_t BlocksExec = 0; 727 for (const GCOVBlock &Block : Func->blocks()) 728 if (Block.getNumDstEdges() && Block.getCount()) 729 ++BlocksExec; 730 731 OS << "function " << Func->getName() << " called " << EntryCount 732 << " returned " << safeDiv(Func->getExitCount() * 100, EntryCount) 733 << "% blocks executed " 734 << safeDiv(BlocksExec * 100, Func->getNumBlocks() - 1) << "%\n"; 735 } 736 } 737 738 /// printBlockInfo - Output counts for each block. 739 void FileInfo::printBlockInfo(raw_ostream &OS, const GCOVBlock &Block, 740 uint32_t LineIndex, uint32_t &BlockNo) const { 741 if (Block.getCount() == 0) 742 OS << " $$$$$:"; 743 else 744 OS << format("%9" PRIu64 ":", Block.getCount()); 745 OS << format("%5u-block %2u\n", LineIndex + 1, BlockNo++); 746 } 747 748 /// printBranchInfo - Print conditional branch probabilities. 749 void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block, 750 GCOVCoverage &Coverage, uint32_t &EdgeNo) { 751 SmallVector<uint64_t, 16> BranchCounts; 752 uint64_t TotalCounts = 0; 753 for (const GCOVArc *Edge : Block.dsts()) { 754 BranchCounts.push_back(Edge->Count); 755 TotalCounts += Edge->Count; 756 if (Block.getCount()) 757 ++Coverage.BranchesExec; 758 if (Edge->Count) 759 ++Coverage.BranchesTaken; 760 ++Coverage.Branches; 761 762 if (Options.FuncCoverage) { 763 const GCOVFunction *Function = &Block.getParent(); 764 GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; 765 if (Block.getCount()) 766 ++FuncCoverage.BranchesExec; 767 if (Edge->Count) 768 ++FuncCoverage.BranchesTaken; 769 ++FuncCoverage.Branches; 770 } 771 } 772 773 for (uint64_t N : BranchCounts) 774 OS << format("branch %2u ", EdgeNo++) 775 << formatBranchInfo(Options, N, TotalCounts) << "\n"; 776 } 777 778 /// printUncondBranchInfo - Print unconditional branch probabilities. 779 void FileInfo::printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo, 780 uint64_t Count) const { 781 OS << format("unconditional %2u ", EdgeNo++) 782 << formatBranchInfo(Options, Count, Count) << "\n"; 783 } 784 785 // printCoverage - Print generic coverage info used by both printFuncCoverage 786 // and printFileCoverage. 787 void FileInfo::printCoverage(raw_ostream &OS, 788 const GCOVCoverage &Coverage) const { 789 OS << format("Lines executed:%.2f%% of %u\n", 790 double(Coverage.LinesExec) * 100 / Coverage.LogicalLines, 791 Coverage.LogicalLines); 792 if (Options.BranchInfo) { 793 if (Coverage.Branches) { 794 OS << format("Branches executed:%.2f%% of %u\n", 795 double(Coverage.BranchesExec) * 100 / Coverage.Branches, 796 Coverage.Branches); 797 OS << format("Taken at least once:%.2f%% of %u\n", 798 double(Coverage.BranchesTaken) * 100 / Coverage.Branches, 799 Coverage.Branches); 800 } else { 801 OS << "No branches\n"; 802 } 803 OS << "No calls\n"; // to be consistent with gcov 804 } 805 } 806 807 // printFuncCoverage - Print per-function coverage info. 808 void FileInfo::printFuncCoverage(raw_ostream &OS) const { 809 for (const auto &FC : FuncCoverages) { 810 const GCOVCoverage &Coverage = FC.second; 811 OS << "Function '" << Coverage.Name << "'\n"; 812 printCoverage(OS, Coverage); 813 OS << "\n"; 814 } 815 } 816 817 // printFileCoverage - Print per-file coverage info. 818 void FileInfo::printFileCoverage(raw_ostream &OS) const { 819 for (const auto &FC : FileCoverages) { 820 const std::string &Filename = FC.first; 821 const GCOVCoverage &Coverage = FC.second; 822 OS << "File '" << Coverage.Name << "'\n"; 823 printCoverage(OS, Coverage); 824 if (!Options.NoOutput) 825 OS << "Creating '" << Filename << "'\n"; 826 OS << "\n"; 827 } 828 } 829