Support for reading program counts in llvm-cov.
[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/GCOV.h"
16 #include "llvm/ADT/OwningPtr.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/MemoryObject.h"
20 #include "llvm/Support/system_error.h"
21 using namespace llvm;
22
23 //===----------------------------------------------------------------------===//
24 // GCOVFile implementation.
25
26 /// ~GCOVFile - Delete GCOVFile and its content.
27 GCOVFile::~GCOVFile() {
28   DeleteContainerPointers(Functions);
29 }
30
31 /// isGCDAFile - Return true if Format identifies a .gcda file.
32 static bool isGCDAFile(GCOV::GCOVFormat Format) {
33   return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404;
34 }
35
36 /// isGCNOFile - Return true if Format identifies a .gcno file.
37 static bool isGCNOFile(GCOV::GCOVFormat Format) {
38   return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404;
39 }
40
41 /// read - Read GCOV buffer.
42 bool GCOVFile::read(GCOVBuffer &Buffer) {
43   GCOV::GCOVFormat Format = Buffer.readGCOVFormat();
44   if (Format == GCOV::InvalidGCOV)
45     return false;
46
47   if (isGCNOFile(Format)) {
48     while (true) {
49       GCOVFunction *GFun = new GCOVFunction();
50       if (!GFun->read(Buffer, Format))
51         break;
52       Functions.push_back(GFun);
53     }
54   }
55   else if (isGCDAFile(Format)) {
56     for (size_t i = 0, e = Functions.size(); i < e; ++i) {
57       bool ReadGCDA = Functions[i]->read(Buffer, Format);
58       (void)ReadGCDA;
59       assert(ReadGCDA && ".gcda data does not match .gcno data");
60     }
61     while (Buffer.readProgramTag())
62       ++ProgramCount;
63   }
64
65   return true;
66 }
67
68 /// dump - Dump GCOVFile content on standard out for debugging purposes.
69 void GCOVFile::dump() {
70   for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
71          E = Functions.end(); I != E; ++I)
72     (*I)->dump();
73 }
74
75 /// collectLineCounts - Collect line counts. This must be used after
76 /// reading .gcno and .gcda files.
77 void GCOVFile::collectLineCounts(FileInfo &FI) {
78   for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
79          E = Functions.end(); I != E; ++I) 
80     (*I)->collectLineCounts(FI);
81   FI.setProgramCount(ProgramCount);
82 }
83
84 //===----------------------------------------------------------------------===//
85 // GCOVFunction implementation.
86
87 /// ~GCOVFunction - Delete GCOVFunction and its content.
88 GCOVFunction::~GCOVFunction() {
89   DeleteContainerPointers(Blocks);
90 }
91
92 /// read - Read a function from the buffer. Return false if buffer cursor
93 /// does not point to a function tag.
94 bool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
95   if (!Buff.readFunctionTag())
96     return false;
97
98   Buff.readInt(); // Function header length
99   Ident = Buff.readInt(); 
100   Buff.readInt(); // Checksum #1
101   if (Format != GCOV::GCNO_402 && Format != GCOV::GCDA_402)
102     Buff.readInt(); // Checksum #2
103
104   Name = Buff.readString();
105   if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404)
106     Filename = Buff.readString();
107
108   if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) {
109     Buff.readArcTag();
110     uint32_t i = 0;
111     uint32_t Count = Buff.readInt() / 2;
112
113     // This for loop adds the counts for each block. A second nested loop is
114     // required to combine the edge counts that are contained in the GCDA file.
115     for (uint32_t Line = 0; i < Count; ++Line) {
116       GCOVBlock &Block = *Blocks[Line];
117       for (size_t Edge = 0, End = Block.getNumEdges(); Edge < End; ++Edge) {
118         assert(i < Count && "Unexpected number of Edges!");
119         Block.addCount(Buff.readInt64());
120         ++i;
121       }
122     }
123     return true;
124   }
125
126   LineNumber = Buff.readInt();
127
128   // read blocks.
129   bool BlockTagFound = Buff.readBlockTag();
130   (void)BlockTagFound;
131   assert(BlockTagFound && "Block Tag not found!");
132   uint32_t BlockCount = Buff.readInt();
133   for (uint32_t i = 0, e = BlockCount; i != e; ++i) {
134     Buff.readInt(); // Block flags;
135     Blocks.push_back(new GCOVBlock(i));
136   }
137
138   // read edges.
139   while (Buff.readEdgeTag()) {
140     uint32_t EdgeCount = (Buff.readInt() - 1) / 2;
141     uint32_t BlockNo = Buff.readInt();
142     assert(BlockNo < BlockCount && "Unexpected Block number!");
143     for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
144       Blocks[BlockNo]->addEdge(Buff.readInt());
145       Buff.readInt(); // Edge flag
146     }
147   }
148
149   // read line table.
150   while (Buff.readLineTag()) {
151     uint32_t LineTableLength = Buff.readInt();
152     uint32_t EndPos = Buff.getCursor() + LineTableLength*4;
153     uint32_t BlockNo = Buff.readInt();
154     assert(BlockNo < BlockCount && "Unexpected Block number!");
155     GCOVBlock *Block = Blocks[BlockNo];
156     Buff.readInt(); // flag
157     while (Buff.getCursor() != (EndPos - 4)) {
158       StringRef Filename = Buff.readString();
159       if (Buff.getCursor() == (EndPos - 4)) break;
160       while (uint32_t L = Buff.readInt())
161         Block->addLine(Filename, L);
162     }
163     Buff.readInt(); // flag
164   }
165   return true;
166 }
167
168 /// dump - Dump GCOVFunction content on standard out for debugging purposes.
169 void GCOVFunction::dump() {
170   outs() <<  "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
171   for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
172          E = Blocks.end(); I != E; ++I)
173     (*I)->dump();
174 }
175
176 /// collectLineCounts - Collect line counts. This must be used after
177 /// reading .gcno and .gcda files.
178 void GCOVFunction::collectLineCounts(FileInfo &FI) {
179   for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
180          E = Blocks.end(); I != E; ++I)
181     (*I)->collectLineCounts(FI);
182 }
183
184 //===----------------------------------------------------------------------===//
185 // GCOVBlock implementation.
186
187 /// ~GCOVBlock - Delete GCOVBlock and its content.
188 GCOVBlock::~GCOVBlock() {
189   Edges.clear();
190   DeleteContainerSeconds(Lines);
191 }
192
193 void GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) {
194   GCOVLines *&LinesForFile = Lines[Filename];
195   if (!LinesForFile)
196     LinesForFile = new GCOVLines();
197   LinesForFile->add(LineNo);
198 }
199
200 /// collectLineCounts - Collect line counts. This must be used after
201 /// reading .gcno and .gcda files.
202 void GCOVBlock::collectLineCounts(FileInfo &FI) {
203   for (StringMap<GCOVLines *>::iterator I = Lines.begin(),
204          E = Lines.end(); I != E; ++I)
205     I->second->collectLineCounts(FI, I->first(), Counter);
206 }
207
208 /// dump - Dump GCOVBlock content on standard out for debugging purposes.
209 void GCOVBlock::dump() {
210   outs() << "Block : " << Number << " Counter : " << Counter << "\n";
211   if (!Edges.empty()) {
212     outs() << "\tEdges : ";
213     for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end();
214          I != E; ++I)
215       outs() << (*I) << ",";
216     outs() << "\n";
217   }
218   if (!Lines.empty()) {
219     outs() << "\tLines : ";
220     for (StringMap<GCOVLines *>::iterator LI = Lines.begin(),
221            LE = Lines.end(); LI != LE; ++LI) {
222       outs() << LI->first() << " -> ";
223       LI->second->dump();
224       outs() << "\n";
225     }
226   }
227 }
228
229 //===----------------------------------------------------------------------===//
230 // GCOVLines implementation.
231
232 /// collectLineCounts - Collect line counts. This must be used after
233 /// reading .gcno and .gcda files.
234 void GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename, 
235                                   uint64_t Count) {
236   for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
237          E = Lines.end(); I != E; ++I)
238     FI.addLineCount(Filename, *I, Count);
239 }
240
241 /// dump - Dump GCOVLines content on standard out for debugging purposes.
242 void GCOVLines::dump() {
243   for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
244          E = Lines.end(); I != E; ++I)
245     outs() << (*I) << ",";
246 }
247
248 //===----------------------------------------------------------------------===//
249 // FileInfo implementation.
250
251 /// print -  Print source files with collected line count information.
252 void FileInfo::print(StringRef gcnoFile, StringRef gcdaFile) {
253   for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end();
254        I != E; ++I) {
255     StringRef Filename = I->first();
256     outs() << "        -:    0:Source:" << Filename << "\n";
257     outs() << "        -:    0:Graph:" << gcnoFile << "\n";
258     outs() << "        -:    0:Data:" << gcdaFile << "\n";
259     outs() << "        -:    0:Programs:" << ProgramCount << "\n";
260     LineCounts &L = LineInfo[Filename];
261     OwningPtr<MemoryBuffer> Buff;
262     if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
263       errs() << Filename << ": " << ec.message() << "\n";
264       return;
265     }
266     StringRef AllLines = Buff.take()->getBuffer();
267     uint32_t i = 0;
268     while (!AllLines.empty()) {
269       if (L.find(i) != L.end()) {
270         if (L[i] == 0)
271           outs() << "    #####:";
272         else
273           outs() << format("%9lu:", L[i]);
274       } else {
275         outs() << "        -:";
276       }
277       std::pair<StringRef, StringRef> P = AllLines.split('\n');
278       if (AllLines != P.first)
279         outs() << format("%5u:", i+1) << P.first;
280       outs() << "\n";
281       AllLines = P.second;
282       ++i;
283     }
284   }
285 }
286