llvm.org GIT mirror llvm / d02c42b
Introduce llvm-cov. Add llvm-cov skeleton. It has initial support to read coverage info generated by GCOVProfiling.cpp. Today, you can do prompt> clang a.c -ftest-coverage -fprofile-arcs -o a prompt> ./a prompt> llvm-cov -gcno a.gcno -gcda a.gcda a.c : #include "a.h" : : int main() { : int i = 0; : if (i) { 1: int j = 0; 1: j = 1; 1: } else { : int k = 1; : k = 2; : } 1: return 0; : } : : git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@140712 91177308-0d34-0410-b5e6-96231b3b80d8 Devang Patel 8 years ago
6 changed file(s) with 609 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
2525 lli llvm-extract llvm-mc \
2626 bugpoint llvm-bcanalyzer llvm-stub \
2727 llvm-diff macho-dump llvm-objdump \
28 llvm-rtdyld llvm-dwarfdump
28 llvm-rtdyld llvm-dwarfdump llvm-cov
2929
3030 # Let users override the set of tools to build from the command line.
3131 ifdef ONLY_TOOLS
0 set(LLVM_LINK_COMPONENTS instrumentation )
1
2 add_llvm_tool(llvm-cov
3 GCOVReader.cpp
4 llvm-cov.cpp
5 )
0 //===- tools/llvm-cov/GCOVReader.cpp - LLVM coverage tool -----------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // GCOVReader implements the interface to read coverage files that use 'gcov'
10 // format.
11 //
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "GCOVReader.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/OwningPtr.h"
18 #include "llvm/Support/MemoryObject.h"
19 #include "llvm/Support/system_error.h"
20 using namespace llvm;
21
22 //===----------------------------------------------------------------------===//
23 // GCOVFile implementation.
24
25 /// ~GCOVFile - Delete GCOVFile and its content.
26 GCOVFile::~GCOVFile() {
27 DeleteContainerPointers(Functions);
28 }
29
30 /// read - Read GCOV buffer.
31 bool GCOVFile::read(GCOVBuffer &Buffer) {
32 Format = Buffer.readGCOVFormat();
33 if (Format == InvalidGCOV)
34 return false;
35
36 unsigned i = 0;
37 while(1) {
38 GCOVFunction *GFun = NULL;
39 if(Format == GCDA_402 || Format == GCDA_404) {
40 if (i < Functions.size())
41 GFun = Functions[i];
42 } else
43 GFun = new GCOVFunction();
44
45 if (GFun && GFun->read(Buffer, Format)) {
46 if(Format == GCNO_402 || Format == GCNO_404)
47 Functions.push_back(GFun);
48 }
49 else {
50 delete GFun;
51 break;
52 }
53 ++i;
54 }
55 return true;
56 }
57
58 /// dump - Dump GCOVFile content on standard out for debugging purposes.
59 void GCOVFile::dump() {
60 for (SmallVector::iterator I = Functions.begin(),
61 E = Functions.end(); I != E; ++I)
62 (*I)->dump();
63 }
64
65 /// collectLineCounts - Collect line counts. This must be used after
66 /// reading .gcno and .gcda files.
67 void GCOVFile::collectLineCounts(FileInfo &FI) {
68 for (SmallVector::iterator I = Functions.begin(),
69 E = Functions.end(); I != E; ++I)
70 (*I)->collectLineCounts(FI);
71 FI.print();
72 }
73
74 //===----------------------------------------------------------------------===//
75 // GCOVFunction implementation.
76
77 /// ~GCOVFunction - Delete GCOVFunction and its content.
78 GCOVFunction::~GCOVFunction() {
79 DeleteContainerPointers(Blocks);
80 }
81
82 /// read - Read a aunction from the buffer. Return false if buffer cursor
83 /// does not point to a function tag.
84 bool GCOVFunction::read(GCOVBuffer &Buff, GCOVFormat Format) {
85 if (!Buff.readFunctionTag())
86 return false;
87
88 Buff.readInt(); // Function header length
89 Ident = Buff.readInt();
90 Buff.readInt(); // Checksum #1
91 if (Format != GCNO_402)
92 Buff.readInt(); // Checksum #2
93
94 Name = Buff.readString();
95 if(Format == GCNO_402 || Format == GCNO_404)
96 Filename = Buff.readString();
97
98 if(Format == GCDA_402 || Format == GCDA_404) {
99 Buff.readArcTag();
100 uint32_t Count = Buff.readInt() / 2;
101 for (unsigned i = 0, e = Count; i != e; ++i) {
102 Blocks[i]->addCount(Buff.readInt64());
103 }
104 return true;;
105 }
106
107 LineNumber = Buff.readInt();
108
109 // read blocks.
110 assert (Buff.readBlockTag() && "Block Tag not found!");
111 uint32_t BlockCount = Buff.readInt();
112 for (int i = 0, e = BlockCount; i != e; ++i) {
113 Buff.readInt(); // Block flags;
114 Blocks.push_back(new GCOVBlock(i));
115 }
116
117 // read edges.
118 while (Buff.readEdgeTag()) {
119 uint32_t EdgeCount = (Buff.readInt() - 1) / 2;
120 uint32_t BlockNo = Buff.readInt();
121 assert (BlockNo < BlockCount && "Unexpected Block number!");
122 for (int i = 0, e = EdgeCount; i != e; ++i) {
123 Blocks[BlockNo]->addEdge(Buff.readInt());
124 Buff.readInt(); // Edge flag
125 }
126 }
127
128 // read line table.
129 while (Buff.readLineTag()) {
130 uint32_t LineTableLength = Buff.readInt();
131 uint32_t Size = Buff.getCursor() + LineTableLength*4;
132 uint32_t BlockNo = Buff.readInt();
133 assert (BlockNo < BlockCount && "Unexpected Block number!");
134 GCOVBlock *Block = Blocks[BlockNo];
135 Buff.readInt(); // flag
136 while (Buff.getCursor() != (Size - 4)) {
137 StringRef Filename = Buff.readString();
138 if (Buff.getCursor() == (Size - 4)) break;
139 while (uint32_t L = Buff.readInt())
140 Block->addLine(Filename, L);
141 }
142 Buff.readInt(); // flag
143 }
144 return true;
145 }
146
147 /// dump - Dump GCOVFunction content on standard out for debugging purposes.
148 void GCOVFunction::dump() {
149 outs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
150 for (SmallVector::iterator I = Blocks.begin(),
151 E = Blocks.end(); I != E; ++I)
152 (*I)->dump();
153 }
154
155 /// collectLineCounts - Collect line counts. This must be used after
156 /// reading .gcno and .gcda files.
157 void GCOVFunction::collectLineCounts(FileInfo &FI) {
158 for (SmallVector::iterator I = Blocks.begin(),
159 E = Blocks.end(); I != E; ++I)
160 (*I)->collectLineCounts(FI);
161 }
162
163 //===----------------------------------------------------------------------===//
164 // GCOVBlock implementation.
165
166 /// ~GCOVBlock - Delete GCOVBlock and its content.
167 GCOVBlock::~GCOVBlock() {
168 Edges.clear();
169 DeleteContainerSeconds(Lines);
170 }
171
172 void GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) {
173 GCOVLines *&LinesForFile = Lines[Filename];
174 if (!LinesForFile)
175 LinesForFile = new GCOVLines();
176 LinesForFile->add(LineNo);
177 }
178
179 /// collectLineCounts - Collect line counts. This must be used after
180 /// reading .gcno and .gcda files.
181 void GCOVBlock::collectLineCounts(FileInfo &FI) {
182 for (StringMap::iterator I = Lines.begin(),
183 E = Lines.end(); I != E; ++I)
184 I->second->collectLineCounts(FI, I->first(), Counter);
185 }
186
187 /// dump - Dump GCOVBlock content on standard out for debugging purposes.
188 void GCOVBlock::dump() {
189 outs() << "Block : " << Number << " Counter : " << Counter << "\n";
190 if (!Edges.empty()) {
191 outs() << "\tEdges : ";
192 for (SmallVector::iterator I = Edges.begin(), E = Edges.end();
193 I != E; ++I)
194 outs() << (*I) << ",";
195 outs() << "\n";
196 }
197 if (!Lines.empty()) {
198 outs() << "\tLines : ";
199 for (StringMap::iterator LI = Lines.begin(),
200 LE = Lines.end(); LI != LE; ++LI) {
201 outs() << LI->first() << " -> ";
202 LI->second->dump();
203 outs() << "\n";
204 }
205 }
206 }
207
208 //===----------------------------------------------------------------------===//
209 // GCOVLines implementation.
210
211 /// collectLineCounts - Collect line counts. This must be used after
212 /// reading .gcno and .gcda files.
213 void GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename,
214 uint32_t Count) {
215 for (SmallVector::iterator I = Lines.begin(),
216 E = Lines.end(); I != E; ++I)
217 FI.addLineCount(Filename, *I, Count);
218 }
219
220 /// dump - Dump GCOVLines content on standard out for debugging purposes.
221 void GCOVLines::dump() {
222 for (SmallVector::iterator I = Lines.begin(),
223 E = Lines.end(); I != E; ++I)
224 outs() << (*I) << ",";
225 }
226
227 //===----------------------------------------------------------------------===//
228 // FileInfo implementation.
229
230 /// addLineCount - Add line count for the given line number in a file.
231 void FileInfo::addLineCount(StringRef Filename, uint32_t Line, uint32_t Count) {
232 if (LineInfo.find(Filename) == LineInfo.end()) {
233 OwningPtr Buff;
234 if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
235 errs() << Filename << ": " << ec.message() << "\n";
236 return;
237 }
238 StringRef AllLines = Buff.take()->getBuffer();
239 LineCounts L(AllLines.count('\n')+2);
240 L[Line-1] = Count;
241 LineInfo[Filename] = L;
242 return;
243 }
244 LineCounts &L = LineInfo[Filename];
245 L[Line-1] = Count;
246 }
247
248 /// print - Print source files with collected line count information.
249 void FileInfo::print() {
250 for (StringMap::iterator I = LineInfo.begin(), E = LineInfo.end();
251 I != E; ++I) {
252 StringRef Filename = I->first();
253 outs() << Filename << "\n";
254 LineCounts &L = LineInfo[Filename];
255 OwningPtr Buff;
256 if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
257 errs() << Filename << ": " << ec.message() << "\n";
258 return;
259 }
260 StringRef AllLines = Buff.take()->getBuffer();
261 for (unsigned i = 0, e = L.size(); i != e; ++i) {
262 if (L[i])
263 outs() << L[i] << ":\t";
264 else
265 outs() << " :\t";
266 std::pair P = AllLines.split('\n');
267 if (AllLines != P.first)
268 outs() << P.first;
269 outs() << "\n";
270 AllLines = P.second;
271 }
272 }
273 }
274
275
0 //===-- tools/cov/GCOVReader.h - LLVM coverage tool -------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This header provides the interface to read coverage files that use 'gcov'
10 // format.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef GCOVREADER_H
15 #define GCOVREADER_H
16
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringMap.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/raw_ostream.h"
21
22 namespace llvm {
23
24 class GCOVFunction;
25 class GCOVBlock;
26 class GCOVLines;
27 class FileInfo;
28
29 enum GCOVFormat {
30 InvalidGCOV,
31 GCNO_402,
32 GCNO_404,
33 GCDA_402,
34 GCDA_404
35 };
36
37 /// GCOVBuffer - A wrapper around MemoryBuffer to provid GCOV specific
38 /// read operations.
39 class GCOVBuffer {
40 public:
41 GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
42
43 /// readGCOVFormat - Read GCOV signature at the beginning of buffer.
44 enum GCOVFormat readGCOVFormat() {
45 StringRef Magic = Buffer->getBuffer().slice(0, 12);
46 Cursor = 12;
47 if (Magic == "oncg*404MVLL")
48 return GCNO_404;
49 else if (Magic == "oncg*204MVLL")
50 return GCNO_402;
51 else if (Magic == "adcg*404MVLL")
52 return GCDA_404;
53 else if (Magic == "adcg*204MVLL")
54 return GCDA_402;
55
56 Cursor = 0;
57 return InvalidGCOV;
58 }
59
60 /// readFunctionTag - If cursor points to a function tag then increment the
61 /// cursor and return true otherwise return false.
62 bool readFunctionTag() {
63 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
64 if (Tag.empty() ||
65 Tag[0] != '\0' || Tag[1] != '\0' ||
66 Tag[2] != '\0' || Tag[3] != '\1') {
67 return false;
68 }
69 Cursor += 4;
70 return true;
71 }
72
73 /// readBlockTag - If cursor points to a block tag then increment the
74 /// cursor and return true otherwise return false.
75 bool readBlockTag() {
76 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
77 if (Tag.empty() ||
78 Tag[0] != '\0' || Tag[1] != '\0' ||
79 Tag[2] != '\x41' || Tag[3] != '\x01') {
80 return false;
81 }
82 Cursor += 4;
83 return true;
84 }
85
86 /// readEdgeTag - If cursor points to an edge tag then increment the
87 /// cursor and return true otherwise return false.
88 bool readEdgeTag() {
89 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
90 if (Tag.empty() ||
91 Tag[0] != '\0' || Tag[1] != '\0' ||
92 Tag[2] != '\x43' || Tag[3] != '\x01') {
93 return false;
94 }
95 Cursor += 4;
96 return true;
97 }
98
99 /// readLineTag - If cursor points to a line tag then increment the
100 /// cursor and return true otherwise return false.
101 bool readLineTag() {
102 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
103 if (Tag.empty() ||
104 Tag[0] != '\0' || Tag[1] != '\0' ||
105 Tag[2] != '\x45' || Tag[3] != '\x01') {
106 return false;
107 }
108 Cursor += 4;
109 return true;
110 }
111
112 /// readArcTag - If cursor points to an gcda arc tag then increment the
113 /// cursor and return true otherwise return false.
114 bool readArcTag() {
115 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
116 if (Tag.empty() ||
117 Tag[0] != '\0' || Tag[1] != '\0' ||
118 Tag[2] != '\xa1' || Tag[3] != '\1') {
119 return false;
120 }
121 Cursor += 4;
122 return true;
123 }
124
125 uint32_t readInt() {
126 uint32_t Result;
127 StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4);
128 assert (Str.empty() == false && "Unexpected memory buffer end!");
129 Cursor += 4;
130 Result = *(uint32_t *)(Str.data());
131 return Result;
132 }
133
134 uint64_t readInt64() {
135 uint64_t Lo = readInt();
136 uint64_t Hi = readInt();
137 uint64_t Result = Lo | (Hi << 32);
138 return Result;
139 }
140
141 StringRef readString() {
142 uint32_t Len = readInt() * 4;
143 StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+Len);
144 Cursor += Len;
145 return Str;
146 }
147
148 uint64_t getCursor() const { return Cursor; }
149 private:
150 MemoryBuffer *Buffer;
151 uint64_t Cursor;
152 };
153
154 /// GCOVFile - Collects file information.
155 class GCOVFile {
156 public:
157 GCOVFile() : Format(InvalidGCOV) {}
158 ~GCOVFile();
159 bool read(GCOVBuffer &Buffer);
160 void dump();
161 void collectLineCounts(FileInfo &FI);
162 private:
163 enum GCOVFormat Format;
164 SmallVector Functions;
165 };
166
167 /// GCOVFunction - Collects function information.
168 class GCOVFunction {
169 public:
170 GCOVFunction() : Ident(0), LineNumber(0) {}
171 ~GCOVFunction();
172 bool read(GCOVBuffer &Buffer, GCOVFormat Format);
173 void dump();
174 void collectLineCounts(FileInfo &FI);
175 private:
176 uint32_t Ident;
177 uint32_t LineNumber;
178 StringRef Name;
179 StringRef Filename;
180 SmallVector Blocks;
181 };
182
183 /// GCOVBlock - Collects block information.
184 class GCOVBlock {
185 public:
186 GCOVBlock(uint32_t N) : Number(N), Counter(0) {}
187 ~GCOVBlock();
188 void addEdge(uint32_t N) { Edges.push_back(N); }
189 void addLine(StringRef Filename, uint32_t LineNo);
190 void addCount(uint64_t N) { Counter = N; }
191 void dump();
192 void collectLineCounts(FileInfo &FI);
193 private:
194 uint32_t Number;
195 uint64_t Counter;
196 SmallVector Edges;
197 StringMap Lines;
198 };
199
200 /// GCOVLines - A wrapper around a vector of int to keep track of line nos.
201 class GCOVLines {
202 public:
203 ~GCOVLines() { Lines.clear(); }
204 void add(uint32_t N) { Lines.push_back(N); }
205 void collectLineCounts(FileInfo &FI, StringRef Filename, uint32_t Count);
206 void dump();
207
208 private:
209 SmallVector Lines;
210 };
211
212 typedef SmallVector LineCounts;
213 class FileInfo {
214 public:
215 void addLineCount(StringRef Filename, uint32_t Line, uint32_t Count);
216 void print();
217 private:
218 StringMap LineInfo;
219 };
220
221
222 }
223
224 #endif
0 ##===- tools/llvm-gcov/Makefile ----------------------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file is distributed under the University of Illinois Open Source
5 # License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8
9 LEVEL = ../..
10
11 TOOLNAME = llvm-cov
12 LINK_COMPONENTS := instrumentation
13
14 # This tool has no plugins, optimize startup time.
15 TOOL_NO_EXPORTS = 1
16
17 include $(LEVEL)/Makefile.common
0 //===- tools/llvm-cov/llvm-cov.cpp - LLVM coverage tool -------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //
10 // llvm-cov is a command line tools to analyze and report coverage information.
11 //
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "GCOVReader.h"
16 #include "llvm/ADT/OwningPtr.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/ManagedStatic.h"
19 #include "llvm/Support/MemoryObject.h"
20 #include "llvm/Support/PrettyStackTrace.h"
21 #include "llvm/Support/Signals.h"
22 #include "llvm/Support/system_error.h"
23 using namespace llvm;
24
25 static cl::opt
26 DumpGCOV("dump", cl::init(false), cl::desc("dump gcov file"));
27
28 static cl::opt
29 InputGCNO("gcno", cl::desc(""), cl::init(""));
30
31 static cl::opt
32 InputGCDA("gcda", cl::desc(""), cl::init(""));
33
34
35 //===----------------------------------------------------------------------===//
36 int main(int argc, char **argv) {
37 // Print a stack trace if we signal out.
38 sys::PrintStackTraceOnErrorSignal();
39 PrettyStackTraceProgram X(argc, argv);
40 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
41
42 cl::ParseCommandLineOptions(argc, argv, "llvm cov\n");
43
44
45 GCOVFile GF;
46 if (InputGCNO.empty())
47 errs() << " " << argv[0] << ": No gcov input file!\n";
48
49 OwningPtr Buff;
50 if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCNO, Buff)) {
51 errs() << InputGCNO << ": " << ec.message() << "\n";
52 return 1;
53 }
54 GCOVBuffer GB(Buff.take());
55
56 if (!GF.read(GB)) {
57 errs() << "Invalid .gcno File!\n";
58 return 1;
59 }
60
61 if (!InputGCDA.empty()) {
62 OwningPtr Buff2;
63 if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCDA, Buff2)) {
64 errs() << InputGCDA << ": " << ec.message() << "\n";
65 return 1;
66 }
67 GCOVBuffer GB2(Buff2.take());
68
69 if (!GF.read(GB2)) {
70 errs() << "Invalid .gcda File!\n";
71 return 1;
72 }
73 }
74
75
76 if (DumpGCOV)
77 GF.dump();
78
79 FileInfo FI;
80 GF.collectLineCounts(FI);
81 return 0;
82 }