1249259Sdim//===- GCOVr.cpp - LLVM coverage tool -------------------------------------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// GCOV implements the interface to read and write coverage files that use
11249259Sdim// 'gcov' format.
12249259Sdim//
13249259Sdim//===----------------------------------------------------------------------===//
14249259Sdim
15249259Sdim#include "llvm/Support/GCOV.h"
16249259Sdim#include "llvm/ADT/OwningPtr.h"
17249259Sdim#include "llvm/ADT/STLExtras.h"
18249259Sdim#include "llvm/Support/MemoryObject.h"
19249259Sdim#include "llvm/Support/system_error.h"
20249259Sdimusing namespace llvm;
21249259Sdim
22249259Sdim//===----------------------------------------------------------------------===//
23249259Sdim// GCOVFile implementation.
24249259Sdim
25249259Sdim/// ~GCOVFile - Delete GCOVFile and its content.
26249259SdimGCOVFile::~GCOVFile() {
27249259Sdim  DeleteContainerPointers(Functions);
28249259Sdim}
29249259Sdim
30249259Sdim/// isGCDAFile - Return true if Format identifies a .gcda file.
31249259Sdimstatic bool isGCDAFile(GCOV::GCOVFormat Format) {
32249259Sdim  return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404;
33249259Sdim}
34249259Sdim
35249259Sdim/// isGCNOFile - Return true if Format identifies a .gcno file.
36249259Sdimstatic bool isGCNOFile(GCOV::GCOVFormat Format) {
37249259Sdim  return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404;
38249259Sdim}
39249259Sdim
40249259Sdim/// read - Read GCOV buffer.
41249259Sdimbool GCOVFile::read(GCOVBuffer &Buffer) {
42249259Sdim  GCOV::GCOVFormat Format = Buffer.readGCOVFormat();
43249259Sdim  if (Format == GCOV::InvalidGCOV)
44249259Sdim    return false;
45249259Sdim
46249259Sdim  unsigned i = 0;
47249259Sdim  while (1) {
48249259Sdim    GCOVFunction *GFun = NULL;
49249259Sdim    if (isGCDAFile(Format)) {
50249259Sdim      // Use existing function while reading .gcda file.
51249259Sdim      assert(i < Functions.size() && ".gcda data does not match .gcno data");
52249259Sdim      GFun = Functions[i];
53249259Sdim    } else if (isGCNOFile(Format)){
54249259Sdim      GFun = new GCOVFunction();
55249259Sdim      Functions.push_back(GFun);
56249259Sdim    }
57249259Sdim    if (!GFun || !GFun->read(Buffer, Format))
58249259Sdim      break;
59249259Sdim    ++i;
60249259Sdim  }
61249259Sdim  return true;
62249259Sdim}
63249259Sdim
64249259Sdim/// dump - Dump GCOVFile content on standard out for debugging purposes.
65249259Sdimvoid GCOVFile::dump() {
66249259Sdim  for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(),
67249259Sdim         E = Functions.end(); I != E; ++I)
68249259Sdim    (*I)->dump();
69249259Sdim}
70249259Sdim
71249259Sdim/// collectLineCounts - Collect line counts. This must be used after
72249259Sdim/// reading .gcno and .gcda files.
73249259Sdimvoid GCOVFile::collectLineCounts(FileInfo &FI) {
74249259Sdim  for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(),
75249259Sdim         E = Functions.end(); I != E; ++I)
76249259Sdim    (*I)->collectLineCounts(FI);
77249259Sdim  FI.print();
78249259Sdim}
79249259Sdim
80249259Sdim//===----------------------------------------------------------------------===//
81249259Sdim// GCOVFunction implementation.
82249259Sdim
83249259Sdim/// ~GCOVFunction - Delete GCOVFunction and its content.
84249259SdimGCOVFunction::~GCOVFunction() {
85249259Sdim  DeleteContainerPointers(Blocks);
86249259Sdim}
87249259Sdim
88249259Sdim/// read - Read a aunction from the buffer. Return false if buffer cursor
89249259Sdim/// does not point to a function tag.
90249259Sdimbool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
91249259Sdim  if (!Buff.readFunctionTag())
92249259Sdim    return false;
93249259Sdim
94249259Sdim  Buff.readInt(); // Function header length
95249259Sdim  Ident = Buff.readInt();
96249259Sdim  Buff.readInt(); // Checksum #1
97249259Sdim  if (Format != GCOV::GCNO_402)
98249259Sdim    Buff.readInt(); // Checksum #2
99249259Sdim
100249259Sdim  Name = Buff.readString();
101249259Sdim  if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404)
102249259Sdim    Filename = Buff.readString();
103249259Sdim
104249259Sdim  if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) {
105249259Sdim    Buff.readArcTag();
106249259Sdim    uint32_t Count = Buff.readInt() / 2;
107249259Sdim    for (unsigned i = 0, e = Count; i != e; ++i) {
108249259Sdim      Blocks[i]->addCount(Buff.readInt64());
109249259Sdim    }
110249259Sdim    return true;
111249259Sdim  }
112249259Sdim
113249259Sdim  LineNumber = Buff.readInt();
114249259Sdim
115249259Sdim  // read blocks.
116249259Sdim  bool BlockTagFound = Buff.readBlockTag();
117249259Sdim  (void)BlockTagFound;
118249259Sdim  assert(BlockTagFound && "Block Tag not found!");
119249259Sdim  uint32_t BlockCount = Buff.readInt();
120249259Sdim  for (int i = 0, e = BlockCount; i != e; ++i) {
121249259Sdim    Buff.readInt(); // Block flags;
122249259Sdim    Blocks.push_back(new GCOVBlock(i));
123249259Sdim  }
124249259Sdim
125249259Sdim  // read edges.
126249259Sdim  while (Buff.readEdgeTag()) {
127249259Sdim    uint32_t EdgeCount = (Buff.readInt() - 1) / 2;
128249259Sdim    uint32_t BlockNo = Buff.readInt();
129249259Sdim    assert(BlockNo < BlockCount && "Unexpected Block number!");
130249259Sdim    for (int i = 0, e = EdgeCount; i != e; ++i) {
131249259Sdim      Blocks[BlockNo]->addEdge(Buff.readInt());
132249259Sdim      Buff.readInt(); // Edge flag
133249259Sdim    }
134249259Sdim  }
135249259Sdim
136249259Sdim  // read line table.
137249259Sdim  while (Buff.readLineTag()) {
138249259Sdim    uint32_t LineTableLength = Buff.readInt();
139249259Sdim    uint32_t Size = Buff.getCursor() + LineTableLength*4;
140249259Sdim    uint32_t BlockNo = Buff.readInt();
141249259Sdim    assert(BlockNo < BlockCount && "Unexpected Block number!");
142249259Sdim    GCOVBlock *Block = Blocks[BlockNo];
143249259Sdim    Buff.readInt(); // flag
144249259Sdim    while (Buff.getCursor() != (Size - 4)) {
145249259Sdim      StringRef Filename = Buff.readString();
146249259Sdim      if (Buff.getCursor() == (Size - 4)) break;
147249259Sdim      while (uint32_t L = Buff.readInt())
148249259Sdim        Block->addLine(Filename, L);
149249259Sdim    }
150249259Sdim    Buff.readInt(); // flag
151249259Sdim  }
152249259Sdim  return true;
153249259Sdim}
154249259Sdim
155249259Sdim/// dump - Dump GCOVFunction content on standard out for debugging purposes.
156249259Sdimvoid GCOVFunction::dump() {
157249259Sdim  outs() <<  "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
158249259Sdim  for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(),
159249259Sdim         E = Blocks.end(); I != E; ++I)
160249259Sdim    (*I)->dump();
161249259Sdim}
162249259Sdim
163249259Sdim/// collectLineCounts - Collect line counts. This must be used after
164249259Sdim/// reading .gcno and .gcda files.
165249259Sdimvoid GCOVFunction::collectLineCounts(FileInfo &FI) {
166249259Sdim  for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(),
167249259Sdim         E = Blocks.end(); I != E; ++I)
168249259Sdim    (*I)->collectLineCounts(FI);
169249259Sdim}
170249259Sdim
171249259Sdim//===----------------------------------------------------------------------===//
172249259Sdim// GCOVBlock implementation.
173249259Sdim
174249259Sdim/// ~GCOVBlock - Delete GCOVBlock and its content.
175249259SdimGCOVBlock::~GCOVBlock() {
176249259Sdim  Edges.clear();
177249259Sdim  DeleteContainerSeconds(Lines);
178249259Sdim}
179249259Sdim
180249259Sdimvoid GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) {
181249259Sdim  GCOVLines *&LinesForFile = Lines[Filename];
182249259Sdim  if (!LinesForFile)
183249259Sdim    LinesForFile = new GCOVLines();
184249259Sdim  LinesForFile->add(LineNo);
185249259Sdim}
186249259Sdim
187249259Sdim/// collectLineCounts - Collect line counts. This must be used after
188249259Sdim/// reading .gcno and .gcda files.
189249259Sdimvoid GCOVBlock::collectLineCounts(FileInfo &FI) {
190249259Sdim  for (StringMap<GCOVLines *>::iterator I = Lines.begin(),
191249259Sdim         E = Lines.end(); I != E; ++I)
192249259Sdim    I->second->collectLineCounts(FI, I->first(), Counter);
193249259Sdim}
194249259Sdim
195249259Sdim/// dump - Dump GCOVBlock content on standard out for debugging purposes.
196249259Sdimvoid GCOVBlock::dump() {
197249259Sdim  outs() << "Block : " << Number << " Counter : " << Counter << "\n";
198249259Sdim  if (!Edges.empty()) {
199249259Sdim    outs() << "\tEdges : ";
200249259Sdim    for (SmallVector<uint32_t, 16>::iterator I = Edges.begin(), E = Edges.end();
201249259Sdim         I != E; ++I)
202249259Sdim      outs() << (*I) << ",";
203249259Sdim    outs() << "\n";
204249259Sdim  }
205249259Sdim  if (!Lines.empty()) {
206249259Sdim    outs() << "\tLines : ";
207249259Sdim    for (StringMap<GCOVLines *>::iterator LI = Lines.begin(),
208249259Sdim           LE = Lines.end(); LI != LE; ++LI) {
209249259Sdim      outs() << LI->first() << " -> ";
210249259Sdim      LI->second->dump();
211249259Sdim      outs() << "\n";
212249259Sdim    }
213249259Sdim  }
214249259Sdim}
215249259Sdim
216249259Sdim//===----------------------------------------------------------------------===//
217249259Sdim// GCOVLines implementation.
218249259Sdim
219249259Sdim/// collectLineCounts - Collect line counts. This must be used after
220249259Sdim/// reading .gcno and .gcda files.
221249259Sdimvoid GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename,
222249259Sdim                                  uint32_t Count) {
223249259Sdim  for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(),
224249259Sdim         E = Lines.end(); I != E; ++I)
225249259Sdim    FI.addLineCount(Filename, *I, Count);
226249259Sdim}
227249259Sdim
228249259Sdim/// dump - Dump GCOVLines content on standard out for debugging purposes.
229249259Sdimvoid GCOVLines::dump() {
230249259Sdim  for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(),
231249259Sdim         E = Lines.end(); I != E; ++I)
232249259Sdim    outs() << (*I) << ",";
233249259Sdim}
234249259Sdim
235249259Sdim//===----------------------------------------------------------------------===//
236249259Sdim// FileInfo implementation.
237249259Sdim
238249259Sdim/// addLineCount - Add line count for the given line number in a file.
239249259Sdimvoid FileInfo::addLineCount(StringRef Filename, uint32_t Line, uint32_t Count) {
240249259Sdim  if (LineInfo.find(Filename) == LineInfo.end()) {
241249259Sdim    OwningPtr<MemoryBuffer> Buff;
242249259Sdim    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
243249259Sdim      errs() << Filename << ": " << ec.message() << "\n";
244249259Sdim      return;
245249259Sdim    }
246249259Sdim    StringRef AllLines = Buff.take()->getBuffer();
247249259Sdim    LineCounts L(AllLines.count('\n')+2);
248249259Sdim    L[Line-1] = Count;
249249259Sdim    LineInfo[Filename] = L;
250249259Sdim    return;
251249259Sdim  }
252249259Sdim  LineCounts &L = LineInfo[Filename];
253249259Sdim  L[Line-1] = Count;
254249259Sdim}
255249259Sdim
256249259Sdim/// print -  Print source files with collected line count information.
257249259Sdimvoid FileInfo::print() {
258249259Sdim  for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end();
259249259Sdim       I != E; ++I) {
260249259Sdim    StringRef Filename = I->first();
261249259Sdim    outs() << Filename << "\n";
262249259Sdim    LineCounts &L = LineInfo[Filename];
263249259Sdim    OwningPtr<MemoryBuffer> Buff;
264249259Sdim    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
265249259Sdim      errs() << Filename << ": " << ec.message() << "\n";
266249259Sdim      return;
267249259Sdim    }
268249259Sdim    StringRef AllLines = Buff.take()->getBuffer();
269249259Sdim    for (unsigned i = 0, e = L.size(); i != e; ++i) {
270249259Sdim      if (L[i])
271249259Sdim        outs() << L[i] << ":\t";
272249259Sdim      else
273249259Sdim        outs() << " :\t";
274249259Sdim      std::pair<StringRef, StringRef> P = AllLines.split('\n');
275249259Sdim      if (AllLines != P.first)
276249259Sdim        outs() << P.first;
277249259Sdim      outs() << "\n";
278249259Sdim      AllLines = P.second;
279249259Sdim    }
280249259Sdim  }
281249259Sdim}
282249259Sdim
283249259Sdim
284