#include <stdio.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#ifndef _WIN32#include <unistd.h>#include <errno.h>#else#include <windows.h>#include <io.h>#endif /* section layout (all little endian): 32bit offset to executable/so file name filename \0 function name \0 align to 64 bits 64bit function start line 64bits end_line(28bits) / start_line(28bits) / flag=0xff(8bits) 64bits counter \0 \0 \0 executable/so file name \0 */ typedef struct tcov_line { unsigned int fline; unsigned int lline; unsigned long long count;} tcov_line; typedef struct tcov_function { char *function; unsigned int first_line; unsigned int n_line; unsigned int m_line; tcov_line *line;} tcov_function; typedef struct tcov_file { char *filename; unsigned int n_func; unsigned int m_func; tcov_function *func; struct tcov_file *next;} tcov_file; static FILE *open_tcov_file (char *cov_filename){ int fd;#ifndef _WIN32 struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; /* Until EOF. */ lock.l_pid = getpid ();#endif fd = open (cov_filename, O_RDWR | O_CREAT, 0666); if (fd < 0) return NULL; #ifndef _WIN32 while (fcntl (fd, F_SETLKW, &lock) && errno == EINTR) continue;#else { OVERLAPPED overlapped = { 0 }; LockFileEx((HANDLE)_get_osfhandle(fd), LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &overlapped); }#endif return fdopen (fd, "r+");} static unsigned long long get_value(unsigned char *p, int size){ unsigned long long value = 0; p += size; while (size--) value = (value << 8) | *--p; return value;} static int sort_func (const void *p, const void *q){ const tcov_function *pp = (const tcov_function *) p; const tcov_function *pq = (const tcov_function *) q; return pp->first_line > pq->first_line ? 1 : pp->first_line < pq->first_line ? -1 : 0;} static int sort_line (const void *p, const void *q){ const tcov_line *pp = (const tcov_line *) p; const tcov_line *pq = (const tcov_line *) q; return pp->fline > pq->fline ? 1 : pp->fline < pq->fline ? -1 : pp->count < pq->count ? 1 : pp->count > pq->count ? -1 : 0;} /* sort to let inline functions work */static tcov_file *sort_test_coverage (unsigned char *p){ int i, j, k; unsigned char *start = p; tcov_file *file = NULL; tcov_file *nfile; p += 4; while (*p) { char *filename = (char *)p; size_t len = strlen (filename); nfile = file; while (nfile) { if (strcmp (nfile->filename, filename) == 0) break; nfile = nfile->next; } if (nfile == NULL) { nfile = malloc (sizeof(tcov_file)); if (nfile == NULL) { fprintf (stderr, "Malloc error test_coverage\n"); return file; } nfile->filename = filename; nfile->n_func = 0; nfile->m_func = 0; nfile->func = NULL; nfile->next = NULL; if (file == NULL) file = nfile; else { tcov_file *lfile = file; while (lfile->next) lfile = lfile->next; lfile->next = nfile; } } p += len + 1; while (*p) { int i; char *function = (char *)p; tcov_function *func; p += strlen (function) + 1; p += -(p - start) & 7; for (i = 0; i < nfile->n_func; i++) { func = &nfile->func[i]; if (strcmp (func->function, function) == 0) break; } if (i == nfile->n_func) { if (nfile->n_func >= nfile->m_func) { nfile->m_func = nfile->m_func == 0 ? 4 : nfile->m_func * 2; nfile->func = realloc (nfile->func, nfile->m_func * sizeof (tcov_function)); if (nfile->func == NULL) { fprintf (stderr, "Realloc error test_coverage\n"); return file; } } func = &nfile->func[nfile->n_func++]; func->function = function; func->first_line = get_value (p, 8); func->n_line = 0; func->m_line = 0; func->line = NULL; } p += 8; while (*p) { tcov_line *line; unsigned long long val; if (func->n_line >= func->m_line) { func->m_line = func->m_line == 0 ? 4 : func->m_line * 2; func->line = realloc (func->line, func->m_line * sizeof (tcov_line)); if (func->line == NULL) { fprintf (stderr, "Realloc error test_coverage\n"); return file; } } line = &func->line[func->n_line++]; val = get_value (p, 8); line->fline = (val >> 8) & 0xfffffffULL; line->lline = val >> 36; line->count = get_value (p + 8, 8); p += 16; } p++; } p++; } nfile = file; while (nfile) { qsort (nfile->func, nfile->n_func, sizeof (tcov_function), sort_func); for (i = 0; i < nfile->n_func; i++) { tcov_function *func = &nfile->func[i]; qsort (func->line, func->n_line, sizeof (tcov_line), sort_line); } nfile = nfile->next; } return file;} /* merge with previous tcov file */static void merge_test_coverage (tcov_file *file, FILE *fp, unsigned int *pruns){ unsigned int runs; char *p; char str[10000]; *pruns = 1; if (fp == NULL) return; if (fgets(str, sizeof(str), fp) && (p = strrchr (str, ':')) && (sscanf (p + 1, "%u", &runs) == 1)) *pruns = runs + 1; while (file) { int i; size_t len = strlen (file->filename); while (fgets(str, sizeof(str), fp) && (p = strstr(str, "0:File:")) == NULL) {} if ((p = strstr(str, "0:File:")) == NULL || strncmp (p + strlen("0:File:"), file->filename, len) != 0 || p[strlen("0:File:") + len] != ' ') break; for (i = 0; i < file->n_func; i++) { int j; tcov_function *func = &file->func[i]; unsigned int next_zero = 0; unsigned int curline = 0; for (j = 0; j < func->n_line; j++) { tcov_line *line = &func->line[j]; unsigned int fline = line->fline; unsigned long long count; unsigned int tmp; char c; while (curline < fline && fgets(str, sizeof(str), fp)) if ((p = strchr(str, ':')) && sscanf (p + 1, "%u", &tmp) == 1) curline = tmp; if (sscanf (str, "%llu%c\n", &count, &c) == 2) { if (next_zero == 0) line->count += count; next_zero = c == '*'; } } } file = file->next; }} /* store tcov data in file */void __store_test_coverage (unsigned char * p){ int i, j; unsigned int files; unsigned int funcs; unsigned int blocks; unsigned int blocks_run; unsigned int runs; char *cov_filename = (char *)p + get_value (p, 4); FILE *fp; char *q; tcov_file *file; tcov_file *nfile; tcov_function *func; fp = open_tcov_file (cov_filename); if (fp == NULL) { fprintf (stderr, "Cannot create coverage file: %s\n", cov_filename); return; } file = sort_test_coverage (p); merge_test_coverage (file, fp, &runs); fseek (fp, 0, SEEK_SET); fprintf (fp, " -: 0:Runs:%u\n", runs); files = 0; funcs = 0; blocks = 0; blocks_run = 0; nfile = file; while (nfile) { files++; for (i = 0; i < nfile->n_func; i++) { func = &nfile->func[i]; funcs++; for (j = 0; j < func->n_line; j++) { blocks++; blocks_run += func->line[j].count != 0; } } nfile = nfile->next; } if (blocks == 0) blocks = 1; fprintf (fp, " -: 0:All:%s Files:%u Functions:%u %.02f%%\n", cov_filename, files, funcs, 100.0 * (double) blocks_run / blocks); nfile = file; while (nfile) { FILE *src = fopen (nfile->filename, "r"); unsigned int curline = 1; char str[10000]; if (src == NULL) goto next; funcs = 0; blocks = 0; blocks_run = 0; for (i = 0; i < nfile->n_func; i++) { func = &nfile->func[i]; funcs++; for (j = 0; j < func->n_line; j++) { blocks++; blocks_run += func->line[j].count != 0; } } if (blocks == 0) blocks = 1; fprintf (fp, " -: 0:File:%s Functions:%u %.02f%%\n", nfile->filename, funcs, 100.0 * (double) blocks_run / blocks); for (i = 0; i < nfile->n_func; i++) { func = &nfile->func[i]; while (curline < func->first_line && fgets(str, sizeof(str), src)) fprintf (fp, " -:%5u:%s", curline++, str); blocks = 0; blocks_run = 0; for (j = 0; j < func->n_line; j++) { blocks++; blocks_run += func->line[j].count != 0; } if (blocks == 0) blocks = 1; fprintf (fp, " -: 0:Function:%s %.02f%%\n", func->function, 100.0 * (double) blocks_run / blocks);#if 0 for (j = 0; j < func->n_line; j++) { unsigned int fline = func->line[j].fline; unsigned int lline = func->line[j].lline; unsigned long long count = func->line[j].count; fprintf (fp, "%u %u %llu\n", fline, lline, count); }#endif for (j = 0; j < func->n_line;) { unsigned int fline = func->line[j].fline; unsigned int lline = func->line[j].lline; unsigned long long count = func->line[j].count; unsigned int has_zero = 0; unsigned int same_line = fline == lline; j++; while (j < func->n_line) { unsigned int nfline = func->line[j].fline; unsigned int nlline = func->line[j].lline; unsigned long long ncount = func->line[j].count; if (fline == nfline) { if (ncount == 0) has_zero = 1; else if (ncount > count) count = ncount; same_line = nfline == nlline; lline = nlline; j++; } else break; } if (same_line) lline++; while (curline < fline && fgets(str, sizeof(str), src)) fprintf (fp, " -:%5u:%s", curline++, str); while (curline < lline && fgets(str, sizeof(str), src)) { if (count == 0) fprintf (fp, " #####:%5u:%s", curline, str); else if (has_zero) fprintf (fp, "%8llu*:%5u:%s", count, curline, str); else fprintf (fp, "%9llu:%5u:%s", count, curline, str); curline++; } } } while (fgets(str, sizeof(str), src)) fprintf (fp, " -:%5u:%s", curline++, str); fclose (src);next: nfile = nfile->next; } while (file) { for (i = 0; i < file->n_func; i++) { func = &file->func[i]; free (func->line); } free (file->func); nfile = file; file = file->next; free (nfile); } fclose (fp);}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
#include <errno.h>
#else
#include <windows.h>
#include <io.h>
#endif
/* section layout (all little endian):
32bit offset to executable/so file name
filename \0
function name \0
align to 64 bits
64bit function start line
64bits end_line(28bits) / start_line(28bits) / flag=0xff(8bits)
64bits counter
\0
\0
\0
executable/so file name \0
*/
typedef struct tcov_line {
unsigned int fline;
unsigned int lline;
unsigned long long count;
} tcov_line;
typedef struct tcov_function {
char *function;
unsigned int first_line;
unsigned int n_line;
unsigned int m_line;
tcov_line *line;
} tcov_function;
typedef struct tcov_file {
char *filename;
unsigned int n_func;
unsigned int m_func;
tcov_function *func;
struct tcov_file *next;
} tcov_file;
static FILE *open_tcov_file (char *cov_filename)
{
int fd;
#ifndef _WIN32
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; /* Until EOF. */
lock.l_pid = getpid ();
#endif
fd = open (cov_filename, O_RDWR | O_CREAT, 0666);
if (fd < 0)
return NULL;
#ifndef _WIN32
while (fcntl (fd, F_SETLKW, &lock) && errno == EINTR)
continue;
#else
{
OVERLAPPED overlapped = { 0 };
LockFileEx((HANDLE)_get_osfhandle(fd), LOCKFILE_EXCLUSIVE_LOCK,
0, 1, 0, &overlapped);
}
#endif
return fdopen (fd, "r+");
}
static unsigned long long get_value(unsigned char *p, int size)
{
unsigned long long value = 0;
p += size;
while (size--)
value = (value << 8) | *--p;
return value;
}
static int sort_func (const void *p, const void *q)
{
const tcov_function *pp = (const tcov_function *) p;
const tcov_function *pq = (const tcov_function *) q;
return pp->first_line > pq->first_line ? 1 :
pp->first_line < pq->first_line ? -1 : 0;
}
static int sort_line (const void *p, const void *q)
{
const tcov_line *pp = (const tcov_line *) p;
const tcov_line *pq = (const tcov_line *) q;
return pp->fline > pq->fline ? 1 :
pp->fline < pq->fline ? -1 :
pp->count < pq->count ? 1 :
pp->count > pq->count ? -1 : 0;
}
/* sort to let inline functions work */
static tcov_file *sort_test_coverage (unsigned char *p)
{
int i, j, k;
unsigned char *start = p;
tcov_file *file = NULL;
tcov_file *nfile;
p += 4;
while (*p) {
char *filename = (char *)p;
size_t len = strlen (filename);
nfile = file;
while (nfile) {
if (strcmp (nfile->filename, filename) == 0)
break;
nfile = nfile->next;
}
if (nfile == NULL) {
nfile = malloc (sizeof(tcov_file));
if (nfile == NULL) {
fprintf (stderr, "Malloc error test_coverage\n");
return file;
}
nfile->filename = filename;
nfile->n_func = 0;
nfile->m_func = 0;
nfile->func = NULL;
nfile->next = NULL;
if (file == NULL)
file = nfile;
else {
tcov_file *lfile = file;
while (lfile->next)
lfile = lfile->next;
lfile->next = nfile;
}
}
p += len + 1;
while (*p) {
int i;
char *function = (char *)p;
tcov_function *func;
p += strlen (function) + 1;
p += -(p - start) & 7;
for (i = 0; i < nfile->n_func; i++) {
func = &nfile->func[i];
if (strcmp (func->function, function) == 0)
break;
}
if (i == nfile->n_func) {
if (nfile->n_func >= nfile->m_func) {
nfile->m_func = nfile->m_func == 0 ? 4 : nfile->m_func * 2;
nfile->func = realloc (nfile->func,
nfile->m_func *
sizeof (tcov_function));
if (nfile->func == NULL) {
fprintf (stderr, "Realloc error test_coverage\n");
return file;
}
}
func = &nfile->func[nfile->n_func++];
func->function = function;
func->first_line = get_value (p, 8);
func->n_line = 0;
func->m_line = 0;
func->line = NULL;
}
p += 8;
while (*p) {
tcov_line *line;
unsigned long long val;
if (func->n_line >= func->m_line) {
func->m_line = func->m_line == 0 ? 4 : func->m_line * 2;
func->line = realloc (func->line,
func->m_line * sizeof (tcov_line));
if (func->line == NULL) {
fprintf (stderr, "Realloc error test_coverage\n");
return file;
}
}
line = &func->line[func->n_line++];
val = get_value (p, 8);
line->fline = (val >> 8) & 0xfffffffULL;
line->lline = val >> 36;
line->count = get_value (p + 8, 8);
p += 16;
}
p++;
}
p++;
}
nfile = file;
while (nfile) {
qsort (nfile->func, nfile->n_func, sizeof (tcov_function), sort_func);
for (i = 0; i < nfile->n_func; i++) {
tcov_function *func = &nfile->func[i];
qsort (func->line, func->n_line, sizeof (tcov_line), sort_line);
}
nfile = nfile->next;
}
return file;
}
/* merge with previous tcov file */
static void merge_test_coverage (tcov_file *file, FILE *fp,
unsigned int *pruns)
{
unsigned int runs;
char *p;
char str[10000];
*pruns = 1;
if (fp == NULL)
return;
if (fgets(str, sizeof(str), fp) &&
(p = strrchr (str, ':')) &&
(sscanf (p + 1, "%u", &runs) == 1))
*pruns = runs + 1;
while (file) {
int i;
size_t len = strlen (file->filename);
while (fgets(str, sizeof(str), fp) &&
(p = strstr(str, "0:File:")) == NULL) {}
if ((p = strstr(str, "0:File:")) == NULL ||
strncmp (p + strlen("0:File:"), file->filename, len) != 0 ||
p[strlen("0:File:") + len] != ' ')
break;
for (i = 0; i < file->n_func; i++) {
int j;
tcov_function *func = &file->func[i];
unsigned int next_zero = 0;
unsigned int curline = 0;
for (j = 0; j < func->n_line; j++) {
tcov_line *line = &func->line[j];
unsigned int fline = line->fline;
unsigned long long count;
unsigned int tmp;
char c;
while (curline < fline &&
fgets(str, sizeof(str), fp))
if ((p = strchr(str, ':')) &&
sscanf (p + 1, "%u", &tmp) == 1)
curline = tmp;
if (sscanf (str, "%llu%c\n", &count, &c) == 2) {
if (next_zero == 0)
line->count += count;
next_zero = c == '*';
}
}
}
file = file->next;
}
}
/* store tcov data in file */
void __store_test_coverage (unsigned char * p)
{
int i, j;
unsigned int files;
unsigned int funcs;
unsigned int blocks;
unsigned int blocks_run;
unsigned int runs;
char *cov_filename = (char *)p + get_value (p, 4);
FILE *fp;
char *q;
tcov_file *file;
tcov_file *nfile;
tcov_function *func;
fp = open_tcov_file (cov_filename);
if (fp == NULL) {
fprintf (stderr, "Cannot create coverage file: %s\n", cov_filename);
return;
}
file = sort_test_coverage (p);
merge_test_coverage (file, fp, &runs);
fseek (fp, 0, SEEK_SET);
fprintf (fp, " -: 0:Runs:%u\n", runs);
files = 0;
funcs = 0;
blocks = 0;
blocks_run = 0;
nfile = file;
while (nfile) {
files++;
for (i = 0; i < nfile->n_func; i++) {
func = &nfile->func[i];
funcs++;
for (j = 0; j < func->n_line; j++) {
blocks++;
blocks_run += func->line[j].count != 0;
}
}
nfile = nfile->next;
}
if (blocks == 0)
blocks = 1;
fprintf (fp, " -: 0:All:%s Files:%u Functions:%u %.02f%%\n",
cov_filename, files, funcs, 100.0 * (double) blocks_run / blocks);
nfile = file;
while (nfile) {
FILE *src = fopen (nfile->filename, "r");
unsigned int curline = 1;
char str[10000];
if (src == NULL)
goto next;
funcs = 0;
blocks = 0;
blocks_run = 0;
for (i = 0; i < nfile->n_func; i++) {
func = &nfile->func[i];
funcs++;
for (j = 0; j < func->n_line; j++) {
blocks++;
blocks_run += func->line[j].count != 0;
}
}
if (blocks == 0)
blocks = 1;
fprintf (fp, " -: 0:File:%s Functions:%u %.02f%%\n",
nfile->filename, funcs, 100.0 * (double) blocks_run / blocks);
for (i = 0; i < nfile->n_func; i++) {
func = &nfile->func[i];
while (curline < func->first_line &&
fgets(str, sizeof(str), src))
fprintf (fp, " -:%5u:%s", curline++, str);
blocks = 0;
blocks_run = 0;
for (j = 0; j < func->n_line; j++) {
blocks++;
blocks_run += func->line[j].count != 0;
}
if (blocks == 0)
blocks = 1;
fprintf (fp, " -: 0:Function:%s %.02f%%\n",
func->function, 100.0 * (double) blocks_run / blocks);
#if 0
for (j = 0; j < func->n_line; j++) {
unsigned int fline = func->line[j].fline;
unsigned int lline = func->line[j].lline;
unsigned long long count = func->line[j].count;
fprintf (fp, "%u %u %llu\n", fline, lline, count);
}
#endif
for (j = 0; j < func->n_line;) {
unsigned int fline = func->line[j].fline;
unsigned int lline = func->line[j].lline;
unsigned long long count = func->line[j].count;
unsigned int has_zero = 0;
unsigned int same_line = fline == lline;
j++;
while (j < func->n_line) {
unsigned int nfline = func->line[j].fline;
unsigned int nlline = func->line[j].lline;
unsigned long long ncount = func->line[j].count;
if (fline == nfline) {
if (ncount == 0)
has_zero = 1;
else if (ncount > count)
count = ncount;
same_line = nfline == nlline;
lline = nlline;
j++;
}
else
break;
}
if (same_line)
lline++;
while (curline < fline &&
fgets(str, sizeof(str), src))
fprintf (fp, " -:%5u:%s", curline++, str);
while (curline < lline &&
fgets(str, sizeof(str), src)) {
if (count == 0)
fprintf (fp, " #####:%5u:%s",
curline, str);
else if (has_zero)
fprintf (fp, "%8llu*:%5u:%s",
count, curline, str);
else
fprintf (fp, "%9llu:%5u:%s",
count, curline, str);
curline++;
}
}
}
while (fgets(str, sizeof(str), src))
fprintf (fp, " -:%5u:%s", curline++, str);
fclose (src);
next:
nfile = nfile->next;
}
while (file) {
for (i = 0; i < file->n_func; i++) {
func = &file->func[i];
free (func->line);
}
free (file->func);
nfile = file;
file = file->next;
free (nfile);
}
fclose (fp);
}