2003-04-05 10:04:04 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu" -*- */
|
|
|
|
|
/* decode-gcov.c gcov decoder program
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2003 Red Hat Inc.
|
|
|
|
|
*
|
|
|
|
|
* Partially derived from gcov,
|
|
|
|
|
* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
|
|
|
|
|
* 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
|
|
|
|
*
|
|
|
|
|
* This file is NOT licensed under the Academic Free License
|
|
|
|
|
* as it is largely derived from gcov.c and gcov-io.h in the
|
|
|
|
|
* gcc source code.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define DBUS_COMPILATION /* cheat */
|
|
|
|
|
#include <dbus/dbus-list.h>
|
|
|
|
|
#include <dbus/dbus-string.h>
|
|
|
|
|
#include <dbus/dbus-sysdeps.h>
|
|
|
|
|
#include <dbus/dbus-marshal.h>
|
2003-04-05 17:04:23 +00:00
|
|
|
#include <dbus/dbus-hash.h>
|
2003-04-05 10:04:04 +00:00
|
|
|
#undef DBUS_COMPILATION
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
die (const char *message)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "%s", message);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This bizarro function is from gcov-io.h in gcc source tree */
|
|
|
|
|
static int
|
|
|
|
|
fetch_long (long *dest,
|
|
|
|
|
const char *source,
|
|
|
|
|
size_t bytes)
|
|
|
|
|
{
|
|
|
|
|
long value = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
|
|
|
|
|
if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
for (; i >= 0; i--)
|
|
|
|
|
value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
|
|
|
|
|
|
|
|
|
|
if ((source[bytes - 1] & 128) && (value > 0))
|
|
|
|
|
value = - value;
|
|
|
|
|
|
|
|
|
|
*dest = value;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef DBUS_INT64_TYPE dbus_int64_t;
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
fetch_long64 (dbus_int64_t *dest,
|
|
|
|
|
const char *source,
|
|
|
|
|
size_t bytes)
|
|
|
|
|
{
|
|
|
|
|
dbus_int64_t value = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
|
|
|
|
|
if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
for (; i >= 0; i--)
|
|
|
|
|
value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
|
|
|
|
|
|
|
|
|
|
if ((source[bytes - 1] & 128) && (value > 0))
|
|
|
|
|
value = - value;
|
|
|
|
|
|
|
|
|
|
*dest = value;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define BB_FILENAME (-1)
|
|
|
|
|
#define BB_FUNCTION (-2)
|
|
|
|
|
#define BB_ENDOFLIST 0
|
|
|
|
|
|
|
|
|
|
static dbus_bool_t
|
|
|
|
|
string_get_int (const DBusString *str,
|
|
|
|
|
int start,
|
|
|
|
|
long *val)
|
|
|
|
|
{
|
|
|
|
|
const char *p;
|
|
|
|
|
|
|
|
|
|
if ((_dbus_string_get_length (str) - start) < 4)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
p = _dbus_string_get_const_data (str);
|
|
|
|
|
|
|
|
|
|
p += start;
|
|
|
|
|
|
|
|
|
|
fetch_long (val, p, 4);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static dbus_bool_t
|
|
|
|
|
string_get_int64 (const DBusString *str,
|
|
|
|
|
int start,
|
|
|
|
|
dbus_int64_t *val)
|
|
|
|
|
{
|
|
|
|
|
const char *p;
|
|
|
|
|
|
|
|
|
|
if ((_dbus_string_get_length (str) - start) < 8)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
p = _dbus_string_get_const_data (str);
|
|
|
|
|
|
|
|
|
|
p += start;
|
|
|
|
|
|
|
|
|
|
fetch_long64 (val, p, 8);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static dbus_bool_t
|
|
|
|
|
string_get_string (const DBusString *str,
|
|
|
|
|
int start,
|
|
|
|
|
long terminator,
|
|
|
|
|
DBusString *val,
|
|
|
|
|
int *end)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
long n;
|
|
|
|
|
|
|
|
|
|
i = start;
|
|
|
|
|
while (string_get_int (str, i, &n))
|
|
|
|
|
{
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if (n == terminator)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
_dbus_string_append_byte (val, n & 0xff);
|
|
|
|
|
_dbus_string_append_byte (val, (n >> 8) & 0xff);
|
|
|
|
|
_dbus_string_append_byte (val, (n >> 16) & 0xff);
|
|
|
|
|
_dbus_string_append_byte (val, (n >> 24) & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*end = i;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dump_bb_file (const DBusString *contents)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
long val;
|
|
|
|
|
int n_functions;
|
|
|
|
|
|
|
|
|
|
n_functions = 0;
|
|
|
|
|
i = 0;
|
|
|
|
|
while (string_get_int (contents, i, &val))
|
|
|
|
|
{
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
case BB_FILENAME:
|
|
|
|
|
{
|
|
|
|
|
DBusString f;
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&f))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (string_get_string (contents, i,
|
|
|
|
|
BB_FILENAME,
|
|
|
|
|
&f, &i))
|
|
|
|
|
{
|
|
|
|
|
printf ("File %s\n", _dbus_string_get_const_data (&f));
|
|
|
|
|
}
|
|
|
|
|
_dbus_string_free (&f);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case BB_FUNCTION:
|
|
|
|
|
{
|
|
|
|
|
DBusString f;
|
|
|
|
|
if (!_dbus_string_init (&f))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (string_get_string (contents, i,
|
|
|
|
|
BB_FUNCTION,
|
|
|
|
|
&f, &i))
|
|
|
|
|
{
|
|
|
|
|
printf ("Function %s\n", _dbus_string_get_const_data (&f));
|
|
|
|
|
}
|
|
|
|
|
_dbus_string_free (&f);
|
|
|
|
|
|
|
|
|
|
n_functions += 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case BB_ENDOFLIST:
|
|
|
|
|
printf ("End of block\n");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf ("Line %ld\n", val);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf ("%d functions in file\n", n_functions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define FLAG_ON_TREE 0x1
|
|
|
|
|
#define FLAG_FAKE 0x2
|
|
|
|
|
#define FLAG_FALL_THROUGH 0x4
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dump_bbg_file (const DBusString *contents)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
long val;
|
|
|
|
|
int n_functions;
|
|
|
|
|
int n_arcs;
|
|
|
|
|
int n_blocks;
|
|
|
|
|
int n_arcs_off_tree;
|
|
|
|
|
|
|
|
|
|
n_arcs_off_tree = 0;
|
|
|
|
|
n_blocks = 0;
|
|
|
|
|
n_arcs = 0;
|
|
|
|
|
n_functions = 0;
|
|
|
|
|
i = 0;
|
|
|
|
|
while (string_get_int (contents, i, &val))
|
|
|
|
|
{
|
|
|
|
|
long n_blocks_in_func;
|
|
|
|
|
long n_arcs_in_func;
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
n_blocks_in_func = val;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &n_arcs_in_func))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
printf ("Function has %ld blocks and %ld arcs\n",
|
|
|
|
|
n_blocks_in_func, n_arcs_in_func);
|
|
|
|
|
|
|
|
|
|
n_functions += 1;
|
|
|
|
|
n_blocks += n_blocks_in_func;
|
|
|
|
|
n_arcs += n_arcs_in_func;
|
|
|
|
|
|
|
|
|
|
j = 0;
|
|
|
|
|
while (j < n_blocks_in_func)
|
|
|
|
|
{
|
|
|
|
|
long n_arcs_in_block;
|
|
|
|
|
int k;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &n_arcs_in_block))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
printf (" Block has %ld arcs\n", n_arcs_in_block);
|
|
|
|
|
|
|
|
|
|
k = 0;
|
|
|
|
|
while (k < n_arcs_in_block)
|
|
|
|
|
{
|
|
|
|
|
long destination_block;
|
|
|
|
|
long flags;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &destination_block))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &flags))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
printf (" Arc has destination block %ld flags 0x%lx\n",
|
|
|
|
|
destination_block, flags);
|
|
|
|
|
|
|
|
|
|
if ((flags & FLAG_ON_TREE) == 0)
|
|
|
|
|
n_arcs_off_tree += 1;
|
|
|
|
|
|
|
|
|
|
++k;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (k < n_arcs_in_block)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
++j;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (j < n_blocks_in_func)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &val))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if (val != -1)
|
|
|
|
|
die ("-1 separator not found\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
|
|
|
|
|
n_functions, n_blocks, n_arcs, n_arcs_off_tree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The da file contains first a count of arcs in the file,
|
|
|
|
|
* then a count of executions for all "off tree" arcs
|
|
|
|
|
* in the file.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
dump_da_file (const DBusString *contents)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
dbus_int64_t val;
|
|
|
|
|
int n_arcs;
|
|
|
|
|
int claimed_n_arcs;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
if (!string_get_int64 (contents, i, &val))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
i += 8;
|
|
|
|
|
|
|
|
|
|
printf ("%ld arcs in file\n", (long) val);
|
|
|
|
|
claimed_n_arcs = val;
|
|
|
|
|
|
|
|
|
|
n_arcs = 0;
|
|
|
|
|
while (string_get_int64 (contents, i, &val))
|
|
|
|
|
{
|
|
|
|
|
i += 8;
|
|
|
|
|
|
|
|
|
|
printf ("%ld executions of arc %d\n",
|
|
|
|
|
(long) val, n_arcs);
|
|
|
|
|
|
|
|
|
|
++n_arcs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n_arcs != claimed_n_arcs)
|
|
|
|
|
{
|
|
|
|
|
printf ("File claimed to have %d arcs but only had %d\n",
|
|
|
|
|
claimed_n_arcs, n_arcs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct Arc Arc;
|
|
|
|
|
typedef struct Block Block;
|
|
|
|
|
typedef struct Function Function;
|
|
|
|
|
typedef struct File File;
|
|
|
|
|
typedef struct Line Line;
|
|
|
|
|
|
|
|
|
|
struct Arc
|
|
|
|
|
{
|
|
|
|
|
int source;
|
|
|
|
|
int target;
|
|
|
|
|
dbus_int64_t arc_count;
|
|
|
|
|
unsigned int count_valid : 1;
|
|
|
|
|
unsigned int on_tree : 1;
|
|
|
|
|
unsigned int fake : 1;
|
|
|
|
|
unsigned int fall_through : 1;
|
|
|
|
|
Arc *pred_next;
|
|
|
|
|
Arc *succ_next;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Block
|
|
|
|
|
{
|
|
|
|
|
Arc *succ;
|
|
|
|
|
Arc *pred;
|
|
|
|
|
dbus_int64_t succ_count;
|
|
|
|
|
dbus_int64_t pred_count;
|
|
|
|
|
dbus_int64_t exec_count;
|
|
|
|
|
DBusList *lines;
|
|
|
|
|
unsigned int count_valid : 1;
|
|
|
|
|
unsigned int on_tree : 1;
|
|
|
|
|
unsigned int inside_dbus_build_tests : 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Function
|
|
|
|
|
{
|
|
|
|
|
char *name;
|
|
|
|
|
Block *block_graph;
|
|
|
|
|
int n_blocks;
|
|
|
|
|
unsigned int unused : 1;
|
|
|
|
|
unsigned int inside_dbus_build_tests : 1;
|
|
|
|
|
unsigned int partial : 1; /* only some of the blocks were executed */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Line
|
|
|
|
|
{
|
|
|
|
|
int number;
|
|
|
|
|
char *text;
|
|
|
|
|
DBusList *blocks;
|
|
|
|
|
unsigned int inside_dbus_build_tests : 1;
|
|
|
|
|
unsigned int partial : 1; /* only some of the blocks were executed */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct File
|
|
|
|
|
{
|
|
|
|
|
char *name;
|
|
|
|
|
Line *lines;
|
|
|
|
|
int n_lines;
|
|
|
|
|
DBusList *functions;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
function_add_arc (Function *function,
|
|
|
|
|
long source,
|
|
|
|
|
long target,
|
|
|
|
|
long flags)
|
|
|
|
|
{
|
|
|
|
|
Arc *arc;
|
|
|
|
|
|
|
|
|
|
arc = dbus_new0 (Arc, 1);
|
|
|
|
|
if (arc == NULL)
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
arc->target = target;
|
|
|
|
|
arc->source = source;
|
|
|
|
|
|
|
|
|
|
arc->succ_next = function->block_graph[source].succ;
|
|
|
|
|
function->block_graph[source].succ = arc;
|
|
|
|
|
function->block_graph[source].succ_count += 1;
|
|
|
|
|
|
|
|
|
|
arc->pred_next = function->block_graph[target].pred;
|
|
|
|
|
function->block_graph[target].pred = arc;
|
|
|
|
|
function->block_graph[target].pred_count += 1;
|
|
|
|
|
|
|
|
|
|
if ((flags & FLAG_ON_TREE) != 0)
|
|
|
|
|
arc->on_tree = TRUE;
|
|
|
|
|
|
|
|
|
|
if ((flags & FLAG_FAKE) != 0)
|
|
|
|
|
arc->fake = TRUE;
|
|
|
|
|
|
|
|
|
|
if ((flags & FLAG_FALL_THROUGH) != 0)
|
|
|
|
|
arc->fall_through = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static Arc*
|
|
|
|
|
reverse_arcs (Arc *arc)
|
|
|
|
|
{
|
|
|
|
|
struct Arc *prev = 0;
|
|
|
|
|
struct Arc *next;
|
|
|
|
|
|
|
|
|
|
for ( ; arc; arc = next)
|
|
|
|
|
{
|
|
|
|
|
next = arc->succ_next;
|
|
|
|
|
arc->succ_next = prev;
|
|
|
|
|
prev = arc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
function_reverse_succ_arcs (Function *func)
|
|
|
|
|
{
|
|
|
|
|
/* Must reverse the order of all succ arcs, to ensure that they match
|
|
|
|
|
* the order of the data in the .da file.
|
|
|
|
|
*/
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < func->n_blocks; i++)
|
|
|
|
|
if (func->block_graph[i].succ)
|
|
|
|
|
func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_functions_from_bbg (const DBusString *contents,
|
|
|
|
|
DBusList **functions)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
long val;
|
|
|
|
|
int n_functions;
|
|
|
|
|
int n_arcs;
|
|
|
|
|
int n_blocks;
|
|
|
|
|
int n_arcs_off_tree;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("Loading arcs and blocks from .bbg file\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
n_arcs_off_tree = 0;
|
|
|
|
|
n_blocks = 0;
|
|
|
|
|
n_arcs = 0;
|
|
|
|
|
n_functions = 0;
|
|
|
|
|
i = 0;
|
|
|
|
|
while (string_get_int (contents, i, &val))
|
|
|
|
|
{
|
|
|
|
|
Function *func;
|
|
|
|
|
long n_blocks_in_func;
|
|
|
|
|
long n_arcs_in_func;
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
n_blocks_in_func = val;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &n_arcs_in_func))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
n_functions += 1;
|
|
|
|
|
n_blocks += n_blocks_in_func;
|
|
|
|
|
n_arcs += n_arcs_in_func;
|
|
|
|
|
|
|
|
|
|
func = dbus_new0 (Function, 1);
|
|
|
|
|
if (func == NULL)
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
func->block_graph = dbus_new0 (Block, n_blocks_in_func);
|
|
|
|
|
func->n_blocks = n_blocks_in_func;
|
|
|
|
|
|
|
|
|
|
j = 0;
|
|
|
|
|
while (j < n_blocks_in_func)
|
|
|
|
|
{
|
|
|
|
|
long n_arcs_in_block;
|
|
|
|
|
int k;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &n_arcs_in_block))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
k = 0;
|
|
|
|
|
while (k < n_arcs_in_block)
|
|
|
|
|
{
|
|
|
|
|
long destination_block;
|
|
|
|
|
long flags;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &destination_block))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &flags))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if ((flags & FLAG_ON_TREE) == 0)
|
|
|
|
|
n_arcs_off_tree += 1;
|
|
|
|
|
|
|
|
|
|
function_add_arc (func, j, destination_block,
|
|
|
|
|
flags);
|
|
|
|
|
|
|
|
|
|
++k;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (k < n_arcs_in_block)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
++j;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (j < n_blocks_in_func)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
function_reverse_succ_arcs (func);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_list_append (functions, func))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (!string_get_int (contents, i, &val))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
if (val != -1)
|
|
|
|
|
die ("-1 separator not found\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
|
|
|
|
|
n_functions, n_blocks, n_arcs, n_arcs_off_tree);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
_dbus_assert (n_functions == _dbus_list_get_length (functions));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
add_counts_from_da (const DBusString *contents,
|
|
|
|
|
DBusList **functions)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
dbus_int64_t val;
|
|
|
|
|
int n_arcs;
|
|
|
|
|
int claimed_n_arcs;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
Function *current_func;
|
|
|
|
|
int current_block;
|
|
|
|
|
Arc *current_arc;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("Loading execution count for each arc from .da file\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
if (!string_get_int64 (contents, i, &val))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
i += 8;
|
|
|
|
|
|
|
|
|
|
claimed_n_arcs = val;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (functions);
|
|
|
|
|
if (link == NULL)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
current_func = link->data;
|
|
|
|
|
current_block = 0;
|
|
|
|
|
current_arc = current_func->block_graph[current_block].succ;
|
|
|
|
|
|
|
|
|
|
n_arcs = 0;
|
|
|
|
|
while (string_get_int64 (contents, i, &val))
|
|
|
|
|
{
|
|
|
|
|
i += 8;
|
|
|
|
|
|
|
|
|
|
while (current_arc == NULL ||
|
|
|
|
|
current_arc->on_tree)
|
|
|
|
|
{
|
|
|
|
|
if (current_arc == NULL)
|
|
|
|
|
{
|
|
|
|
|
++current_block;
|
|
|
|
|
|
|
|
|
|
if (current_block == current_func->n_blocks)
|
|
|
|
|
{
|
|
|
|
|
link = _dbus_list_get_next_link (functions, link);
|
|
|
|
|
if (link == NULL)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Ran out of functions loading .da file\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
current_func = link->data;
|
|
|
|
|
current_block = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current_arc = current_func->block_graph[current_block].succ;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
current_arc = current_arc->succ_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_dbus_assert (current_arc != NULL);
|
|
|
|
|
_dbus_assert (!current_arc->on_tree);
|
|
|
|
|
|
|
|
|
|
current_arc->arc_count = val;
|
|
|
|
|
current_arc->count_valid = TRUE;
|
|
|
|
|
current_func->block_graph[current_block].succ_count -= 1;
|
|
|
|
|
current_func->block_graph[current_arc->target].pred_count -= 1;
|
|
|
|
|
|
|
|
|
|
++n_arcs;
|
|
|
|
|
|
|
|
|
|
current_arc = current_arc->succ_next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
|
|
|
|
|
if (n_arcs != claimed_n_arcs)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
|
|
|
|
|
claimed_n_arcs, n_arcs);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("%d arcs in file\n", n_arcs);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
function_solve_graph (Function *func)
|
|
|
|
|
{
|
|
|
|
|
int passes, changes;
|
|
|
|
|
dbus_int64_t total;
|
|
|
|
|
int i;
|
|
|
|
|
Arc *arc;
|
|
|
|
|
Block *block_graph;
|
|
|
|
|
int n_blocks;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("Solving function graph\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
n_blocks = func->n_blocks;
|
|
|
|
|
block_graph = func->block_graph;
|
|
|
|
|
|
|
|
|
|
/* For every block in the file,
|
|
|
|
|
- if every exit/entrance arc has a known count, then set the block count
|
|
|
|
|
- if the block count is known, and every exit/entrance arc but one has
|
|
|
|
|
a known execution count, then set the count of the remaining arc
|
|
|
|
|
|
|
|
|
|
As arc counts are set, decrement the succ/pred count, but don't delete
|
|
|
|
|
the arc, that way we can easily tell when all arcs are known, or only
|
|
|
|
|
one arc is unknown. */
|
|
|
|
|
|
|
|
|
|
/* The order that the basic blocks are iterated through is important.
|
|
|
|
|
Since the code that finds spanning trees starts with block 0, low numbered
|
|
|
|
|
arcs are put on the spanning tree in preference to high numbered arcs.
|
|
|
|
|
Hence, most instrumented arcs are at the end. Graph solving works much
|
|
|
|
|
faster if we propagate numbers from the end to the start.
|
|
|
|
|
|
|
|
|
|
This takes an average of slightly more than 3 passes. */
|
|
|
|
|
|
|
|
|
|
changes = 1;
|
|
|
|
|
passes = 0;
|
|
|
|
|
while (changes)
|
|
|
|
|
{
|
|
|
|
|
passes++;
|
|
|
|
|
changes = 0;
|
|
|
|
|
|
|
|
|
|
for (i = n_blocks - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
if (! block_graph[i].count_valid)
|
|
|
|
|
{
|
|
|
|
|
if (block_graph[i].succ_count == 0)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
for (arc = block_graph[i].succ; arc;
|
|
|
|
|
arc = arc->succ_next)
|
|
|
|
|
total += arc->arc_count;
|
|
|
|
|
block_graph[i].exec_count = total;
|
|
|
|
|
block_graph[i].count_valid = 1;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (block_graph[i].pred_count == 0)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
for (arc = block_graph[i].pred; arc;
|
|
|
|
|
arc = arc->pred_next)
|
|
|
|
|
total += arc->arc_count;
|
|
|
|
|
block_graph[i].exec_count = total;
|
|
|
|
|
block_graph[i].count_valid = 1;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (block_graph[i].count_valid)
|
|
|
|
|
{
|
|
|
|
|
if (block_graph[i].succ_count == 1)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
/* One of the counts will be invalid, but it is zero,
|
|
|
|
|
so adding it in also doesn't hurt. */
|
|
|
|
|
for (arc = block_graph[i].succ; arc;
|
|
|
|
|
arc = arc->succ_next)
|
|
|
|
|
total += arc->arc_count;
|
|
|
|
|
/* Calculate count for remaining arc by conservation. */
|
|
|
|
|
total = block_graph[i].exec_count - total;
|
|
|
|
|
/* Search for the invalid arc, and set its count. */
|
|
|
|
|
for (arc = block_graph[i].succ; arc;
|
|
|
|
|
arc = arc->succ_next)
|
|
|
|
|
if (! arc->count_valid)
|
|
|
|
|
break;
|
|
|
|
|
if (! arc)
|
|
|
|
|
die ("arc == NULL\n");
|
|
|
|
|
arc->count_valid = 1;
|
|
|
|
|
arc->arc_count = total;
|
|
|
|
|
block_graph[i].succ_count -= 1;
|
|
|
|
|
|
|
|
|
|
block_graph[arc->target].pred_count -= 1;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
if (block_graph[i].pred_count == 1)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
/* One of the counts will be invalid, but it is zero,
|
|
|
|
|
so adding it in also doesn't hurt. */
|
|
|
|
|
for (arc = block_graph[i].pred; arc;
|
|
|
|
|
arc = arc->pred_next)
|
|
|
|
|
total += arc->arc_count;
|
|
|
|
|
/* Calculate count for remaining arc by conservation. */
|
|
|
|
|
total = block_graph[i].exec_count - total;
|
|
|
|
|
/* Search for the invalid arc, and set its count. */
|
|
|
|
|
for (arc = block_graph[i].pred; arc;
|
|
|
|
|
arc = arc->pred_next)
|
|
|
|
|
if (! arc->count_valid)
|
|
|
|
|
break;
|
|
|
|
|
if (! arc)
|
|
|
|
|
die ("arc == NULL\n");
|
|
|
|
|
arc->count_valid = 1;
|
|
|
|
|
arc->arc_count = total;
|
|
|
|
|
block_graph[i].pred_count -= 1;
|
|
|
|
|
|
|
|
|
|
block_graph[arc->source].succ_count -= 1;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the graph has been correctly solved, every block will have a
|
|
|
|
|
* succ and pred count of zero.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < n_blocks; i++)
|
|
|
|
|
{
|
|
|
|
|
if (block_graph[i].succ_count || block_graph[i].pred_count)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Block graph solved incorrectly\n");
|
|
|
|
|
fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
|
|
|
|
|
i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
solve_graphs (DBusList **functions)
|
|
|
|
|
{
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
|
|
|
|
|
function_solve_graph (func);
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (functions, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
load_functions_for_c_file (const DBusString *filename,
|
|
|
|
|
DBusList **functions)
|
|
|
|
|
{
|
|
|
|
|
DBusString bbg_filename;
|
|
|
|
|
DBusString da_filename;
|
|
|
|
|
DBusString contents;
|
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
|
|
dbus_error_init (&error);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&bbg_filename) ||
|
|
|
|
|
!_dbus_string_init (&da_filename) ||
|
|
|
|
|
!_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
|
|
|
|
|
!_dbus_string_copy (filename, 0, &da_filename, 0) ||
|
|
|
|
|
!_dbus_string_init (&contents))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
_dbus_string_shorten (&bbg_filename, 2);
|
|
|
|
|
_dbus_string_shorten (&da_filename, 2);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_append (&bbg_filename, ".bbg") ||
|
|
|
|
|
!_dbus_string_append (&da_filename, ".da"))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (!_dbus_file_get_contents (&contents, &bbg_filename,
|
|
|
|
|
&error))
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Could not open file: %s\n",
|
|
|
|
|
error.message);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get_functions_from_bbg (&contents, functions);
|
|
|
|
|
|
|
|
|
|
_dbus_string_set_length (&contents, 0);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_file_get_contents (&contents, &da_filename,
|
|
|
|
|
&error))
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Could not open file: %s\n",
|
|
|
|
|
error.message);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add_counts_from_da (&contents, functions);
|
|
|
|
|
|
|
|
|
|
solve_graphs (functions);
|
|
|
|
|
|
|
|
|
|
_dbus_string_free (&contents);
|
|
|
|
|
_dbus_string_free (&da_filename);
|
|
|
|
|
_dbus_string_free (&bbg_filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_lines_from_bb_file (const DBusString *contents,
|
|
|
|
|
File *fl)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
long val;
|
|
|
|
|
int n_functions;
|
|
|
|
|
dbus_bool_t in_our_file;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
Function *func;
|
|
|
|
|
int block;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("Getting line numbers for blocks from .bb file\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* There's this "filename" field in the .bb file which
|
|
|
|
|
* mysteriously comes *after* the first function in the
|
|
|
|
|
* file in the .bb file; and every .bb file seems to
|
|
|
|
|
* have only one filename. I don't understand
|
|
|
|
|
* what's going on here, so just set in_our_file = TRUE
|
|
|
|
|
* at the start categorically.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
block = 0;
|
|
|
|
|
func = NULL;
|
|
|
|
|
in_our_file = TRUE;
|
|
|
|
|
link = _dbus_list_get_first_link (&fl->functions);
|
|
|
|
|
n_functions = 0;
|
|
|
|
|
i = 0;
|
|
|
|
|
while (string_get_int (contents, i, &val))
|
|
|
|
|
{
|
|
|
|
|
i += 4;
|
|
|
|
|
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
case BB_FILENAME:
|
|
|
|
|
{
|
|
|
|
|
DBusString f;
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&f))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (string_get_string (contents, i,
|
|
|
|
|
BB_FILENAME,
|
|
|
|
|
&f, &i))
|
|
|
|
|
{
|
|
|
|
|
/* fl->name is a full path and the filename in .bb is
|
|
|
|
|
* not.
|
|
|
|
|
*/
|
|
|
|
|
DBusString tmp_str;
|
|
|
|
|
|
|
|
|
|
_dbus_string_init_const (&tmp_str, fl->name);
|
|
|
|
|
|
|
|
|
|
if (_dbus_string_ends_with_c_str (&tmp_str,
|
|
|
|
|
_dbus_string_get_const_data (&f)))
|
|
|
|
|
in_our_file = TRUE;
|
|
|
|
|
else
|
|
|
|
|
in_our_file = FALSE;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
fprintf (stderr,
|
|
|
|
|
"File %s in .bb, looking for %s, in_our_file = %d\n",
|
|
|
|
|
_dbus_string_get_const_data (&f),
|
|
|
|
|
fl->name,
|
|
|
|
|
in_our_file);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
_dbus_string_free (&f);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case BB_FUNCTION:
|
|
|
|
|
{
|
|
|
|
|
DBusString f;
|
|
|
|
|
if (!_dbus_string_init (&f))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (string_get_string (contents, i,
|
|
|
|
|
BB_FUNCTION,
|
|
|
|
|
&f, &i))
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
block = 0;
|
|
|
|
|
|
|
|
|
|
if (in_our_file)
|
|
|
|
|
{
|
|
|
|
|
if (link == NULL)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "No function object for function %s\n",
|
|
|
|
|
_dbus_string_get_const_data (&f));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
func = link->data;
|
|
|
|
|
link = _dbus_list_get_next_link (&fl->functions, link);
|
|
|
|
|
|
|
|
|
|
if (func->name == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!_dbus_string_copy_data (&f, &func->name))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
die ("got two names for function?\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_dbus_string_free (&f);
|
|
|
|
|
|
|
|
|
|
n_functions += 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case BB_ENDOFLIST:
|
|
|
|
|
block += 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
#if 0
|
|
|
|
|
fprintf (stderr, "Line %ld\n", val);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (val >= fl->n_lines)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Line %ld but file only has %d lines\n",
|
|
|
|
|
val, fl->n_lines);
|
|
|
|
|
}
|
|
|
|
|
else if (func != NULL)
|
|
|
|
|
{
|
|
|
|
|
val -= 1; /* To convert the 1-based line number to 0-based */
|
|
|
|
|
_dbus_assert (val >= 0);
|
|
|
|
|
|
|
|
|
|
if (block < func->n_blocks)
|
|
|
|
|
{
|
|
|
|
|
if (!_dbus_list_append (&func->block_graph[block].lines,
|
|
|
|
|
&fl->lines[val]))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!_dbus_list_append (&fl->lines[val].blocks,
|
|
|
|
|
&func->block_graph[block]))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
|
|
|
|
|
block, func->n_blocks);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Line %ld given outside of any function\n",
|
|
|
|
|
val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("%d functions in file\n", n_functions);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
load_block_line_associations (const DBusString *filename,
|
|
|
|
|
File *f)
|
|
|
|
|
{
|
|
|
|
|
DBusString bb_filename;
|
|
|
|
|
DBusString contents;
|
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
|
|
dbus_error_init (&error);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&bb_filename) ||
|
|
|
|
|
!_dbus_string_copy (filename, 0, &bb_filename, 0) ||
|
|
|
|
|
!_dbus_string_init (&contents))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
_dbus_string_shorten (&bb_filename, 2);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_append (&bb_filename, ".bb"))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (!_dbus_file_get_contents (&contents, &bb_filename,
|
|
|
|
|
&error))
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Could not open file: %s\n",
|
|
|
|
|
error.message);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get_lines_from_bb_file (&contents, f);
|
|
|
|
|
|
|
|
|
|
_dbus_string_free (&contents);
|
|
|
|
|
_dbus_string_free (&bb_filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
count_lines_in_string (const DBusString *str)
|
|
|
|
|
{
|
|
|
|
|
int n_lines;
|
|
|
|
|
const char *p;
|
|
|
|
|
const char *prev;
|
|
|
|
|
const char *end;
|
|
|
|
|
const char *last_line_end;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("Counting lines in source file\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
n_lines = 0;
|
|
|
|
|
prev = NULL;
|
|
|
|
|
p = _dbus_string_get_const_data (str);
|
|
|
|
|
end = p + _dbus_string_get_length (str);
|
|
|
|
|
last_line_end = p;
|
|
|
|
|
while (p != end)
|
|
|
|
|
{
|
|
|
|
|
/* too lazy to handle \r\n as one linebreak */
|
|
|
|
|
if (*p == '\n' || *p == '\r')
|
|
|
|
|
{
|
|
|
|
|
++n_lines;
|
|
|
|
|
last_line_end = p + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prev = p;
|
|
|
|
|
++p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (last_line_end != p)
|
|
|
|
|
++n_lines;
|
|
|
|
|
|
|
|
|
|
return n_lines;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fill_line_content (const DBusString *str,
|
|
|
|
|
Line *lines)
|
|
|
|
|
{
|
|
|
|
|
int n_lines;
|
|
|
|
|
const char *p;
|
|
|
|
|
const char *prev;
|
|
|
|
|
const char *end;
|
|
|
|
|
const char *last_line_end;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
printf ("Saving contents of each line in source file\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
n_lines = 0;
|
|
|
|
|
prev = NULL;
|
|
|
|
|
p = _dbus_string_get_const_data (str);
|
|
|
|
|
end = p + _dbus_string_get_length (str);
|
|
|
|
|
last_line_end = p;
|
|
|
|
|
while (p != end)
|
|
|
|
|
{
|
|
|
|
|
if (*p == '\n' || *p == '\r')
|
|
|
|
|
{
|
|
|
|
|
lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
|
|
|
|
|
if (lines[n_lines].text == NULL)
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
|
|
|
|
|
lines[n_lines].number = n_lines + 1;
|
|
|
|
|
|
|
|
|
|
++n_lines;
|
|
|
|
|
|
|
|
|
|
last_line_end = p + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prev = p;
|
|
|
|
|
++p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p != last_line_end)
|
|
|
|
|
{
|
|
|
|
|
memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
|
|
|
|
|
++n_lines;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mark_unused_functions (File *f)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&f->functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
dbus_bool_t used;
|
|
|
|
|
|
|
|
|
|
used = FALSE;
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < func->n_blocks)
|
|
|
|
|
{
|
|
|
|
|
if (func->block_graph[i].exec_count > 0)
|
|
|
|
|
used = TRUE;
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!used)
|
|
|
|
|
func->unused = TRUE;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&f->functions, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mark_inside_dbus_build_tests (File *f)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
int inside_depth;
|
|
|
|
|
|
|
|
|
|
inside_depth = 0;
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < f->n_lines)
|
|
|
|
|
{
|
|
|
|
|
Line *l = &f->lines[i];
|
|
|
|
|
|
|
|
|
|
if (inside_depth == 0)
|
|
|
|
|
{
|
|
|
|
|
const char *a, *b;
|
|
|
|
|
|
|
|
|
|
a = strstr (l->text, "#ifdef");
|
|
|
|
|
b = strstr (l->text, "DBUS_BUILD_TESTS");
|
|
|
|
|
if (a && b)
|
|
|
|
|
inside_depth += 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (strstr (l->text, "#if") != NULL)
|
|
|
|
|
inside_depth += 1;
|
|
|
|
|
else if (strstr (l->text, "#endif") != NULL)
|
|
|
|
|
inside_depth -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inside_depth > 0)
|
|
|
|
|
{
|
|
|
|
|
/* Mark the line and its blocks */
|
|
|
|
|
DBusList *blink;
|
|
|
|
|
|
|
|
|
|
l->inside_dbus_build_tests = TRUE;
|
|
|
|
|
|
|
|
|
|
blink = _dbus_list_get_first_link (&l->blocks);
|
|
|
|
|
while (blink != NULL)
|
|
|
|
|
{
|
|
|
|
|
Block *b = blink->data;
|
|
|
|
|
|
|
|
|
|
b->inside_dbus_build_tests = TRUE;
|
|
|
|
|
|
|
|
|
|
blink = _dbus_list_get_next_link (&l->blocks, blink);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now mark functions where for all blocks that are associated
|
|
|
|
|
* with a source line, the block is inside_dbus_build_tests.
|
|
|
|
|
*/
|
|
|
|
|
link = _dbus_list_get_first_link (&f->functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < func->n_blocks)
|
|
|
|
|
{
|
|
|
|
|
/* Break as soon as any block is not a test block */
|
|
|
|
|
if (func->block_graph[i].lines != NULL &&
|
|
|
|
|
!func->block_graph[i].inside_dbus_build_tests)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == func->n_blocks)
|
|
|
|
|
func->inside_dbus_build_tests = TRUE;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&f->functions, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mark_partials (File *f)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < f->n_lines)
|
|
|
|
|
{
|
|
|
|
|
Line *l = &f->lines[i];
|
|
|
|
|
DBusList *blink;
|
|
|
|
|
int n_blocks;
|
|
|
|
|
int n_blocks_executed;
|
|
|
|
|
|
|
|
|
|
n_blocks = 0;
|
|
|
|
|
n_blocks_executed = 0;
|
|
|
|
|
blink = _dbus_list_get_first_link (&l->blocks);
|
|
|
|
|
while (blink != NULL)
|
|
|
|
|
{
|
|
|
|
|
Block *b = blink->data;
|
|
|
|
|
|
|
|
|
|
if (b->exec_count > 0)
|
|
|
|
|
n_blocks_executed += 1;
|
|
|
|
|
|
|
|
|
|
n_blocks += 1;
|
|
|
|
|
|
|
|
|
|
blink = _dbus_list_get_next_link (&l->blocks, blink);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n_blocks_executed > 0 &&
|
|
|
|
|
n_blocks_executed < n_blocks)
|
|
|
|
|
l->partial = TRUE;
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&f->functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
int i;
|
|
|
|
|
int n_blocks;
|
|
|
|
|
int n_blocks_executed;
|
|
|
|
|
|
|
|
|
|
n_blocks = 0;
|
|
|
|
|
n_blocks_executed = 0;
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < func->n_blocks)
|
|
|
|
|
{
|
|
|
|
|
/* Break as soon as any block is not a test block */
|
|
|
|
|
if (func->block_graph[i].exec_count > 0)
|
|
|
|
|
n_blocks_executed += 1;
|
|
|
|
|
|
|
|
|
|
n_blocks += 1;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n_blocks_executed > 0 &&
|
|
|
|
|
n_blocks_executed < n_blocks)
|
|
|
|
|
func->partial = TRUE;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&f->functions, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static File*
|
|
|
|
|
load_c_file (const DBusString *filename)
|
|
|
|
|
{
|
|
|
|
|
DBusString contents;
|
|
|
|
|
DBusError error;
|
|
|
|
|
File *f;
|
|
|
|
|
|
|
|
|
|
f = dbus_new0 (File, 1);
|
|
|
|
|
if (f == NULL)
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_copy_data (filename, &f->name))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&contents))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
dbus_error_init (&error);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_file_get_contents (&contents, filename,
|
|
|
|
|
&error))
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Could not open file: %s\n",
|
|
|
|
|
error.message);
|
|
|
|
|
dbus_error_free (&error);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
load_functions_for_c_file (filename, &f->functions);
|
|
|
|
|
|
|
|
|
|
f->n_lines = count_lines_in_string (&contents);
|
|
|
|
|
f->lines = dbus_new0 (Line, f->n_lines);
|
|
|
|
|
if (f->lines == NULL)
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
fill_line_content (&contents, f->lines);
|
|
|
|
|
|
|
|
|
|
_dbus_string_free (&contents);
|
|
|
|
|
|
|
|
|
|
load_block_line_associations (filename, f);
|
|
|
|
|
|
|
|
|
|
mark_unused_functions (f);
|
|
|
|
|
mark_inside_dbus_build_tests (f);
|
|
|
|
|
mark_partials (f);
|
|
|
|
|
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct Stats Stats;
|
|
|
|
|
|
|
|
|
|
struct Stats
|
|
|
|
|
{
|
|
|
|
|
int n_blocks;
|
|
|
|
|
int n_blocks_executed;
|
|
|
|
|
int n_blocks_inside_dbus_build_tests;
|
|
|
|
|
|
|
|
|
|
int n_lines; /* lines that have blocks on them */
|
|
|
|
|
int n_lines_executed;
|
|
|
|
|
int n_lines_partial;
|
|
|
|
|
int n_lines_inside_dbus_build_tests;
|
|
|
|
|
|
|
|
|
|
int n_functions;
|
|
|
|
|
int n_functions_executed;
|
|
|
|
|
int n_functions_partial;
|
|
|
|
|
int n_functions_inside_dbus_build_tests;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static dbus_bool_t
|
|
|
|
|
line_was_executed (Line *l)
|
|
|
|
|
{
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&l->blocks);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Block *b = link->data;
|
|
|
|
|
|
|
|
|
|
if (b->exec_count > 0)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&l->blocks, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
line_exec_count (Line *l)
|
|
|
|
|
{
|
|
|
|
|
DBusList *link;
|
|
|
|
|
dbus_int64_t total;
|
|
|
|
|
|
|
|
|
|
total = 0;
|
|
|
|
|
link = _dbus_list_get_first_link (&l->blocks);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Block *b = link->data;
|
|
|
|
|
|
|
|
|
|
total += b->exec_count;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&l->blocks, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
merge_stats_for_file (Stats *stats,
|
|
|
|
|
File *f)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < f->n_lines; ++i)
|
|
|
|
|
{
|
|
|
|
|
Line *l = &f->lines[i];
|
|
|
|
|
|
|
|
|
|
if (l->inside_dbus_build_tests)
|
|
|
|
|
{
|
|
|
|
|
stats->n_lines_inside_dbus_build_tests += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (line_was_executed (l))
|
|
|
|
|
stats->n_lines_executed += 1;
|
|
|
|
|
|
|
|
|
|
if (l->blocks != NULL)
|
|
|
|
|
stats->n_lines += 1;
|
|
|
|
|
|
|
|
|
|
if (l->partial)
|
|
|
|
|
stats->n_lines_partial += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&f->functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
|
|
|
|
|
if (func->inside_dbus_build_tests)
|
|
|
|
|
stats->n_functions_inside_dbus_build_tests += 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
stats->n_functions += 1;
|
|
|
|
|
|
|
|
|
|
if (!func->unused)
|
|
|
|
|
stats->n_functions_executed += 1;
|
|
|
|
|
|
|
|
|
|
if (func->partial)
|
|
|
|
|
stats->n_functions_partial += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < func->n_blocks)
|
|
|
|
|
{
|
|
|
|
|
Block *b = &func->block_graph[i];
|
|
|
|
|
|
|
|
|
|
if (b->inside_dbus_build_tests)
|
|
|
|
|
stats->n_blocks_inside_dbus_build_tests += 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (b->exec_count > 0)
|
|
|
|
|
stats->n_blocks_executed += 1;
|
|
|
|
|
|
|
|
|
|
stats->n_blocks += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&f->functions, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The output of this matches gcov exactly ("diff" shows no difference) */
|
|
|
|
|
static void
|
|
|
|
|
print_annotated_source_gcov_format (File *f)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < f->n_lines)
|
|
|
|
|
{
|
|
|
|
|
Line *l = &f->lines[i];
|
|
|
|
|
|
|
|
|
|
if (l->blocks != NULL)
|
|
|
|
|
{
|
|
|
|
|
int exec_count;
|
|
|
|
|
|
|
|
|
|
exec_count = line_exec_count (l);
|
|
|
|
|
|
|
|
|
|
if (exec_count > 0)
|
|
|
|
|
printf ("%12d %s\n",
|
|
|
|
|
exec_count, l->text);
|
|
|
|
|
else
|
|
|
|
|
printf (" ###### %s\n", l->text);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf ("\t\t%s\n", l->text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_annotated_source (File *f)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < f->n_lines)
|
|
|
|
|
{
|
|
|
|
|
Line *l = &f->lines[i];
|
|
|
|
|
|
|
|
|
|
if (l->inside_dbus_build_tests)
|
|
|
|
|
printf ("*");
|
|
|
|
|
else
|
|
|
|
|
printf (" ");
|
|
|
|
|
|
|
|
|
|
if (l->blocks != NULL)
|
|
|
|
|
{
|
|
|
|
|
int exec_count;
|
|
|
|
|
|
|
|
|
|
exec_count = line_exec_count (l);
|
|
|
|
|
|
|
|
|
|
if (exec_count > 0)
|
|
|
|
|
printf ("%12d %s\n",
|
|
|
|
|
exec_count, l->text);
|
|
|
|
|
else
|
|
|
|
|
printf (" ###### %s\n", l->text);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf ("\t\t%s\n", l->text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_block_superdetails (File *f)
|
|
|
|
|
{
|
|
|
|
|
DBusList *link;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&f->functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
|
|
|
|
|
printf ("=== %s():\n", func->name);
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (i < func->n_blocks)
|
|
|
|
|
{
|
|
|
|
|
Block *b = &func->block_graph[i];
|
|
|
|
|
DBusList *l;
|
|
|
|
|
|
|
|
|
|
printf (" %5d executed %d times%s\n", i,
|
|
|
|
|
(int) b->exec_count,
|
|
|
|
|
b->inside_dbus_build_tests ?
|
|
|
|
|
" [inside DBUS_BUILD_TESTS]" : "");
|
|
|
|
|
|
|
|
|
|
l = _dbus_list_get_first_link (&b->lines);
|
|
|
|
|
while (l != NULL)
|
|
|
|
|
{
|
|
|
|
|
Line *line = l->data;
|
|
|
|
|
|
|
|
|
|
printf ("4%d\t%s\n", line->number, line->text);
|
|
|
|
|
|
|
|
|
|
l = _dbus_list_get_next_link (&b->lines, l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&f->functions, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_one_file (const DBusString *filename)
|
|
|
|
|
{
|
|
|
|
|
if (_dbus_string_ends_with_c_str (filename, ".bb"))
|
|
|
|
|
{
|
|
|
|
|
DBusString contents;
|
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&contents))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
dbus_error_init (&error);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_file_get_contents (&contents, filename,
|
|
|
|
|
&error))
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Could not open file: %s\n",
|
|
|
|
|
error.message);
|
|
|
|
|
dbus_error_free (&error);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dump_bb_file (&contents);
|
|
|
|
|
|
|
|
|
|
_dbus_string_free (&contents);
|
|
|
|
|
}
|
|
|
|
|
else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
|
|
|
|
|
{
|
|
|
|
|
DBusString contents;
|
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&contents))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
dbus_error_init (&error);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_file_get_contents (&contents, filename,
|
|
|
|
|
&error))
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Could not open file: %s\n",
|
|
|
|
|
error.message);
|
|
|
|
|
dbus_error_free (&error);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dump_bbg_file (&contents);
|
|
|
|
|
|
|
|
|
|
_dbus_string_free (&contents);
|
|
|
|
|
}
|
|
|
|
|
else if (_dbus_string_ends_with_c_str (filename, ".da"))
|
|
|
|
|
{
|
|
|
|
|
DBusString contents;
|
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&contents))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
|
|
|
|
|
dbus_error_init (&error);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_file_get_contents (&contents, filename,
|
|
|
|
|
&error))
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Could not open file: %s\n",
|
|
|
|
|
error.message);
|
|
|
|
|
dbus_error_free (&error);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dump_da_file (&contents);
|
|
|
|
|
|
|
|
|
|
_dbus_string_free (&contents);
|
|
|
|
|
}
|
|
|
|
|
else if (_dbus_string_ends_with_c_str (filename, ".c"))
|
|
|
|
|
{
|
|
|
|
|
File *f;
|
|
|
|
|
|
|
|
|
|
f = load_c_file (filename);
|
|
|
|
|
|
|
|
|
|
print_annotated_source (f);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Unknown file type %s\n",
|
|
|
|
|
_dbus_string_get_const_data (filename));
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_untested_functions (File *f)
|
|
|
|
|
{
|
|
|
|
|
DBusList *link;
|
|
|
|
|
dbus_bool_t found;
|
|
|
|
|
|
|
|
|
|
found = FALSE;
|
|
|
|
|
link = _dbus_list_get_first_link (&f->functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
|
|
|
|
|
if (func->unused &&
|
|
|
|
|
!func->inside_dbus_build_tests)
|
|
|
|
|
found = TRUE;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&f->functions, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
printf ("Untested functions in %s\n", f->name);
|
|
|
|
|
printf ("=======\n");
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&f->functions);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
Function *func = link->data;
|
|
|
|
|
|
|
|
|
|
if (func->unused &&
|
|
|
|
|
!func->inside_dbus_build_tests)
|
|
|
|
|
printf (" %s\n", func->name);
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&f->functions, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-05 17:04:23 +00:00
|
|
|
static void
|
|
|
|
|
print_stats (Stats *stats,
|
|
|
|
|
const char *of_what)
|
|
|
|
|
{
|
|
|
|
|
int completely;
|
|
|
|
|
|
|
|
|
|
printf ("Summary (%s)\n", of_what);
|
|
|
|
|
printf ("=======\n");
|
|
|
|
|
printf (" %g%% blocks executed (%d of %d)\n",
|
|
|
|
|
(stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
|
|
|
|
|
stats->n_blocks_executed,
|
|
|
|
|
stats->n_blocks);
|
|
|
|
|
|
|
|
|
|
printf (" (ignored %d blocks inside DBUS_BUILD_TESTS)\n",
|
|
|
|
|
stats->n_blocks_inside_dbus_build_tests);
|
|
|
|
|
|
|
|
|
|
printf (" %g%% functions executed (%d of %d)\n",
|
|
|
|
|
(stats->n_functions_executed / (double) stats->n_functions) * 100.0,
|
|
|
|
|
stats->n_functions_executed,
|
|
|
|
|
stats->n_functions);
|
|
|
|
|
|
|
|
|
|
completely = stats->n_functions_executed - stats->n_functions_partial;
|
|
|
|
|
printf (" %g%% functions completely executed (%d of %d)\n",
|
|
|
|
|
(completely / (double) stats->n_functions) * 100.0,
|
|
|
|
|
completely,
|
|
|
|
|
stats->n_functions);
|
|
|
|
|
|
|
|
|
|
printf (" (ignored %d functions inside DBUS_BUILD_TESTS)\n",
|
|
|
|
|
stats->n_functions_inside_dbus_build_tests);
|
|
|
|
|
|
|
|
|
|
printf (" %g%% lines executed (%d of %d)\n",
|
|
|
|
|
(stats->n_lines_executed / (double) stats->n_lines) * 100.0,
|
|
|
|
|
stats->n_lines_executed,
|
|
|
|
|
stats->n_lines);
|
|
|
|
|
|
|
|
|
|
completely = stats->n_lines_executed - stats->n_lines_partial;
|
|
|
|
|
printf (" %g%% lines completely executed (%d of %d)\n",
|
|
|
|
|
(completely / (double) stats->n_lines) * 100.0,
|
|
|
|
|
completely,
|
|
|
|
|
stats->n_lines);
|
|
|
|
|
|
|
|
|
|
printf (" (ignored %d lines inside DBUS_BUILD_TESTS)\n",
|
|
|
|
|
stats->n_lines_inside_dbus_build_tests);
|
|
|
|
|
|
|
|
|
|
printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-05 10:04:04 +00:00
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
MODE_PRINT,
|
|
|
|
|
MODE_REPORT,
|
|
|
|
|
MODE_BLOCKS,
|
|
|
|
|
MODE_GCOV
|
|
|
|
|
} Mode;
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
DBusString filename;
|
|
|
|
|
int i;
|
|
|
|
|
Mode m;
|
|
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Must specify files on command line\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m = MODE_PRINT;
|
|
|
|
|
i = 1;
|
|
|
|
|
|
|
|
|
|
if (strcmp (argv[i], "--report") == 0)
|
|
|
|
|
{
|
|
|
|
|
m = MODE_REPORT;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp (argv[i], "--blocks") == 0)
|
|
|
|
|
{
|
|
|
|
|
m = MODE_BLOCKS;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp (argv[i], "--gcov") == 0)
|
|
|
|
|
{
|
|
|
|
|
m = MODE_GCOV;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i == argc)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Must specify files on command line\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m == MODE_PRINT)
|
|
|
|
|
{
|
|
|
|
|
while (i < argc)
|
|
|
|
|
{
|
|
|
|
|
_dbus_string_init_const (&filename, argv[i]);
|
|
|
|
|
|
|
|
|
|
print_one_file (&filename);
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (m == MODE_BLOCKS || m == MODE_GCOV)
|
|
|
|
|
{
|
|
|
|
|
while (i < argc)
|
|
|
|
|
{
|
|
|
|
|
File *f;
|
|
|
|
|
|
|
|
|
|
_dbus_string_init_const (&filename, argv[i]);
|
|
|
|
|
|
|
|
|
|
f = load_c_file (&filename);
|
|
|
|
|
|
|
|
|
|
if (m == MODE_BLOCKS)
|
|
|
|
|
print_block_superdetails (f);
|
|
|
|
|
else if (m == MODE_GCOV)
|
|
|
|
|
print_annotated_source_gcov_format (f);
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (m == MODE_REPORT)
|
|
|
|
|
{
|
|
|
|
|
Stats stats = { 0, };
|
|
|
|
|
DBusList *files;
|
|
|
|
|
DBusList *link;
|
2003-04-05 17:04:23 +00:00
|
|
|
DBusHashTable *stats_by_dir;
|
|
|
|
|
DBusHashIter iter;
|
2003-04-05 10:04:04 +00:00
|
|
|
|
|
|
|
|
files = NULL;
|
|
|
|
|
while (i < argc)
|
|
|
|
|
{
|
|
|
|
|
_dbus_string_init_const (&filename, argv[i]);
|
|
|
|
|
|
|
|
|
|
if (_dbus_string_ends_with_c_str (&filename, ".c"))
|
|
|
|
|
{
|
|
|
|
|
File *f;
|
|
|
|
|
|
|
|
|
|
f = load_c_file (&filename);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_list_append (&files, f))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Unknown file type %s\n",
|
|
|
|
|
_dbus_string_get_const_data (&filename));
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&files);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
File *f = link->data;
|
|
|
|
|
|
|
|
|
|
merge_stats_for_file (&stats, f);
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&files, link);
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-05 17:04:23 +00:00
|
|
|
print_stats (&stats, "all files");
|
2003-04-05 10:04:04 +00:00
|
|
|
|
2003-04-05 17:04:23 +00:00
|
|
|
stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
|
|
|
|
|
dbus_free, dbus_free);
|
2003-04-05 10:04:04 +00:00
|
|
|
|
2003-04-05 17:04:23 +00:00
|
|
|
link = _dbus_list_get_first_link (&files);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
File *f = link->data;
|
|
|
|
|
DBusString dirname;
|
|
|
|
|
char *dirname_c;
|
|
|
|
|
Stats *dir_stats;
|
|
|
|
|
|
|
|
|
|
_dbus_string_init_const (&filename, f->name);
|
|
|
|
|
|
|
|
|
|
if (!_dbus_string_init (&dirname))
|
|
|
|
|
die ("no memory\n");
|
2003-04-05 10:04:04 +00:00
|
|
|
|
2003-04-05 17:04:23 +00:00
|
|
|
if (!_dbus_string_get_dirname (&filename, &dirname) ||
|
|
|
|
|
!_dbus_string_copy_data (&dirname, &dirname_c))
|
|
|
|
|
die ("no memory\n");
|
2003-04-05 10:04:04 +00:00
|
|
|
|
2003-04-05 17:04:23 +00:00
|
|
|
dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
|
|
|
|
|
dirname_c);
|
|
|
|
|
|
|
|
|
|
if (dir_stats == NULL)
|
|
|
|
|
{
|
|
|
|
|
dir_stats = dbus_new0 (Stats, 1);
|
|
|
|
|
if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
|
|
|
|
|
dir_stats))
|
|
|
|
|
die ("no memory\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
dbus_free (dirname_c);
|
|
|
|
|
|
|
|
|
|
merge_stats_for_file (dir_stats, f);
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&files, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_dbus_hash_iter_init (stats_by_dir, &iter);
|
|
|
|
|
while (_dbus_hash_iter_next (&iter))
|
|
|
|
|
{
|
|
|
|
|
const char *dirname = _dbus_hash_iter_get_string_key (&iter);
|
|
|
|
|
Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
|
|
|
|
|
|
|
|
|
|
print_stats (dir_stats, dirname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_dbus_hash_table_unref (stats_by_dir);
|
2003-04-05 10:04:04 +00:00
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&files);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
File *f = link->data;
|
|
|
|
|
|
|
|
|
|
print_untested_functions (f);
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&files, link);
|
2003-04-05 17:04:23 +00:00
|
|
|
}
|
2003-04-05 10:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|