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 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 526 MemoryBuffer::getFileOrSTDIN(Filename); 527 if (std::error_code EC = BufferOrErr.getError()) { 528 errs() << Filename << ": " << EC.message() << "\n"; 529 Remaining = ""; 530 } else { 531 Buffer = std::move(BufferOrErr.get()); 532 Remaining = Buffer->getBuffer(); 533 } 534 } 535 bool empty() { return Remaining.empty(); } 536 void printNext(raw_ostream &OS, uint32_t LineNum) { 537 StringRef Line; 538 if (empty()) 539 Line = "/*EOF*/"; 540 else 541 std::tie(Line, Remaining) = Remaining.split("\n"); 542 OS << format("%5u:", LineNum) << Line << "\n"; 543 } 544 }; 545 } // end anonymous namespace 546 547 /// Convert a path to a gcov filename. If PreservePaths is true, this 548 /// translates "/" to "#", ".." to "^", and drops ".", to match gcov. 549 static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) { 550 if (!PreservePaths) 551 return sys::path::filename(Filename).str(); 552 553 // This behaviour is defined by gcov in terms of text replacements, so it's 554 // not likely to do anything useful on filesystems with different textual 555 // conventions. 556 llvm::SmallString<256> Result(""); 557 StringRef::iterator I, S, E; 558 for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) { 559 if (*I != '/') 560 continue; 561 562 if (I - S == 1 && *S == '.') { 563 // ".", the current directory, is skipped. 564 } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') { 565 // "..", the parent directory, is replaced with "^". 566 Result.append("^#"); 567 } else { 568 if (S < I) 569 // Leave other components intact, 570 Result.append(S, I); 571 // And separate with "#". 572 Result.push_back('#'); 573 } 574 S = I + 1; 575 } 576 577 if (S < I) 578 Result.append(S, I); 579 return std::string(Result.str()); 580 } 581 582 std::string FileInfo::getCoveragePath(StringRef Filename, 583 StringRef MainFilename) { 584 if (Options.NoOutput) 585 // This is probably a bug in gcov, but when -n is specified, paths aren't 586 // mangled at all, and the -l and -p options are ignored. Here, we do the 587 // same. 588 return std::string(Filename); 589 590 std::string CoveragePath; 591 if (Options.LongFileNames && !Filename.equals(MainFilename)) 592 CoveragePath = 593 mangleCoveragePath(MainFilename, Options.PreservePaths) + "##"; 594 CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths); 595 if (Options.HashFilenames) { 596 MD5 Hasher; 597 MD5::MD5Result Result; 598 Hasher.update(Filename.str()); 599 Hasher.final(Result); 600 CoveragePath += "##" + std::string(Result.digest()); 601 } 602 CoveragePath += ".gcov"; 603 return CoveragePath; 604 } 605 606 std::unique_ptr<raw_ostream> 607 FileInfo::openCoveragePath(StringRef CoveragePath) { 608 std::error_code EC; 609 auto OS = 610 std::make_unique<raw_fd_ostream>(CoveragePath, EC, sys::fs::OF_Text); 611 if (EC) { 612 errs() << EC.message() << "\n"; 613 return std::make_unique<raw_null_ostream>(); 614 } 615 return std::move(OS); 616 } 617 618 /// print - Print source files with collected line count information. 619 void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename, 620 StringRef GCNOFile, StringRef GCDAFile, GCOVFile &file) { 621 SmallVector<StringRef, 4> Filenames; 622 for (const auto &LI : LineInfo) 623 Filenames.push_back(LI.first()); 624 llvm::sort(Filenames); 625 626 for (StringRef Filename : Filenames) { 627 auto AllLines = 628 Options.Intermediate ? LineConsumer() : LineConsumer(Filename); 629 std::string CoveragePath = getCoveragePath(Filename, MainFilename); 630 std::unique_ptr<raw_ostream> CovStream; 631 if (Options.NoOutput || Options.Intermediate) 632 CovStream = std::make_unique<raw_null_ostream>(); 633 else if (!Options.UseStdout) 634 CovStream = openCoveragePath(CoveragePath); 635 raw_ostream &CovOS = 636 !Options.NoOutput && Options.UseStdout ? llvm::outs() : *CovStream; 637 638 CovOS << " -: 0:Source:" << Filename << "\n"; 639 CovOS << " -: 0:Graph:" << GCNOFile << "\n"; 640 CovOS << " -: 0:Data:" << GCDAFile << "\n"; 641 CovOS << " -: 0:Runs:" << RunCount << "\n"; 642 if (file.getVersion() < GCOV::V900) 643 CovOS << " -: 0:Programs:" << ProgramCount << "\n"; 644 645 const LineData &Line = LineInfo[Filename]; 646 GCOVCoverage FileCoverage(Filename); 647 for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty(); 648 ++LineIndex) { 649 if (Options.BranchInfo) { 650 FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex); 651 if (FuncsIt != Line.Functions.end()) 652 printFunctionSummary(CovOS, FuncsIt->second); 653 } 654 655 BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex); 656 if (BlocksIt == Line.Blocks.end()) { 657 // No basic blocks are on this line. Not an executable line of code. 658 CovOS << " -:"; 659 AllLines.printNext(CovOS, LineIndex + 1); 660 } else { 661 const BlockVector &Blocks = BlocksIt->second; 662 663 // Add up the block counts to form line counts. 664 DenseMap<const GCOVFunction *, bool> LineExecs; 665 for (const GCOVBlock *Block : Blocks) { 666 if (Options.FuncCoverage) { 667 // This is a slightly convoluted way to most accurately gather line 668 // statistics for functions. Basically what is happening is that we 669 // don't want to count a single line with multiple blocks more than 670 // once. However, we also don't simply want to give the total line 671 // count to every function that starts on the line. Thus, what is 672 // happening here are two things: 673 // 1) Ensure that the number of logical lines is only incremented 674 // once per function. 675 // 2) If there are multiple blocks on the same line, ensure that the 676 // number of lines executed is incremented as long as at least 677 // one of the blocks are executed. 678 const GCOVFunction *Function = &Block->getParent(); 679 if (FuncCoverages.find(Function) == FuncCoverages.end()) { 680 std::pair<const GCOVFunction *, GCOVCoverage> KeyValue( 681 Function, GCOVCoverage(Function->getName())); 682 FuncCoverages.insert(KeyValue); 683 } 684 GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; 685 686 if (LineExecs.find(Function) == LineExecs.end()) { 687 if (Block->getCount()) { 688 ++FuncCoverage.LinesExec; 689 LineExecs[Function] = true; 690 } else { 691 LineExecs[Function] = false; 692 } 693 ++FuncCoverage.LogicalLines; 694 } else if (!LineExecs[Function] && Block->getCount()) { 695 ++FuncCoverage.LinesExec; 696 LineExecs[Function] = true; 697 } 698 } 699 } 700 701 const uint64_t LineCount = GCOVBlock::getLineCount(Blocks); 702 if (LineCount == 0) 703 CovOS << " #####:"; 704 else { 705 CovOS << format("%9" PRIu64 ":", LineCount); 706 ++FileCoverage.LinesExec; 707 } 708 ++FileCoverage.LogicalLines; 709 710 AllLines.printNext(CovOS, LineIndex + 1); 711 712 uint32_t BlockNo = 0; 713 uint32_t EdgeNo = 0; 714 for (const GCOVBlock *Block : Blocks) { 715 // Only print block and branch information at the end of the block. 716 if (Block->getLastLine() != LineIndex + 1) 717 continue; 718 if (Options.AllBlocks) 719 printBlockInfo(CovOS, *Block, LineIndex, BlockNo); 720 if (Options.BranchInfo) { 721 size_t NumEdges = Block->getNumDstEdges(); 722 if (NumEdges > 1) 723 printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo); 724 else if (Options.UncondBranch && NumEdges == 1) 725 printUncondBranchInfo(CovOS, EdgeNo, Block->succ[0]->Count); 726 } 727 } 728 } 729 } 730 SourceInfo &source = sources[file.filenameToIdx.find(Filename)->second]; 731 source.name = CoveragePath; 732 source.coverage = FileCoverage; 733 } 734 735 if (Options.Intermediate && !Options.NoOutput) { 736 // gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0 737 // (PR GCC/82702). We create just one file. 738 std::string outputPath(sys::path::filename(MainFilename)); 739 std::error_code ec; 740 raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_Text); 741 if (ec) { 742 errs() << ec.message() << "\n"; 743 return; 744 } 745 746 for (const SourceInfo &source : sources) { 747 os << "file:" << source.filename << '\n'; 748 for (const GCOVFunction *f : source.functions) 749 os << "function:" << f->startLine << ',' << f->getEntryCount() << ',' 750 << f->Name << '\n'; 751 const LineData &line = LineInfo[source.filename]; 752 for (uint32_t lineNum = 0; lineNum != line.LastLine; ++lineNum) { 753 BlockLines::const_iterator BlocksIt = line.Blocks.find(lineNum); 754 if (BlocksIt == line.Blocks.end()) 755 continue; 756 const BlockVector &blocks = BlocksIt->second; 757 // GCC 8 (r254259) added third third field for Ada: 758 // lcount:<line>,<count>,<has_unexecuted_blocks> 759 // We don't need the third field. 760 os << "lcount:" << (lineNum + 1) << ',' 761 << GCOVBlock::getLineCount(blocks) << '\n'; 762 763 if (!Options.BranchInfo) 764 continue; 765 for (const GCOVBlock *block : blocks) { 766 if (block->getLastLine() != lineNum + 1 || 767 block->getNumDstEdges() < 2) 768 continue; 769 for (const GCOVArc *arc : block->dsts()) { 770 const char *type = block->getCount() 771 ? arc->Count ? "taken" : "nottaken" 772 : "notexec"; 773 os << "branch:" << (lineNum + 1) << ',' << type << '\n'; 774 } 775 } 776 } 777 } 778 } 779 780 if (!Options.UseStdout) { 781 // FIXME: There is no way to detect calls given current instrumentation. 782 if (Options.FuncCoverage) 783 printFuncCoverage(InfoOS); 784 printFileCoverage(InfoOS); 785 } 786 } 787 788 /// printFunctionSummary - Print function and block summary. 789 void FileInfo::printFunctionSummary(raw_ostream &OS, 790 const FunctionVector &Funcs) const { 791 for (const GCOVFunction *Func : Funcs) { 792 uint64_t EntryCount = Func->getEntryCount(); 793 uint32_t BlocksExec = 0; 794 for (const GCOVBlock &Block : Func->blocks()) 795 if (Block.getNumDstEdges() && Block.getCount()) 796 ++BlocksExec; 797 798 OS << "function " << Func->getName() << " called " << EntryCount 799 << " returned " << safeDiv(Func->getExitCount() * 100, EntryCount) 800 << "% blocks executed " 801 << safeDiv(BlocksExec * 100, Func->getNumBlocks() - 1) << "%\n"; 802 } 803 } 804 805 /// printBlockInfo - Output counts for each block. 806 void FileInfo::printBlockInfo(raw_ostream &OS, const GCOVBlock &Block, 807 uint32_t LineIndex, uint32_t &BlockNo) const { 808 if (Block.getCount() == 0) 809 OS << " $$$$$:"; 810 else 811 OS << format("%9" PRIu64 ":", Block.getCount()); 812 OS << format("%5u-block %2u\n", LineIndex + 1, BlockNo++); 813 } 814 815 /// printBranchInfo - Print conditional branch probabilities. 816 void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block, 817 GCOVCoverage &Coverage, uint32_t &EdgeNo) { 818 SmallVector<uint64_t, 16> BranchCounts; 819 uint64_t TotalCounts = 0; 820 for (const GCOVArc *Edge : Block.dsts()) { 821 BranchCounts.push_back(Edge->Count); 822 TotalCounts += Edge->Count; 823 if (Block.getCount()) 824 ++Coverage.BranchesExec; 825 if (Edge->Count) 826 ++Coverage.BranchesTaken; 827 ++Coverage.Branches; 828 829 if (Options.FuncCoverage) { 830 const GCOVFunction *Function = &Block.getParent(); 831 GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; 832 if (Block.getCount()) 833 ++FuncCoverage.BranchesExec; 834 if (Edge->Count) 835 ++FuncCoverage.BranchesTaken; 836 ++FuncCoverage.Branches; 837 } 838 } 839 840 for (uint64_t N : BranchCounts) 841 OS << format("branch %2u ", EdgeNo++) 842 << formatBranchInfo(Options, N, TotalCounts) << "\n"; 843 } 844 845 /// printUncondBranchInfo - Print unconditional branch probabilities. 846 void FileInfo::printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo, 847 uint64_t Count) const { 848 OS << format("unconditional %2u ", EdgeNo++) 849 << formatBranchInfo(Options, Count, Count) << "\n"; 850 } 851 852 // printCoverage - Print generic coverage info used by both printFuncCoverage 853 // and printFileCoverage. 854 void FileInfo::printCoverage(raw_ostream &OS, 855 const GCOVCoverage &Coverage) const { 856 OS << format("Lines executed:%.2f%% of %u\n", 857 double(Coverage.LinesExec) * 100 / Coverage.LogicalLines, 858 Coverage.LogicalLines); 859 if (Options.BranchInfo) { 860 if (Coverage.Branches) { 861 OS << format("Branches executed:%.2f%% of %u\n", 862 double(Coverage.BranchesExec) * 100 / Coverage.Branches, 863 Coverage.Branches); 864 OS << format("Taken at least once:%.2f%% of %u\n", 865 double(Coverage.BranchesTaken) * 100 / Coverage.Branches, 866 Coverage.Branches); 867 } else { 868 OS << "No branches\n"; 869 } 870 OS << "No calls\n"; // to be consistent with gcov 871 } 872 } 873 874 // printFuncCoverage - Print per-function coverage info. 875 void FileInfo::printFuncCoverage(raw_ostream &OS) const { 876 for (const auto &FC : FuncCoverages) { 877 const GCOVCoverage &Coverage = FC.second; 878 OS << "Function '" << Coverage.Name << "'\n"; 879 printCoverage(OS, Coverage); 880 OS << "\n"; 881 } 882 } 883 884 // printFileCoverage - Print per-file coverage info. 885 void FileInfo::printFileCoverage(raw_ostream &OS) const { 886 for (const SourceInfo &source : sources) { 887 const GCOVCoverage &Coverage = source.coverage; 888 OS << "File '" << Coverage.Name << "'\n"; 889 printCoverage(OS, Coverage); 890 if (!Options.NoOutput && !Options.Intermediate) 891 OS << "Creating '" << source.name << "'\n"; 892 OS << "\n"; 893 } 894 } 895