123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This header provides the interface to read and write coverage files that
- // use 'gcov' format.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_PROFILEDATA_GCOV_H
- #define LLVM_PROFILEDATA_GCOV_H
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/DenseSet.h"
- #include "llvm/ADT/MapVector.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringMap.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/iterator.h"
- #include "llvm/ADT/iterator_range.h"
- #include "llvm/Support/DataExtractor.h"
- #include "llvm/Support/MemoryBuffer.h"
- #include "llvm/Support/raw_ostream.h"
- #include <algorithm>
- #include <cassert>
- #include <cstddef>
- #include <cstdint>
- #include <limits>
- #include <map>
- #include <memory>
- #include <string>
- #include <utility>
- namespace llvm {
- class GCOVFunction;
- class GCOVBlock;
- namespace GCOV {
- enum GCOVVersion { V304, V407, V408, V800, V900 };
- /// A struct for passing gcov options between functions.
- struct Options {
- Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L,
- bool M, bool N, bool R, bool T, bool X, std::string SourcePrefix)
- : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
- PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L),
- Demangle(M), NoOutput(N), RelativeOnly(R), UseStdout(T),
- HashFilenames(X), SourcePrefix(std::move(SourcePrefix)) {}
- bool AllBlocks;
- bool BranchInfo;
- bool BranchCount;
- bool FuncCoverage;
- bool PreservePaths;
- bool UncondBranch;
- bool Intermediate;
- bool LongFileNames;
- bool Demangle;
- bool NoOutput;
- bool RelativeOnly;
- bool UseStdout;
- bool HashFilenames;
- std::string SourcePrefix;
- };
- } // end namespace GCOV
- /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
- /// read operations.
- class GCOVBuffer {
- public:
- GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
- ~GCOVBuffer() { consumeError(cursor.takeError()); }
- /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
- bool readGCNOFormat() {
- StringRef buf = Buffer->getBuffer();
- StringRef magic = buf.substr(0, 4);
- if (magic == "gcno") {
- de = DataExtractor(buf.substr(4), false, 0);
- } else if (magic == "oncg") {
- de = DataExtractor(buf.substr(4), true, 0);
- } else {
- errs() << "unexpected magic: " << magic << "\n";
- return false;
- }
- return true;
- }
- /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
- bool readGCDAFormat() {
- StringRef buf = Buffer->getBuffer();
- StringRef magic = buf.substr(0, 4);
- if (magic == "gcda") {
- de = DataExtractor(buf.substr(4), false, 0);
- } else if (magic == "adcg") {
- de = DataExtractor(buf.substr(4), true, 0);
- } else {
- return false;
- }
- return true;
- }
- /// readGCOVVersion - Read GCOV version.
- bool readGCOVVersion(GCOV::GCOVVersion &Version) {
- std::string str(de.getBytes(cursor, 4));
- if (str.size() != 4)
- return false;
- if (de.isLittleEndian())
- std::reverse(str.begin(), str.end());
- int ver = str[0] >= 'A'
- ? (str[0] - 'A') * 100 + (str[1] - '0') * 10 + str[2] - '0'
- : (str[0] - '0') * 10 + str[2] - '0';
- if (ver >= 90) {
- // PR gcov-profile/84846, r269678
- Version = GCOV::V900;
- return true;
- } else if (ver >= 80) {
- // PR gcov-profile/48463
- Version = GCOV::V800;
- return true;
- } else if (ver >= 48) {
- // r189778: the exit block moved from the last to the second.
- Version = GCOV::V408;
- return true;
- } else if (ver >= 47) {
- // r173147: split checksum into cfg checksum and line checksum.
- Version = GCOV::V407;
- return true;
- } else if (ver >= 34) {
- Version = GCOV::V304;
- return true;
- }
- errs() << "unexpected version: " << str << "\n";
- return false;
- }
- uint32_t getWord() { return de.getU32(cursor); }
- StringRef getString() {
- uint32_t len;
- if (!readInt(len) || len == 0)
- return {};
- return de.getBytes(cursor, len * 4).split('\0').first;
- }
- bool readInt(uint32_t &Val) {
- if (cursor.tell() + 4 > de.size()) {
- Val = 0;
- errs() << "unexpected end of memory buffer: " << cursor.tell() << "\n";
- return false;
- }
- Val = de.getU32(cursor);
- return true;
- }
- bool readInt64(uint64_t &Val) {
- uint32_t Lo, Hi;
- if (!readInt(Lo) || !readInt(Hi))
- return false;
- Val = ((uint64_t)Hi << 32) | Lo;
- return true;
- }
- bool readString(StringRef &Str) {
- uint32_t len;
- if (!readInt(len) || len == 0)
- return false;
- Str = de.getBytes(cursor, len * 4).split('\0').first;
- return bool(cursor);
- }
- DataExtractor de{ArrayRef<uint8_t>{}, false, 0};
- DataExtractor::Cursor cursor{0};
- private:
- MemoryBuffer *Buffer;
- };
- /// GCOVFile - Collects coverage information for one pair of coverage file
- /// (.gcno and .gcda).
- class GCOVFile {
- public:
- GCOVFile() = default;
- bool readGCNO(GCOVBuffer &Buffer);
- bool readGCDA(GCOVBuffer &Buffer);
- GCOV::GCOVVersion getVersion() const { return Version; }
- void print(raw_ostream &OS) const;
- void dump() const;
- std::vector<std::string> filenames;
- StringMap<unsigned> filenameToIdx;
- public:
- bool GCNOInitialized = false;
- GCOV::GCOVVersion Version;
- uint32_t Checksum = 0;
- StringRef cwd;
- SmallVector<std::unique_ptr<GCOVFunction>, 16> functions;
- std::map<uint32_t, GCOVFunction *> IdentToFunction;
- uint32_t RunCount = 0;
- uint32_t ProgramCount = 0;
- using iterator = pointee_iterator<
- SmallVectorImpl<std::unique_ptr<GCOVFunction>>::const_iterator>;
- iterator begin() const { return iterator(functions.begin()); }
- iterator end() const { return iterator(functions.end()); }
- };
- struct GCOVArc {
- GCOVArc(GCOVBlock &src, GCOVBlock &dst, uint32_t flags)
- : src(src), dst(dst), flags(flags) {}
- bool onTree() const;
- GCOVBlock &src;
- GCOVBlock &dst;
- uint32_t flags;
- uint64_t count = 0;
- uint64_t cycleCount = 0;
- };
- /// GCOVFunction - Collects function information.
- class GCOVFunction {
- public:
- using BlockIterator = pointee_iterator<
- SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
- GCOVFunction(GCOVFile &file) : file(file) {}
- StringRef getName(bool demangle) const;
- StringRef getFilename() const;
- uint64_t getEntryCount() const;
- GCOVBlock &getExitBlock() const;
- iterator_range<BlockIterator> blocksRange() const {
- return make_range(blocks.begin(), blocks.end());
- }
- uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred);
- void print(raw_ostream &OS) const;
- void dump() const;
- GCOVFile &file;
- uint32_t ident = 0;
- uint32_t linenoChecksum;
- uint32_t cfgChecksum = 0;
- uint32_t startLine = 0;
- uint32_t startColumn = 0;
- uint32_t endLine = 0;
- uint32_t endColumn = 0;
- uint8_t artificial = 0;
- StringRef Name;
- mutable SmallString<0> demangled;
- unsigned srcIdx;
- SmallVector<std::unique_ptr<GCOVBlock>, 0> blocks;
- SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs;
- DenseSet<const GCOVBlock *> visited;
- };
- /// GCOVBlock - Collects block information.
- class GCOVBlock {
- public:
- using EdgeIterator = SmallVectorImpl<GCOVArc *>::const_iterator;
- using BlockVector = SmallVector<const GCOVBlock *, 1>;
- using BlockVectorLists = SmallVector<BlockVector, 4>;
- using Edges = SmallVector<GCOVArc *, 4>;
- GCOVBlock(uint32_t N) : number(N) {}
- void addLine(uint32_t N) { lines.push_back(N); }
- uint32_t getLastLine() const { return lines.back(); }
- uint64_t getCount() const { return count; }
- void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
- void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); }
- iterator_range<EdgeIterator> srcs() const {
- return make_range(pred.begin(), pred.end());
- }
- iterator_range<EdgeIterator> dsts() const {
- return make_range(succ.begin(), succ.end());
- }
- void print(raw_ostream &OS) const;
- void dump() const;
- static uint64_t
- augmentOneCycle(GCOVBlock *src,
- std::vector<std::pair<GCOVBlock *, size_t>> &stack);
- static uint64_t getCyclesCount(const BlockVector &blocks);
- static uint64_t getLineCount(const BlockVector &Blocks);
- public:
- uint32_t number;
- uint64_t count = 0;
- SmallVector<GCOVArc *, 2> pred;
- SmallVector<GCOVArc *, 2> succ;
- SmallVector<uint32_t, 4> lines;
- bool traversable = false;
- GCOVArc *incoming = nullptr;
- };
- void gcovOneInput(const GCOV::Options &options, StringRef filename,
- StringRef gcno, StringRef gcda, GCOVFile &file);
- } // end namespace llvm
- #endif // LLVM_SUPPORT_GCOV_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|