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