Skip to content

Commit 2e50575

Browse files
committed
Add edge coverage sample instrumentation.
This example tracks edge coverage information and writes the result out to a file.
1 parent 8011604 commit 2e50575

1 file changed

Lines changed: 231 additions & 0 deletions

File tree

examples/cov.c

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/*
2+
* COVERAGE instrumentation.
3+
*/
4+
5+
/*
6+
* Reports edge coverage information.
7+
*
8+
* EXAMPLE USAGE:
9+
* $ e9compile cov.c
10+
* $ e9tool --dump-all -M "jmp or call" \
11+
* -P 'entry((static)BB,(static)next)@cov' xterm
12+
* $ ./a.out
13+
*
14+
* INPUT:
15+
* This example program parses the "a.out.BBs.csv" file in order to map jump
16+
* targets to the corresponding basic block. Use E9Tool's --dump-all option
17+
* to generate this file.
18+
*
19+
* OUTPUT:
20+
* This example program will write the resulting coverage into a
21+
* "a.out.COV.csv" file with three columns:
22+
* 1) The "from" basic block
23+
* 2) The "to" basic block
24+
* 3) The count (number of times edge taken)
25+
*
26+
* NOTES:
27+
* The output file will NOT be generated if the program crashes or calls fast
28+
* exit (e.g., _Exit()).
29+
*/
30+
31+
#include "stdlib.c"
32+
33+
static bool option_tty = false;
34+
35+
#define RED (option_tty? "\33[31m": "")
36+
#define GREEN (option_tty? "\33[32m": "")
37+
#define YELLOW (option_tty? "\33[33m": "")
38+
#define OFF (option_tty? "\33[0m" : "")
39+
40+
typedef struct
41+
{
42+
const uintptr_t from;
43+
const uintptr_t to;
44+
size_t count;
45+
} ENTRY;
46+
47+
static void *COV = NULL; // Global state.
48+
static mutex_t mutex = MUTEX_INITIALIZER; // Global mutex.
49+
50+
static const char *output = NULL; // Output filename.
51+
static FILE *stream = NULL; // Output stream.
52+
53+
typedef struct
54+
{
55+
uintptr_t *data;
56+
size_t size;
57+
size_t max;
58+
} INFO;
59+
static INFO BBs = {0}; // All basic blocks.
60+
61+
/*
62+
* Error reporting.
63+
*/
64+
#define error(msg, ...) \
65+
do { \
66+
fprintf(stderr, "%serror%s: " msg "\n", RED, OFF, \
67+
##__VA_ARGS__); \
68+
abort(); \
69+
} while (false)
70+
71+
/*
72+
* Locking/unlocking.
73+
*/
74+
static bool LOCK(void)
75+
{
76+
return (mutex_lock(&mutex) == 0);
77+
}
78+
static void UNLOCK(void)
79+
{
80+
mutex_unlock(&mutex);
81+
}
82+
83+
/*
84+
* BB lookup.
85+
*/
86+
static uintptr_t bb_lookup(uintptr_t target)
87+
{
88+
ssize_t lo = 0, hi = BBs.size-1;
89+
while (lo <= hi)
90+
{
91+
ssize_t mid = (lo + hi) / 2;
92+
if (BBs.data[mid] < target)
93+
lo = mid+1;
94+
else if (BBs.data[mid] > target)
95+
hi = mid-1;
96+
else
97+
return BBs.data[mid];
98+
}
99+
return BBs.data[lo];
100+
}
101+
102+
/*
103+
* ENTRY compare.
104+
*/
105+
static int compare(const void *n, const void *m)
106+
{
107+
const ENTRY *a = (ENTRY *)n, *b = (ENTRY *)m;
108+
if (a->from != b->from)
109+
return (a->from < b->from? -1: 1);
110+
if (a->to != b->to)
111+
return (a->to < b->to? -1: 1);
112+
return 0;
113+
}
114+
115+
/*
116+
* Entry point.
117+
*/
118+
void entry(const void *bb, const void *next)
119+
{
120+
uintptr_t to = (uintptr_t)next;
121+
uintptr_t from = (uintptr_t)bb;
122+
to = bb_lookup(to);
123+
ENTRY key = {from, to, 0};
124+
125+
if (!LOCK())
126+
return;
127+
128+
void *node = tfind(&key, &COV, compare);
129+
ENTRY *entry = (node != NULL? *(ENTRY **)node: NULL);
130+
if (entry == NULL)
131+
{
132+
entry = (ENTRY *)malloc(sizeof(ENTRY));
133+
if (entry == NULL)
134+
error("failed to allocate memory: %s", strerror(errno));
135+
memcpy(entry, &key, sizeof(ENTRY));
136+
(void)tsearch(entry, &COV, compare);
137+
}
138+
entry->count++;
139+
140+
UNLOCK();
141+
}
142+
143+
/*
144+
* Init.
145+
*/
146+
void init(int argc, char **argv, char **envp)
147+
{
148+
option_tty = isatty(STDERR_FILENO);
149+
const char *progname = argv[0];
150+
size_t len = strlen(progname);
151+
char input[len + 16];
152+
int r = snprintf(input, sizeof(input)-1, "%s.BBs.csv", progname);
153+
if (r < 0 || r >= (int)sizeof(input)-1)
154+
error("failed to create input filename: %s", strerror(errno));
155+
stream = fopen(input, "r");
156+
if (stream == NULL)
157+
error("failed to open \"%s%s%s\" for reading: %s", YELLOW, input,
158+
OFF, strerror(errno));
159+
char c;
160+
while ((c = getc(stream)) != '\n' && c != EOF)
161+
;
162+
void *lb, *ub;
163+
while (fscanf(stream, "%p,%p", &lb, &ub) == 2)
164+
{
165+
if (BBs.size >= BBs.max)
166+
{
167+
BBs.max = (BBs.max == 0? 16: 2 * BBs.max);
168+
BBs.data = (uintptr_t *)realloc(BBs.data,
169+
BBs.max * sizeof(uintptr_t));
170+
if (BBs.data == NULL)
171+
{
172+
bad_realloc:
173+
error("failed to allocate memory: %s", strerror(errno));
174+
}
175+
}
176+
BBs.data[BBs.size++] = (uintptr_t)lb;
177+
}
178+
BBs.size++;
179+
BBs.max = BBs.size;
180+
BBs.data = (uintptr_t *)realloc(BBs.data, BBs.max * sizeof(uintptr_t));
181+
if (BBs.data == NULL)
182+
goto bad_realloc;
183+
BBs.data[BBs.size-1] = UINTPTR_MAX;
184+
fclose(stream);
185+
stream = NULL;
186+
fprintf(stderr, "%sCOV%s: parsed %s%zu%s basic-blocks from \"%s%s%s\"\n",
187+
GREEN, OFF, YELLOW, BBs.size-1, OFF, YELLOW, input, OFF);
188+
189+
char tmp[len + 16];
190+
r = snprintf(tmp, sizeof(tmp)-1, "%s.COV.csv", progname);
191+
if (r < 0 || r >= (int)sizeof(tmp)-1)
192+
{
193+
bad_output:
194+
error("failed to create output filename: %s", strerror(errno));
195+
}
196+
output = strdup(tmp);
197+
if (output == NULL)
198+
goto bad_output;
199+
}
200+
201+
/*
202+
* Fini.
203+
*/
204+
void print(const void *node, const VISIT which, const int depth)
205+
{
206+
ENTRY *entry = *(ENTRY **)node;
207+
switch (which)
208+
{
209+
case postorder: case leaf:
210+
fprintf(stream, "%p,%p,%zu\n",
211+
(void *)entry->from, (void *)entry->to, entry->count);
212+
break;
213+
default:
214+
break;
215+
}
216+
}
217+
void fini(void)
218+
{
219+
LOCK();
220+
stream = fopen(output, "w");
221+
if (stream == NULL)
222+
error("failed to open file \"%s%s%s\" for writing: %s",
223+
YELLOW, output, OFF, strerror(errno));
224+
fputs("from,to,count\n", stream);
225+
twalk(COV, print);
226+
fclose(stream);
227+
fprintf(stderr, "%sCOV%s: saved edge coverage information to "
228+
"\"%s%s%s\"\n", GREEN, OFF, YELLOW, output, OFF);
229+
UNLOCK();
230+
}
231+

0 commit comments

Comments
 (0)