1226584Sdim//===-- llvm/Support/GCOV.h - LLVM coverage tool ----------------*- C++ -*-===// 2226584Sdim// 3226584Sdim// The LLVM Compiler Infrastructure 4226584Sdim// 5226584Sdim// This file is distributed under the University of Illinois Open Source 6226584Sdim// License. See LICENSE.TXT for details. 7226584Sdim// 8226584Sdim//===----------------------------------------------------------------------===// 9226584Sdim// 10226584Sdim// This header provides the interface to read and write coverage files that 11226584Sdim// use 'gcov' format. 12226584Sdim// 13226584Sdim//===----------------------------------------------------------------------===// 14226584Sdim 15252723Sdim#ifndef LLVM_SUPPORT_GCOV_H 16252723Sdim#define LLVM_SUPPORT_GCOV_H 17226584Sdim 18263509Sdim#include "llvm/ADT/DenseMap.h" 19226584Sdim#include "llvm/ADT/SmallVector.h" 20226584Sdim#include "llvm/ADT/StringMap.h" 21226584Sdim#include "llvm/Support/MemoryBuffer.h" 22226584Sdim#include "llvm/Support/raw_ostream.h" 23226584Sdim 24226584Sdimnamespace llvm { 25226584Sdim 26226584Sdimclass GCOVFunction; 27226584Sdimclass GCOVBlock; 28226584Sdimclass FileInfo; 29226584Sdim 30245431Sdimnamespace GCOV { 31245431Sdim enum GCOVFormat { 32245431Sdim InvalidGCOV, 33245431Sdim GCNO_402, 34245431Sdim GCNO_404, 35245431Sdim GCDA_402, 36245431Sdim GCDA_404 37245431Sdim }; 38245431Sdim} // end GCOV namespace 39226584Sdim 40226584Sdim/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific 41226584Sdim/// read operations. 42226584Sdimclass GCOVBuffer { 43226584Sdimpublic: 44226584Sdim GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {} 45226584Sdim 46226584Sdim /// readGCOVFormat - Read GCOV signature at the beginning of buffer. 47245431Sdim GCOV::GCOVFormat readGCOVFormat() { 48226584Sdim StringRef Magic = Buffer->getBuffer().slice(0, 12); 49226584Sdim Cursor = 12; 50226584Sdim if (Magic == "oncg*404MVLL") 51245431Sdim return GCOV::GCNO_404; 52226584Sdim else if (Magic == "oncg*204MVLL") 53245431Sdim return GCOV::GCNO_402; 54226584Sdim else if (Magic == "adcg*404MVLL") 55245431Sdim return GCOV::GCDA_404; 56226584Sdim else if (Magic == "adcg*204MVLL") 57245431Sdim return GCOV::GCDA_402; 58226584Sdim 59226584Sdim Cursor = 0; 60245431Sdim return GCOV::InvalidGCOV; 61226584Sdim } 62226584Sdim 63226584Sdim /// readFunctionTag - If cursor points to a function tag then increment the 64226584Sdim /// cursor and return true otherwise return false. 65226584Sdim bool readFunctionTag() { 66226584Sdim StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 67226584Sdim if (Tag.empty() || 68245431Sdim Tag[0] != '\0' || Tag[1] != '\0' || 69245431Sdim Tag[2] != '\0' || Tag[3] != '\1') { 70226584Sdim return false; 71226584Sdim } 72226584Sdim Cursor += 4; 73226584Sdim return true; 74226584Sdim } 75226584Sdim 76226584Sdim /// readBlockTag - If cursor points to a block tag then increment the 77226584Sdim /// cursor and return true otherwise return false. 78226584Sdim bool readBlockTag() { 79226584Sdim StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 80226584Sdim if (Tag.empty() || 81245431Sdim Tag[0] != '\0' || Tag[1] != '\0' || 82245431Sdim Tag[2] != '\x41' || Tag[3] != '\x01') { 83226584Sdim return false; 84226584Sdim } 85226584Sdim Cursor += 4; 86226584Sdim return true; 87226584Sdim } 88226584Sdim 89226584Sdim /// readEdgeTag - If cursor points to an edge tag then increment the 90226584Sdim /// cursor and return true otherwise return false. 91226584Sdim bool readEdgeTag() { 92226584Sdim StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 93226584Sdim if (Tag.empty() || 94245431Sdim Tag[0] != '\0' || Tag[1] != '\0' || 95245431Sdim Tag[2] != '\x43' || Tag[3] != '\x01') { 96226584Sdim return false; 97226584Sdim } 98226584Sdim Cursor += 4; 99226584Sdim return true; 100226584Sdim } 101226584Sdim 102226584Sdim /// readLineTag - If cursor points to a line tag then increment the 103226584Sdim /// cursor and return true otherwise return false. 104226584Sdim bool readLineTag() { 105226584Sdim StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 106226584Sdim if (Tag.empty() || 107245431Sdim Tag[0] != '\0' || Tag[1] != '\0' || 108245431Sdim Tag[2] != '\x45' || Tag[3] != '\x01') { 109226584Sdim return false; 110226584Sdim } 111226584Sdim Cursor += 4; 112226584Sdim return true; 113226584Sdim } 114226584Sdim 115226584Sdim /// readArcTag - If cursor points to an gcda arc tag then increment the 116226584Sdim /// cursor and return true otherwise return false. 117226584Sdim bool readArcTag() { 118226584Sdim StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 119226584Sdim if (Tag.empty() || 120245431Sdim Tag[0] != '\0' || Tag[1] != '\0' || 121245431Sdim Tag[2] != '\xa1' || Tag[3] != '\1') { 122226584Sdim return false; 123226584Sdim } 124226584Sdim Cursor += 4; 125226584Sdim return true; 126226584Sdim } 127226584Sdim 128263509Sdim /// readObjectTag - If cursor points to an object summary tag then increment 129263509Sdim /// the cursor and return true otherwise return false. 130263509Sdim bool readObjectTag() { 131263509Sdim StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 132263509Sdim if (Tag.empty() || 133263509Sdim Tag[0] != '\0' || Tag[1] != '\0' || 134263509Sdim Tag[2] != '\0' || Tag[3] != '\xa1') { 135263509Sdim return false; 136263509Sdim } 137263509Sdim Cursor += 4; 138263509Sdim return true; 139263509Sdim } 140263509Sdim 141263509Sdim /// readProgramTag - If cursor points to a program summary tag then increment 142263509Sdim /// the cursor and return true otherwise return false. 143263509Sdim bool readProgramTag() { 144263509Sdim StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4); 145263509Sdim if (Tag.empty() || 146263509Sdim Tag[0] != '\0' || Tag[1] != '\0' || 147263509Sdim Tag[2] != '\0' || Tag[3] != '\xa3') { 148263509Sdim return false; 149263509Sdim } 150263509Sdim Cursor += 4; 151263509Sdim return true; 152263509Sdim } 153263509Sdim 154263509Sdim bool readInt(uint32_t &Val) { 155263509Sdim if (Buffer->getBuffer().size() < Cursor+4) { 156263509Sdim errs() << "Unexpected end of memory buffer: " << Cursor+4 << ".\n"; 157263509Sdim return false; 158263509Sdim } 159226584Sdim StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4); 160226584Sdim Cursor += 4; 161263509Sdim Val = *(const uint32_t *)(Str.data()); 162263509Sdim return true; 163226584Sdim } 164226584Sdim 165263509Sdim bool readInt64(uint64_t &Val) { 166263509Sdim uint32_t Lo, Hi; 167263509Sdim if (!readInt(Lo) || !readInt(Hi)) return false; 168263509Sdim Val = ((uint64_t)Hi << 32) | Lo; 169263509Sdim return true; 170226584Sdim } 171226584Sdim 172263509Sdim bool readString(StringRef &Str) { 173263509Sdim uint32_t Len; 174263509Sdim if (!readInt(Len)) return false; 175263509Sdim Len *= 4; 176263509Sdim if (Buffer->getBuffer().size() < Cursor+Len) { 177263509Sdim errs() << "Unexpected end of memory buffer: " << Cursor+Len << ".\n"; 178263509Sdim return false; 179263509Sdim } 180263509Sdim Str = Buffer->getBuffer().slice(Cursor, Cursor+Len).split('\0').first; 181226584Sdim Cursor += Len; 182263509Sdim return true; 183226584Sdim } 184226584Sdim 185226584Sdim uint64_t getCursor() const { return Cursor; } 186263509Sdim void advanceCursor(uint32_t n) { Cursor += n*4; } 187226584Sdimprivate: 188226584Sdim MemoryBuffer *Buffer; 189226584Sdim uint64_t Cursor; 190226584Sdim}; 191226584Sdim 192226584Sdim/// GCOVFile - Collects coverage information for one pair of coverage file 193226584Sdim/// (.gcno and .gcda). 194226584Sdimclass GCOVFile { 195226584Sdimpublic: 196263509Sdim GCOVFile() : Functions(), RunCount(0), ProgramCount(0) {} 197226584Sdim ~GCOVFile(); 198226584Sdim bool read(GCOVBuffer &Buffer); 199226584Sdim void dump(); 200226584Sdim void collectLineCounts(FileInfo &FI); 201226584Sdimprivate: 202226584Sdim SmallVector<GCOVFunction *, 16> Functions; 203263509Sdim uint32_t RunCount; 204263509Sdim uint32_t ProgramCount; 205226584Sdim}; 206226584Sdim 207226584Sdim/// GCOVFunction - Collects function information. 208226584Sdimclass GCOVFunction { 209226584Sdimpublic: 210226584Sdim GCOVFunction() : Ident(0), LineNumber(0) {} 211226584Sdim ~GCOVFunction(); 212245431Sdim bool read(GCOVBuffer &Buffer, GCOV::GCOVFormat Format); 213263509Sdim StringRef getFilename() const { return Filename; } 214226584Sdim void dump(); 215226584Sdim void collectLineCounts(FileInfo &FI); 216226584Sdimprivate: 217226584Sdim uint32_t Ident; 218226584Sdim uint32_t LineNumber; 219226584Sdim StringRef Name; 220226584Sdim StringRef Filename; 221226584Sdim SmallVector<GCOVBlock *, 16> Blocks; 222226584Sdim}; 223226584Sdim 224226584Sdim/// GCOVBlock - Collects block information. 225226584Sdimclass GCOVBlock { 226226584Sdimpublic: 227263509Sdim GCOVBlock(GCOVFunction &P, uint32_t N) : 228263509Sdim Parent(P), Number(N), Counter(0), Edges(), Lines() {} 229226584Sdim ~GCOVBlock(); 230226584Sdim void addEdge(uint32_t N) { Edges.push_back(N); } 231263509Sdim void addLine(uint32_t N) { Lines.push_back(N); } 232263509Sdim void addCount(uint64_t N) { Counter += N; } 233263509Sdim size_t getNumEdges() { return Edges.size(); } 234226584Sdim void dump(); 235226584Sdim void collectLineCounts(FileInfo &FI); 236226584Sdimprivate: 237263509Sdim GCOVFunction &Parent; 238226584Sdim uint32_t Number; 239226584Sdim uint64_t Counter; 240226584Sdim SmallVector<uint32_t, 16> Edges; 241263509Sdim SmallVector<uint32_t, 16> Lines; 242226584Sdim}; 243226584Sdim 244263509Sdimtypedef DenseMap<uint32_t, uint64_t> LineCounts; 245226584Sdimclass FileInfo { 246226584Sdimpublic: 247263509Sdim void addLineCount(StringRef Filename, uint32_t Line, uint64_t Count) { 248263509Sdim LineInfo[Filename][Line-1] += Count; 249263509Sdim } 250263509Sdim void setRunCount(uint32_t Runs) { RunCount = Runs; } 251263509Sdim void setProgramCount(uint32_t Programs) { ProgramCount = Programs; } 252263509Sdim void print(raw_fd_ostream &OS, StringRef gcnoFile, StringRef gcdaFile); 253226584Sdimprivate: 254226584Sdim StringMap<LineCounts> LineInfo; 255263509Sdim uint32_t RunCount; 256263509Sdim uint32_t ProgramCount; 257226584Sdim}; 258226584Sdim 259226584Sdim} 260226584Sdim 261226584Sdim#endif 262