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