Home | History | Annotate | Download | only in Support
      1 //===-- llvm/Support/GCOV.h - LLVM coverage tool ----------------*- C++ -*-===//
      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 // This header provides the interface to read and write coverage files that
     11 // use 'gcov' format.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_SUPPORT_GCOV_H
     16 #define LLVM_SUPPORT_GCOV_H
     17 
     18 #include "llvm/ADT/SmallVector.h"
     19 #include "llvm/ADT/StringMap.h"
     20 #include "llvm/Support/MemoryBuffer.h"
     21 #include "llvm/Support/raw_ostream.h"
     22 
     23 namespace llvm {
     24 
     25 class GCOVFunction;
     26 class GCOVBlock;
     27 class GCOVLines;
     28 class FileInfo;
     29 
     30 namespace GCOV {
     31   enum GCOVFormat {
     32     InvalidGCOV,
     33     GCNO_402,
     34     GCNO_404,
     35     GCDA_402,
     36     GCDA_404
     37   };
     38 } // end GCOV namespace
     39 
     40 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
     41 /// read operations.
     42 class GCOVBuffer {
     43 public:
     44   GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
     45 
     46   /// readGCOVFormat - Read GCOV signature at the beginning of buffer.
     47   GCOV::GCOVFormat readGCOVFormat() {
     48     StringRef Magic = Buffer->getBuffer().slice(0, 12);
     49     Cursor = 12;
     50     if (Magic == "oncg*404MVLL")
     51       return GCOV::GCNO_404;
     52     else if (Magic == "oncg*204MVLL")
     53       return GCOV::GCNO_402;
     54     else if (Magic == "adcg*404MVLL")
     55       return GCOV::GCDA_404;
     56     else if (Magic == "adcg*204MVLL")
     57       return GCOV::GCDA_402;
     58 
     59     Cursor = 0;
     60     return GCOV::InvalidGCOV;
     61   }
     62 
     63   /// readFunctionTag - If cursor points to a function tag then increment the
     64   /// cursor and return true otherwise return false.
     65   bool readFunctionTag() {
     66     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
     67     if (Tag.empty() ||
     68         Tag[0] != '\0' || Tag[1] != '\0' ||
     69         Tag[2] != '\0' || Tag[3] != '\1') {
     70       return false;
     71     }
     72     Cursor += 4;
     73     return true;
     74   }
     75 
     76   /// readBlockTag - If cursor points to a block tag then increment the
     77   /// cursor and return true otherwise return false.
     78   bool readBlockTag() {
     79     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
     80     if (Tag.empty() ||
     81         Tag[0] != '\0' || Tag[1] != '\0' ||
     82         Tag[2] != '\x41' || Tag[3] != '\x01') {
     83       return false;
     84     }
     85     Cursor += 4;
     86     return true;
     87   }
     88 
     89   /// readEdgeTag - If cursor points to an edge tag then increment the
     90   /// cursor and return true otherwise return false.
     91   bool readEdgeTag() {
     92     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
     93     if (Tag.empty() ||
     94         Tag[0] != '\0' || Tag[1] != '\0' ||
     95         Tag[2] != '\x43' || Tag[3] != '\x01') {
     96       return false;
     97     }
     98     Cursor += 4;
     99     return true;
    100   }
    101 
    102   /// readLineTag - If cursor points to a line tag then increment the
    103   /// cursor and return true otherwise return false.
    104   bool readLineTag() {
    105     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
    106     if (Tag.empty() ||
    107         Tag[0] != '\0' || Tag[1] != '\0' ||
    108         Tag[2] != '\x45' || Tag[3] != '\x01') {
    109       return false;
    110     }
    111     Cursor += 4;
    112     return true;
    113   }
    114 
    115   /// readArcTag - If cursor points to an gcda arc tag then increment the
    116   /// cursor and return true otherwise return false.
    117   bool readArcTag() {
    118     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
    119     if (Tag.empty() ||
    120         Tag[0] != '\0' || Tag[1] != '\0' ||
    121         Tag[2] != '\xa1' || Tag[3] != '\1') {
    122       return false;
    123     }
    124     Cursor += 4;
    125     return true;
    126   }
    127 
    128   uint32_t readInt() {
    129     uint32_t Result;
    130     StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4);
    131     assert (Str.empty() == false && "Unexpected memory buffer end!");
    132     Cursor += 4;
    133     Result = *(const uint32_t *)(Str.data());
    134     return Result;
    135   }
    136 
    137   uint64_t readInt64() {
    138     uint64_t Lo = readInt();
    139     uint64_t Hi = readInt();
    140     uint64_t Result = Lo | (Hi << 32);
    141     return Result;
    142   }
    143 
    144   StringRef readString() {
    145     uint32_t Len = readInt() * 4;
    146     StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+Len);
    147     Cursor += Len;
    148     return Str;
    149   }
    150 
    151   uint64_t getCursor() const { return Cursor; }
    152 private:
    153   MemoryBuffer *Buffer;
    154   uint64_t Cursor;
    155 };
    156 
    157 /// GCOVFile - Collects coverage information for one pair of coverage file
    158 /// (.gcno and .gcda).
    159 class GCOVFile {
    160 public:
    161   GCOVFile() {}
    162   ~GCOVFile();
    163   bool read(GCOVBuffer &Buffer);
    164   void dump();
    165   void collectLineCounts(FileInfo &FI);
    166 private:
    167   SmallVector<GCOVFunction *, 16> Functions;
    168 };
    169 
    170 /// GCOVFunction - Collects function information.
    171 class GCOVFunction {
    172 public:
    173   GCOVFunction() : Ident(0), LineNumber(0) {}
    174   ~GCOVFunction();
    175   bool read(GCOVBuffer &Buffer, GCOV::GCOVFormat Format);
    176   void dump();
    177   void collectLineCounts(FileInfo &FI);
    178 private:
    179   uint32_t Ident;
    180   uint32_t LineNumber;
    181   StringRef Name;
    182   StringRef Filename;
    183   SmallVector<GCOVBlock *, 16> Blocks;
    184 };
    185 
    186 /// GCOVBlock - Collects block information.
    187 class GCOVBlock {
    188 public:
    189   GCOVBlock(uint32_t N) : Number(N), Counter(0) {}
    190   ~GCOVBlock();
    191   void addEdge(uint32_t N) { Edges.push_back(N); }
    192   void addLine(StringRef Filename, uint32_t LineNo);
    193   void addCount(uint64_t N) { Counter = N; }
    194   void dump();
    195   void collectLineCounts(FileInfo &FI);
    196 private:
    197   uint32_t Number;
    198   uint64_t Counter;
    199   SmallVector<uint32_t, 16> Edges;
    200   StringMap<GCOVLines *> Lines;
    201 };
    202 
    203 /// GCOVLines - A wrapper around a vector of int to keep track of line nos.
    204 class GCOVLines {
    205 public:
    206   ~GCOVLines() { Lines.clear(); }
    207   void add(uint32_t N) { Lines.push_back(N); }
    208   void collectLineCounts(FileInfo &FI, StringRef Filename, uint32_t Count);
    209   void dump();
    210 
    211 private:
    212   SmallVector<uint32_t, 4> Lines;
    213 };
    214 
    215 typedef SmallVector<uint32_t, 16> LineCounts;
    216 class FileInfo {
    217 public:
    218   void addLineCount(StringRef Filename, uint32_t Line, uint32_t Count);
    219   void print();
    220 private:
    221   StringMap<LineCounts> LineInfo;
    222 };
    223 
    224 }
    225 
    226 #endif
    227