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