llvm-cov: Split up reading of GCNO and GCDA files.
[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 /// isGCDAFile - Return true if Format identifies a .gcda file.
33 static bool isGCDAFile(GCOV::GCOVFormat Format) {
34   return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404;
35 }
36
37 /// isGCNOFile - Return true if Format identifies a .gcno file.
38 static bool isGCNOFile(GCOV::GCOVFormat Format) {
39   return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404;
40 }
41
42 /// read - Read GCOV buffer.
43 bool GCOVFile::read(GCOVBuffer &Buffer) {
44   GCOV::GCOVFormat Format = Buffer.readGCOVFormat();
45   if (Format == GCOV::InvalidGCOV)
46     return false;
47
48   if (isGCNOFile(Format)) {
49     if (!Buffer.readInt(Checksum)) return false;
50     while (true) {
51       if (!Buffer.readFunctionTag()) break;
52       GCOVFunction *GFun = new GCOVFunction();
53       if (!GFun->readGCNO(Buffer, Format))
54         return false;
55       Functions.push_back(GFun);
56     }
57   } else if (isGCDAFile(Format)) {
58     uint32_t Checksum2;
59     if (!Buffer.readInt(Checksum2)) return false;
60     if (Checksum != Checksum2) {
61       errs() << "File checksum does not match.\n";
62       return false;
63     }
64     for (size_t i = 0, e = Functions.size(); i < e; ++i) {
65       if (!Buffer.readFunctionTag()) {
66         errs() << "Unexpected number of functions.\n";
67         return false;
68       }
69       if (!Functions[i]->readGCDA(Buffer, Format))
70         return false;
71     }
72     if (Buffer.readObjectTag()) {
73       uint32_t Length;
74       uint32_t Dummy;
75       if (!Buffer.readInt(Length)) return false;
76       if (!Buffer.readInt(Dummy)) return false; // checksum
77       if (!Buffer.readInt(Dummy)) return false; // num
78       if (!Buffer.readInt(RunCount)) return false;;
79       Buffer.advanceCursor(Length-3);
80     }
81     while (Buffer.readProgramTag()) {
82       uint32_t Length;
83       if (!Buffer.readInt(Length)) return false;
84       Buffer.advanceCursor(Length);
85       ++ProgramCount;
86     }
87   }
88
89   return true;
90 }
91
92 /// dump - Dump GCOVFile content to dbgs() for debugging purposes.
93 void GCOVFile::dump() const {
94   for (SmallVectorImpl<GCOVFunction *>::const_iterator I = Functions.begin(),
95          E = Functions.end(); I != E; ++I)
96     (*I)->dump();
97 }
98
99 /// collectLineCounts - Collect line counts. This must be used after
100 /// reading .gcno and .gcda files.
101 void GCOVFile::collectLineCounts(FileInfo &FI) {
102   for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
103          E = Functions.end(); I != E; ++I)
104     (*I)->collectLineCounts(FI);
105   FI.setRunCount(RunCount);
106   FI.setProgramCount(ProgramCount);
107 }
108
109 //===----------------------------------------------------------------------===//
110 // GCOVFunction implementation.
111
112 /// ~GCOVFunction - Delete GCOVFunction and its content.
113 GCOVFunction::~GCOVFunction() {
114   DeleteContainerPointers(Blocks);
115 }
116
117 /// readGCNO - Read a function from the GCNO buffer. Return false if an error
118 /// occurs.
119 bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
120   uint32_t Dummy;
121   if (!Buff.readInt(Dummy)) return false; // Function header length
122   if (!Buff.readInt(Ident)) return false;
123   if (!Buff.readInt(Dummy)) return false; // Checksum #1
124   if (Format != GCOV::GCNO_402)
125     if (!Buff.readInt(Dummy)) return false; // Checksum #2
126
127   if (!Buff.readString(Name)) return false;
128   if (!Buff.readString(Filename)) return false;
129   if (!Buff.readInt(LineNumber)) return false;
130
131   // read blocks.
132   if (!Buff.readBlockTag()) {
133     errs() << "Block tag not found.\n";
134     return false;
135   }
136   uint32_t BlockCount;
137   if (!Buff.readInt(BlockCount)) return false;
138   for (uint32_t i = 0, e = BlockCount; i != e; ++i) {
139     if (!Buff.readInt(Dummy)) return false; // Block flags;
140     Blocks.push_back(new GCOVBlock(*this, i));
141   }
142
143   // read edges.
144   while (Buff.readEdgeTag()) {
145     uint32_t EdgeCount;
146     if (!Buff.readInt(EdgeCount)) return false;
147     EdgeCount = (EdgeCount - 1) / 2;
148     uint32_t BlockNo;
149     if (!Buff.readInt(BlockNo)) return false;
150     if (BlockNo >= BlockCount) {
151       errs() << "Unexpected block number.\n";
152       return false;
153     }
154     for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
155       uint32_t Dst;
156       if (!Buff.readInt(Dst)) return false;
157       Blocks[BlockNo]->addEdge(Dst);
158       if (!Buff.readInt(Dummy)) return false; // Edge flag
159     }
160   }
161
162   // read line table.
163   while (Buff.readLineTag()) {
164     uint32_t LineTableLength;
165     if (!Buff.readInt(LineTableLength)) return false;
166     uint32_t EndPos = Buff.getCursor() + LineTableLength*4;
167     uint32_t BlockNo;
168     if (!Buff.readInt(BlockNo)) return false;
169     if (BlockNo >= BlockCount) {
170       errs() << "Unexpected block number.\n";
171       return false;
172     }
173     GCOVBlock *Block = Blocks[BlockNo];
174     if (!Buff.readInt(Dummy)) return false; // flag
175     while (Buff.getCursor() != (EndPos - 4)) {
176       StringRef F;
177       if (!Buff.readString(F)) return false;
178       if (F != Filename) {
179         errs() << "Multiple sources for a single basic block.\n";
180         return false;
181       }
182       if (Buff.getCursor() == (EndPos - 4)) break;
183       while (true) {
184         uint32_t Line;
185         if (!Buff.readInt(Line)) return false;
186         if (!Line) break;
187         Block->addLine(Line);
188       }
189     }
190     if (!Buff.readInt(Dummy)) return false; // flag
191   }
192   return true;
193 }
194
195 /// readGCDA - Read a function from the GCDA buffer. Return false if an error
196 /// occurs.
197 bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
198   uint32_t Dummy;
199   if (!Buff.readInt(Dummy)) return false; // Function header length
200   if (!Buff.readInt(Ident)) return false;
201   if (!Buff.readInt(Dummy)) return false; // Checksum #1
202   if (Format != GCOV::GCDA_402)
203     if (!Buff.readInt(Dummy)) return false; // Checksum #2
204
205   if (!Buff.readString(Name)) return false;
206
207   if (!Buff.readArcTag()) {
208     errs() << "Arc tag not found.\n";
209     return false;
210   }
211   uint32_t Count;
212   if (!Buff.readInt(Count)) return false;
213   Count /= 2;
214
215   // This for loop adds the counts for each block. A second nested loop is
216   // required to combine the edge counts that are contained in the GCDA file.
217   for (uint32_t Line = 0; Count > 0; ++Line) {
218     if (Line >= Blocks.size()) {
219       errs() << "Unexpected number of edges.\n";
220       return false;
221     }
222     GCOVBlock &Block = *Blocks[Line];
223     for (size_t Edge = 0, End = Block.getNumEdges(); Edge < End; ++Edge) {
224       if (Count == 0) {
225         errs() << "Unexpected number of edges.\n";
226         return false;
227       }
228       uint64_t ArcCount;
229       if (!Buff.readInt64(ArcCount)) return false;
230       Block.addCount(ArcCount);
231       --Count;
232     }
233   }
234   return true;
235 }
236
237 /// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
238 void GCOVFunction::dump() const {
239   dbgs() <<  "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
240   for (SmallVectorImpl<GCOVBlock *>::const_iterator I = Blocks.begin(),
241          E = Blocks.end(); I != E; ++I)
242     (*I)->dump();
243 }
244
245 /// collectLineCounts - Collect line counts. This must be used after
246 /// reading .gcno and .gcda files.
247 void GCOVFunction::collectLineCounts(FileInfo &FI) {
248   for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
249          E = Blocks.end(); I != E; ++I)
250     (*I)->collectLineCounts(FI);
251 }
252
253 //===----------------------------------------------------------------------===//
254 // GCOVBlock implementation.
255
256 /// ~GCOVBlock - Delete GCOVBlock and its content.
257 GCOVBlock::~GCOVBlock() {
258   Edges.clear();
259   Lines.clear();
260 }
261
262 /// collectLineCounts - Collect line counts. This must be used after
263 /// reading .gcno and .gcda files.
264 void GCOVBlock::collectLineCounts(FileInfo &FI) {
265   for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
266          E = Lines.end(); I != E; ++I)
267     FI.addLineCount(Parent.getFilename(), *I, Counter);
268 }
269
270 /// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
271 void GCOVBlock::dump() const {
272   dbgs() << "Block : " << Number << " Counter : " << Counter << "\n";
273   if (!Edges.empty()) {
274     dbgs() << "\tEdges : ";
275     for (SmallVectorImpl<uint32_t>::const_iterator I = Edges.begin(), E = Edges.end();
276          I != E; ++I)
277       dbgs() << (*I) << ",";
278     dbgs() << "\n";
279   }
280   if (!Lines.empty()) {
281     dbgs() << "\tLines : ";
282     for (SmallVectorImpl<uint32_t>::const_iterator I = Lines.begin(),
283            E = Lines.end(); I != E; ++I)
284       dbgs() << (*I) << ",";
285     dbgs() << "\n";
286   }
287 }
288
289 //===----------------------------------------------------------------------===//
290 // FileInfo implementation.
291
292 /// print -  Print source files with collected line count information.
293 void FileInfo::print(raw_fd_ostream &OS, StringRef gcnoFile,
294                      StringRef gcdaFile) const {
295   for (StringMap<LineCounts>::const_iterator I = LineInfo.begin(),
296          E = LineInfo.end(); I != E; ++I) {
297     StringRef Filename = I->first();
298     OwningPtr<MemoryBuffer> Buff;
299     if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
300       errs() << Filename << ": " << ec.message() << "\n";
301       return;
302     }
303     StringRef AllLines = Buff->getBuffer();
304
305     OS << "        -:    0:Source:" << Filename << "\n";
306     OS << "        -:    0:Graph:" << gcnoFile << "\n";
307     OS << "        -:    0:Data:" << gcdaFile << "\n";
308     OS << "        -:    0:Runs:" << RunCount << "\n";
309     OS << "        -:    0:Programs:" << ProgramCount << "\n";
310
311     const LineCounts &L = I->second;
312     uint32_t i = 0;
313     while (!AllLines.empty()) {
314       LineCounts::const_iterator CountIt = L.find(i);
315       if (CountIt != L.end()) {
316         if (CountIt->second == 0)
317           OS << "    #####:";
318         else
319           OS << format("%9" PRIu64 ":", CountIt->second);
320       } else {
321         OS << "        -:";
322       }
323       std::pair<StringRef, StringRef> P = AllLines.split('\n');
324       if (AllLines != P.first)
325         OS << format("%5u:", i+1) << P.first;
326       OS << "\n";
327       AllLines = P.second;
328       ++i;
329     }
330   }
331 }