GCOV.h revision 263508
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/DenseMap.h" 19#include "llvm/ADT/SmallVector.h" 20#include "llvm/ADT/StringMap.h" 21#include "llvm/Support/MemoryBuffer.h" 22#include "llvm/Support/raw_ostream.h" 23 24namespace llvm { 25 26class GCOVFunction; 27class GCOVBlock; 28class FileInfo; 29 30namespace 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. 42class GCOVBuffer { 43public: 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 /// readObjectTag - If cursor points to an object summary tag then increment 129 /// the cursor and return true otherwise return false. 130 bool readObjectTag() { 131 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 132 if (Tag.empty() || 133 Tag[0] != '\0' || Tag[1] != '\0' || 134 Tag[2] != '\0' || Tag[3] != '\xa1') { 135 return false; 136 } 137 Cursor += 4; 138 return true; 139 } 140 141 /// readProgramTag - If cursor points to a program summary tag then increment 142 /// the cursor and return true otherwise return false. 143 bool readProgramTag() { 144 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 145 if (Tag.empty() || 146 Tag[0] != '\0' || Tag[1] != '\0' || 147 Tag[2] != '\0' || Tag[3] != '\xa3') { 148 return false; 149 } 150 Cursor += 4; 151 return true; 152 } 153 154 bool readInt(uint32_t &Val) { 155 if (Buffer->getBuffer().size() < Cursor+4) { 156 errs() << "Unexpected end of memory buffer: " << Cursor+4 << ".\n"; 157 return false; 158 } 159 StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4); 160 Cursor += 4; 161 Val = *(const uint32_t *)(Str.data()); 162 return true; 163 } 164 165 bool readInt64(uint64_t &Val) { 166 uint32_t Lo, Hi; 167 if (!readInt(Lo) || !readInt(Hi)) return false; 168 Val = ((uint64_t)Hi << 32) | Lo; 169 return true; 170 } 171 172 bool readString(StringRef &Str) { 173 uint32_t Len; 174 if (!readInt(Len)) return false; 175 Len *= 4; 176 if (Buffer->getBuffer().size() < Cursor+Len) { 177 errs() << "Unexpected end of memory buffer: " << Cursor+Len << ".\n"; 178 return false; 179 } 180 Str = Buffer->getBuffer().slice(Cursor, Cursor+Len).split('\0').first; 181 Cursor += Len; 182 return true; 183 } 184 185 uint64_t getCursor() const { return Cursor; } 186 void advanceCursor(uint32_t n) { Cursor += n*4; } 187private: 188 MemoryBuffer *Buffer; 189 uint64_t Cursor; 190}; 191 192/// GCOVFile - Collects coverage information for one pair of coverage file 193/// (.gcno and .gcda). 194class GCOVFile { 195public: 196 GCOVFile() : Functions(), RunCount(0), ProgramCount(0) {} 197 ~GCOVFile(); 198 bool read(GCOVBuffer &Buffer); 199 void dump(); 200 void collectLineCounts(FileInfo &FI); 201private: 202 SmallVector<GCOVFunction *, 16> Functions; 203 uint32_t RunCount; 204 uint32_t ProgramCount; 205}; 206 207/// GCOVFunction - Collects function information. 208class GCOVFunction { 209public: 210 GCOVFunction() : Ident(0), LineNumber(0) {} 211 ~GCOVFunction(); 212 bool read(GCOVBuffer &Buffer, GCOV::GCOVFormat Format); 213 StringRef getFilename() const { return Filename; } 214 void dump(); 215 void collectLineCounts(FileInfo &FI); 216private: 217 uint32_t Ident; 218 uint32_t LineNumber; 219 StringRef Name; 220 StringRef Filename; 221 SmallVector<GCOVBlock *, 16> Blocks; 222}; 223 224/// GCOVBlock - Collects block information. 225class GCOVBlock { 226public: 227 GCOVBlock(GCOVFunction &P, uint32_t N) : 228 Parent(P), Number(N), Counter(0), Edges(), Lines() {} 229 ~GCOVBlock(); 230 void addEdge(uint32_t N) { Edges.push_back(N); } 231 void addLine(uint32_t N) { Lines.push_back(N); } 232 void addCount(uint64_t N) { Counter += N; } 233 size_t getNumEdges() { return Edges.size(); } 234 void dump(); 235 void collectLineCounts(FileInfo &FI); 236private: 237 GCOVFunction &Parent; 238 uint32_t Number; 239 uint64_t Counter; 240 SmallVector<uint32_t, 16> Edges; 241 SmallVector<uint32_t, 16> Lines; 242}; 243 244typedef DenseMap<uint32_t, uint64_t> LineCounts; 245class FileInfo { 246public: 247 void addLineCount(StringRef Filename, uint32_t Line, uint64_t Count) { 248 LineInfo[Filename][Line-1] += Count; 249 } 250 void setRunCount(uint32_t Runs) { RunCount = Runs; } 251 void setProgramCount(uint32_t Programs) { ProgramCount = Programs; } 252 void print(raw_fd_ostream &OS, StringRef gcnoFile, StringRef gcdaFile); 253private: 254 StringMap<LineCounts> LineInfo; 255 uint32_t RunCount; 256 uint32_t ProgramCount; 257}; 258 259} 260 261#endif 262