llvm-cov: Split GCOVFile's read into GCNO and GCDA.
[oota-llvm.git] / lib / IR / GCOV.cpp
1 //===- GCOVr.cpp - LLVM coverage tool -------------------------------------===//
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 // GCOV implements the interface to read and write coverage files that use
11 // 'gcov' format.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/Support/Debug.h"
16 #include "llvm/Support/GCOV.h"
17 #include "llvm/ADT/OwningPtr.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/MemoryObject.h"
21 #include "llvm/Support/system_error.h"
22 using namespace llvm;
23
24 //===----------------------------------------------------------------------===//
25 // GCOVFile implementation.
26
27 /// ~GCOVFile - Delete GCOVFile and its content.
28 GCOVFile::~GCOVFile() {
29   DeleteContainerPointers(Functions);
30 }
31
32 /// readGCNO - Read GCNO buffer.
33 bool GCOVFile::readGCNO(GCOVBuffer &Buffer) {
34   if (!Buffer.readGCNOFormat()) return false;
35   if (!Buffer.readGCOVVersion(Version)) return false;
36
37   if (!Buffer.readInt(Checksum)) return false;
38   while (true) {
39     if (!Buffer.readFunctionTag()) break;
40     GCOVFunction *GFun = new GCOVFunction();
41     if (!GFun->readGCNO(Buffer, Version))
42       return false;
43     Functions.push_back(GFun);
44   }
45
46   gcnoInitialized = true;
47   return true;
48 }
49
50 /// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
51 /// called after readGCNO().
52 bool GCOVFile::readGCDA(GCOVBuffer &Buffer) {
53   assert(gcnoInitialized && "readGCDA() can only be called after readGCNO()");
54   if (!Buffer.readGCDAFormat()) return false;
55   GCOV::GCOVVersion GCDAVersion;
56   if (!Buffer.readGCOVVersion(GCDAVersion)) return false;
57   if (Version != GCDAVersion) {
58     errs() << "GCOV versions do not match.\n";
59     return false;
60   }
61
62   uint32_t GCDAChecksum;
63   if (!Buffer.readInt(GCDAChecksum)) return false;
64   if (Checksum != GCDAChecksum) {
65     errs() << "File checksum does not match.\n";
66     return false;
67   }
68   for (size_t i = 0, e = Functions.size(); i < e; ++i) {
69     if (!Buffer.readFunctionTag()) {
70       errs() << "Unexpected number of functions.\n";
71       return false;
72     }
73     if (!Functions[i]->readGCDA(Buffer, Version))
74       return false;
75   }
76   if (Buffer.readObjectTag()) {
77     uint32_t Length;
78     uint32_t Dummy;
79     if (!Buffer.readInt(Length)) return false;
80     if (!Buffer.readInt(Dummy)) return false; // checksum
81     if (!Buffer.readInt(Dummy)) return false; // num
82     if (!Buffer.readInt(RunCount)) return false;;
83     Buffer.advanceCursor(Length-3);
84   }
85   while (Buffer.readProgramTag()) {
86     uint32_t Length;
87     if (!Buffer.readInt(Length)) return false;
88     Buffer.advanceCursor(Length);
89     ++ProgramCount;
90   }
91
92   return true;
93 }
94
95 /// dump - Dump GCOVFile content to dbgs() for debugging purposes.
96 void GCOVFile::dump() const {
97   for (SmallVectorImpl<GCOVFunction *>::const_iterator I = Functions.begin(),
98          E = Functions.end(); I != E; ++I)
99     (*I)->dump();
100 }
101
102 /// collectLineCounts - Collect line counts. This must be used after
103 /// reading .gcno and .gcda files.
104 void GCOVFile::collectLineCounts(FileInfo &FI) {
105   for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
106          E = Functions.end(); I != E; ++I)
107     (*I)->collectLineCounts(FI);
108   FI.setRunCount(RunCount);
109   FI.setProgramCount(ProgramCount);
110 }
111
112 //===----------------------------------------------------------------------===//
113 // GCOVFunction implementation.
114
115 /// ~GCOVFunction - Delete GCOVFunction and its content.
116 GCOVFunction::~GCOVFunction() {
117   DeleteContainerPointers(Blocks);
118   DeleteContainerPointers(Edges);
119 }
120
121 /// readGCNO - Read a function from the GCNO buffer. Return false if an error
122 /// occurs.
123 bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
124   uint32_t Dummy;
125   if (!Buff.readInt(Dummy)) return false; // Function header length
126   if (!Buff.readInt(Ident)) return false;
127   if (!Buff.readInt(Dummy)) return false; // Checksum #1
128   if (Version != GCOV::V402)
129     if (!Buff.readInt(Dummy)) return false; // Checksum #2
130
131   if (!Buff.readString(Name)) return false;
132   if (!Buff.readString(Filename)) return false;
133   if (!Buff.readInt(LineNumber)) return false;
134
135   // read blocks.
136   if (!Buff.readBlockTag()) {
137     errs() << "Block tag not found.\n";
138     return false;
139   }
140   uint32_t BlockCount;
141   if (!Buff.readInt(BlockCount)) return false;
142   for (uint32_t i = 0, e = BlockCount; i != e; ++i) {
143     if (!Buff.readInt(Dummy)) return false; // Block flags;
144     Blocks.push_back(new GCOVBlock(*this, i));
145   }
146
147   // read edges.
148   while (Buff.readEdgeTag()) {
149     uint32_t EdgeCount;
150     if (!Buff.readInt(EdgeCount)) return false;
151     EdgeCount = (EdgeCount - 1) / 2;
152     uint32_t BlockNo;
153     if (!Buff.readInt(BlockNo)) return false;
154     if (BlockNo >= BlockCount) {
155       errs() << "Unexpected block number.\n";
156       return false;
157     }
158     for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
159       uint32_t Dst;
160       if (!Buff.readInt(Dst)) return false;
161       GCOVEdge *Edge = new GCOVEdge(Blocks[BlockNo], Blocks[Dst]);
162       Edges.push_back(Edge);
163       Blocks[BlockNo]->addDstEdge(Edge);
164       Blocks[Dst]->addSrcEdge(Edge);
165       if (!Buff.readInt(Dummy)) return false; // Edge flag
166     }
167   }
168
169   // read line table.
170   while (Buff.readLineTag()) {
171     uint32_t LineTableLength;
172     if (!Buff.readInt(LineTableLength)) return false;
173     uint32_t EndPos = Buff.getCursor() + LineTableLength*4;
174     uint32_t BlockNo;
175     if (!Buff.readInt(BlockNo)) return false;
176     if (BlockNo >= BlockCount) {
177       errs() << "Unexpected block number.\n";
178       return false;
179     }
180     GCOVBlock *Block = Blocks[BlockNo];
181     if (!Buff.readInt(Dummy)) return false; // flag
182     while (Buff.getCursor() != (EndPos - 4)) {
183       StringRef F;
184       if (!Buff.readString(F)) return false;
185       if (F != Filename) {
186         errs() << "Multiple sources for a single basic block.\n";
187         return false;
188       }
189       if (Buff.getCursor() == (EndPos - 4)) break;
190       while (true) {
191         uint32_t Line;
192         if (!Buff.readInt(Line)) return false;
193         if (!Line) break;
194         Block->addLine(Line);
195       }
196     }
197     if (!Buff.readInt(Dummy)) return false; // flag
198   }
199   return true;
200 }
201
202 /// readGCDA - Read a function from the GCDA buffer. Return false if an error
203 /// occurs.
204 bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
205   uint32_t Dummy;
206   if (!Buff.readInt(Dummy)) return false; // Function header length
207   if (!Buff.readInt(Ident)) return false;
208   if (!Buff.readInt(Dummy)) return false; // Checksum #1
209   if (Version != GCOV::V402)
210     if (!Buff.readInt(Dummy)) return false; // Checksum #2
211
212   if (!Buff.readString(Name)) return false;
213
214   if (!Buff.readArcTag()) {
215     errs() << "Arc tag not found.\n";
216     return false;
217   }
218
219   uint32_t Count;
220   if (!Buff.readInt(Count)) return false;
221   Count /= 2;
222
223   // This for loop adds the counts for each block. A second nested loop is
224   // required to combine the edge counts that are contained in the GCDA file.
225   for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
226     // The last block is always reserved for exit block
227     if (BlockNo >= Blocks.size()-1) {
228       errs() << "Unexpected number of edges.\n";
229       return false;
230     }
231     GCOVBlock &Block = *Blocks[BlockNo];
232     for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End;
233            ++EdgeNo) {
234       if (Count == 0) {
235         errs() << "Unexpected number of edges.\n";
236         return false;
237       }
238       uint64_t ArcCount;
239       if (!Buff.readInt64(ArcCount)) return false;
240       Block.addCount(EdgeNo, ArcCount);
241       --Count;
242     }
243   }
244   return true;
245 }
246
247 /// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
248 void GCOVFunction::dump() const {
249   dbgs() <<  "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
250   for (SmallVectorImpl<GCOVBlock *>::const_iterator I = Blocks.begin(),
251          E = Blocks.end(); I != E; ++I)
252     (*I)->dump();
253 }
254
255 /// collectLineCounts - Collect line counts. This must be used after
256 /// reading .gcno and .gcda files.
257 void GCOVFunction::collectLineCounts(FileInfo &FI) {
258   for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
259          E = Blocks.end(); I != E; ++I)
260     (*I)->collectLineCounts(FI);
261 }
262
263 //===----------------------------------------------------------------------===//
264 // GCOVBlock implementation.
265
266 /// ~GCOVBlock - Delete GCOVBlock and its content.
267 GCOVBlock::~GCOVBlock() {
268   SrcEdges.clear();
269   DstEdges.clear();
270   Lines.clear();
271 }
272
273 /// addCount - Add to block counter while storing the edge count. If the
274 /// destination has no outgoing edges, also update that block's count too.
275 void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) {
276   assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid
277   DstEdges[DstEdgeNo]->Count = N;
278   Counter += N;
279   if (!DstEdges[DstEdgeNo]->Dst->getNumDstEdges())
280     DstEdges[DstEdgeNo]->Dst->Counter += N;
281 }
282
283 /// collectLineCounts - Collect line counts. This must be used after
284 /// reading .gcno and .gcda files.
285 void GCOVBlock::collectLineCounts(FileInfo &FI) {
286   for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
287          E = Lines.end(); I != E; ++I)
288     FI.addBlockLine(Parent.getFilename(), *I, this);
289 }
290
291 /// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
292 void GCOVBlock::dump() const {
293   dbgs() << "Block : " << Number << " Counter : " << Counter << "\n";
294   if (!SrcEdges.empty()) {
295     dbgs() << "\tSource Edges : ";
296     for (EdgeIterator I = SrcEdges.begin(), E = SrcEdges.end(); I != E; ++I) {
297       const GCOVEdge *Edge = *I;
298       dbgs() << Edge->Src->Number << " (" << Edge->Count << "), ";
299     }
300     dbgs() << "\n";
301   }
302   if (!DstEdges.empty()) {
303     dbgs() << "\tDestination Edges : ";
304     for (EdgeIterator I = DstEdges.begin(), E = DstEdges.end(); I != E; ++I) {
305       const GCOVEdge *Edge = *I;
306       dbgs() << Edge->Dst->Number << " (" << Edge->Count << "), ";
307     }
308     dbgs() << "\n";
309   }
310   if (!Lines.empty()) {
311     dbgs() << "\tLines : ";
312     for (SmallVectorImpl<uint32_t>::const_iterator I = Lines.begin(),
313            E = Lines.end(); I != E; ++I)
314       dbgs() << (*I) << ",";
315     dbgs() << "\n";
316   }
317 }
318
319 //===----------------------------------------------------------------------===//
320 // FileInfo implementation.
321
322 /// print -  Print source files with collected line count information.
323 void FileInfo::print(StringRef gcnoFile, StringRef gcdaFile) const {
324   for (StringMap<LineData>::const_iterator I = LineInfo.begin(),
325          E = LineInfo.end(); I != E; ++I) {
326     StringRef Filename = I->first();
327     OwningPtr<MemoryBuffer> Buff;
328     if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
329       errs() << Filename << ": " << ec.message() << "\n";
330       return;
331     }
332     StringRef AllLines = Buff->getBuffer();
333
334     std::string CovFilename = Filename.str() + ".llcov";
335     std::string ErrorInfo;
336     raw_fd_ostream OS(CovFilename.c_str(), ErrorInfo);
337     if (!ErrorInfo.empty())
338       errs() << ErrorInfo << "\n";
339
340     OS << "        -:    0:Source:" << Filename << "\n";
341     OS << "        -:    0:Graph:" << gcnoFile << "\n";
342     OS << "        -:    0:Data:" << gcdaFile << "\n";
343     OS << "        -:    0:Runs:" << RunCount << "\n";
344     OS << "        -:    0:Programs:" << ProgramCount << "\n";
345
346     const LineData &Line = I->second;
347     for (uint32_t i = 0; !AllLines.empty(); ++i) {
348       LineData::const_iterator BlocksIt = Line.find(i);
349
350       // Add up the block counts to form line counts.
351       if (BlocksIt != Line.end()) {
352         const BlockVector &Blocks = BlocksIt->second;
353         uint64_t LineCount = 0;
354         for (BlockVector::const_iterator I = Blocks.begin(), E = Blocks.end();
355                I != E; ++I) {
356           LineCount += (*I)->getCount();
357         }
358         if (LineCount == 0)
359           OS << "    #####:";
360         else
361           OS << format("%9" PRIu64 ":", LineCount);
362       } else {
363         OS << "        -:";
364       }
365       std::pair<StringRef, StringRef> P = AllLines.split('\n');
366       OS << format("%5u:", i+1) << P.first << "\n";
367       AllLines = P.second;
368     }
369   }
370 }