1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ofdbus/dbus/tsrc/testapps/dbus_test_cases/decode-gcov.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,2666 @@
1.4 +
1.5 + /* -*- mode: C; c-file-style: "gnu" -*- */
1.6 +/* decode-gcov.c gcov decoder program
1.7 + *
1.8 + * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
1.9 + * Copyright (C) 2003 Red Hat Inc.
1.10 + *
1.11 + * Partially derived from gcov,
1.12 + * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
1.13 + * 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
1.14 + *
1.15 + * This file is NOT licensed under the Academic Free License
1.16 + * as it is largely derived from gcov.c and gcov-io.h in the
1.17 + * gcc source code.
1.18 + *
1.19 + * This program is free software; you can redistribute it and/or modify
1.20 + * it under the terms of the GNU General Public License as published by
1.21 + * the Free Software Foundation; either version 2 of the License, or
1.22 + * (at your option) any later version.
1.23 + *
1.24 + * This program is distributed in the hope that it will be useful,
1.25 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.26 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.27 + * GNU General Public License for more details.
1.28 + *
1.29 + * You should have received a copy of the GNU General Public License
1.30 + * along with this program; if not, write to the Free Software
1.31 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.32 + *
1.33 + */
1.34 +
1.35 +#define DBUS_COMPILATION /* cheat */
1.36 +#ifndef __SYMBIAN32__
1.37 +#include <dbus/dbus-list.h>
1.38 +#include <dbus/dbus-string.h>
1.39 +#include <dbus/dbus-sysdeps.h>
1.40 +#include <dbus/dbus-hash.h>
1.41 +#else
1.42 +#include "dbus-list.h"
1.43 +#include "dbus-string.h"
1.44 +#include "dbus-sysdeps.h"
1.45 +#include "dbus-hash.h"
1.46 +#endif
1.47 +
1.48 +
1.49 +#undef DBUS_COMPILATION
1.50 +#include <stdio.h>
1.51 +#include <stdlib.h>
1.52 +#include <string.h>
1.53 +
1.54 +#ifdef SYMBIAN
1.55 +#define DBUS_HAVE_INT64 1
1.56 +#endif
1.57 +
1.58 +#ifndef DBUS_HAVE_INT64
1.59 +#error "gcov support can't be built without 64-bit integer support"
1.60 +#endif
1.61 +
1.62 +static void
1.63 +die (const char *message)
1.64 +{
1.65 + fprintf (stderr, "%s", message);
1.66 + exit (1);
1.67 +}
1.68 +
1.69 +/* This bizarro function is from gcov-io.h in gcc source tree */
1.70 +static int
1.71 +fetch_long (long *dest,
1.72 + const char *source,
1.73 + size_t bytes)
1.74 +{
1.75 + long value = 0;
1.76 + int i;
1.77 +
1.78 + for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
1.79 + if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
1.80 + return 1;
1.81 +
1.82 + for (; i >= 0; i--)
1.83 + value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
1.84 +
1.85 + if ((source[bytes - 1] & 128) && (value > 0))
1.86 + value = - value;
1.87 +
1.88 + *dest = value;
1.89 + return 0;
1.90 +}
1.91 +
1.92 +static int
1.93 +fetch_long64 (dbus_int64_t *dest,
1.94 + const char *source,
1.95 + size_t bytes)
1.96 +{
1.97 + dbus_int64_t value = 0;
1.98 + int i;
1.99 +
1.100 + for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
1.101 + if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
1.102 + return 1;
1.103 +
1.104 + for (; i >= 0; i--)
1.105 + value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
1.106 +
1.107 + if ((source[bytes - 1] & 128) && (value > 0))
1.108 + value = - value;
1.109 +
1.110 + *dest = value;
1.111 + return 0;
1.112 +}
1.113 +
1.114 +#define BB_FILENAME (-1)
1.115 +#define BB_FUNCTION (-2)
1.116 +#define BB_ENDOFLIST 0
1.117 +
1.118 +static dbus_bool_t
1.119 +string_get_int (const DBusString *str,
1.120 + int start,
1.121 + long *val)
1.122 +{
1.123 + const char *p;
1.124 +
1.125 + if ((_dbus_string_get_length (str) - start) < 4)
1.126 + return FALSE;
1.127 +
1.128 + p = _dbus_string_get_const_data (str);
1.129 +
1.130 + p += start;
1.131 +
1.132 + fetch_long (val, p, 4);
1.133 +
1.134 + return TRUE;
1.135 +}
1.136 +
1.137 +static dbus_bool_t
1.138 +string_get_int64 (const DBusString *str,
1.139 + int start,
1.140 + dbus_int64_t *val)
1.141 +{
1.142 + const char *p;
1.143 +
1.144 + if ((_dbus_string_get_length (str) - start) < 8)
1.145 + return FALSE;
1.146 +
1.147 + p = _dbus_string_get_const_data (str);
1.148 +
1.149 + p += start;
1.150 +
1.151 + fetch_long64 (val, p, 8);
1.152 +
1.153 + return TRUE;
1.154 +}
1.155 +
1.156 +static dbus_bool_t
1.157 +string_get_string (const DBusString *str,
1.158 + int start,
1.159 + long terminator,
1.160 + DBusString *val,
1.161 + int *end)
1.162 +{
1.163 + int i;
1.164 + long n;
1.165 +
1.166 + i = start;
1.167 + while (string_get_int (str, i, &n))
1.168 + {
1.169 + unsigned char b;
1.170 +
1.171 + i += 4;
1.172 +
1.173 + if (n == terminator)
1.174 + break;
1.175 +
1.176 + b = n & 0xff;
1.177 + if (b)
1.178 + {
1.179 + _dbus_string_append_byte (val, b);
1.180 + b = (n >> 8) & 0xff;
1.181 + if (b)
1.182 + {
1.183 + _dbus_string_append_byte (val, b);
1.184 + b = (n >> 16) & 0xff;
1.185 + if (b)
1.186 + {
1.187 + _dbus_string_append_byte (val, b);
1.188 + b = (n >> 24) & 0xff;
1.189 + if (b)
1.190 + _dbus_string_append_byte (val, b);
1.191 + }
1.192 + }
1.193 + }
1.194 + }
1.195 +
1.196 + *end = i;
1.197 +
1.198 + return TRUE;
1.199 +}
1.200 +
1.201 +#ifdef DBUS_HAVE_GCC33_GCOV
1.202 +/* In gcc33 .bbg files, there's a function name of the form:
1.203 + * -1, length, name (padded to 4), -1, checksum
1.204 + */
1.205 +static dbus_bool_t
1.206 +string_get_function (const DBusString *str,
1.207 + int start,
1.208 + DBusString *funcname,
1.209 + int *checksum,
1.210 + int *next)
1.211 +{
1.212 + int end;
1.213 + long val;
1.214 + int i;
1.215 +
1.216 + i = start;
1.217 +
1.218 + if (!string_get_int (str, i, &val))
1.219 + die ("no room for -1 before function name\n");
1.220 +
1.221 + i += 4;
1.222 +
1.223 + if (val != -1)
1.224 + die ("value before function name is not -1\n");
1.225 +
1.226 + if (!string_get_int (str, i, &val))
1.227 + die ("no length found for function name\n");
1.228 +
1.229 + i += 4;
1.230 +
1.231 + end = i + val;
1.232 + if (end > _dbus_string_get_length (str))
1.233 + die ("Function name length points past end of file\n");
1.234 +
1.235 + if (!_dbus_string_append (funcname,
1.236 + _dbus_string_get_const_data (str) + i))
1.237 + die ("no memory\n");
1.238 +
1.239 + /* skip alignment padding the length doesn't include the nul so add 1
1.240 + */
1.241 + i = _DBUS_ALIGN_VALUE (end + 1, 4);
1.242 +
1.243 + if (!string_get_int (str, i, &val) ||
1.244 + val != -1)
1.245 + die ("-1 at end of function name not found\n");
1.246 +
1.247 + i += 4;
1.248 +
1.249 + if (!string_get_int (str, i, &val))
1.250 + die ("no checksum found at end of function name\n");
1.251 +
1.252 + i += 4;
1.253 +
1.254 + *checksum = val;
1.255 +
1.256 + *next = i;
1.257 +
1.258 + return TRUE;
1.259 +}
1.260 +#endif /* DBUS_HAVE_GCC33_GCOV */
1.261 +
1.262 +static void
1.263 +dump_bb_file (const DBusString *contents)
1.264 +{
1.265 + int i;
1.266 + long val;
1.267 + int n_functions;
1.268 +
1.269 + n_functions = 0;
1.270 + i = 0;
1.271 + while (string_get_int (contents, i, &val))
1.272 + {
1.273 + i += 4;
1.274 +
1.275 + switch (val)
1.276 + {
1.277 + case BB_FILENAME:
1.278 + {
1.279 + DBusString f;
1.280 +
1.281 + if (!_dbus_string_init (&f))
1.282 + die ("no memory\n");
1.283 +
1.284 + if (string_get_string (contents, i,
1.285 + BB_FILENAME,
1.286 + &f, &i))
1.287 + {
1.288 + printf ("File %s\n", _dbus_string_get_const_data (&f));
1.289 + }
1.290 + _dbus_string_free (&f);
1.291 + }
1.292 + break;
1.293 + case BB_FUNCTION:
1.294 + {
1.295 + DBusString f;
1.296 + if (!_dbus_string_init (&f))
1.297 + die ("no memory\n");
1.298 +
1.299 + if (string_get_string (contents, i,
1.300 + BB_FUNCTION,
1.301 + &f, &i))
1.302 + {
1.303 + printf ("Function %s\n", _dbus_string_get_const_data (&f));
1.304 + }
1.305 + _dbus_string_free (&f);
1.306 +
1.307 + n_functions += 1;
1.308 + }
1.309 + break;
1.310 + case BB_ENDOFLIST:
1.311 + printf ("End of block\n");
1.312 + break;
1.313 + default:
1.314 + printf ("Line %ld\n", val);
1.315 + break;
1.316 + }
1.317 + }
1.318 +
1.319 + printf ("%d functions in file\n", n_functions);
1.320 +}
1.321 +
1.322 +#define FLAG_ON_TREE 0x1
1.323 +#define FLAG_FAKE 0x2
1.324 +#define FLAG_FALL_THROUGH 0x4
1.325 +
1.326 +static void
1.327 +dump_bbg_file (const DBusString *contents)
1.328 +{
1.329 + int i;
1.330 + long val;
1.331 + int n_functions;
1.332 + int n_arcs;
1.333 + int n_blocks;
1.334 + int n_arcs_off_tree;
1.335 +
1.336 + n_arcs_off_tree = 0;
1.337 + n_blocks = 0;
1.338 + n_arcs = 0;
1.339 + n_functions = 0;
1.340 + i = 0;
1.341 + while (i < _dbus_string_get_length (contents))
1.342 + {
1.343 + long n_blocks_in_func;
1.344 + long n_arcs_in_func;
1.345 + int j;
1.346 +
1.347 +#ifdef DBUS_HAVE_GCC33_GCOV
1.348 + /* In gcc33 .bbg files, there's a function name of the form:
1.349 + * -1, length, name (padded to 4), -1, checksum
1.350 + * after that header on each function description, it's
1.351 + * the same as in gcc32
1.352 + */
1.353 +
1.354 + {
1.355 + DBusString funcname;
1.356 + int checksum;
1.357 +
1.358 + if (!_dbus_string_init (&funcname))
1.359 + die ("no memory\n");
1.360 +
1.361 + if (!string_get_function (contents, i,
1.362 + &funcname, &checksum, &i))
1.363 + die ("could not read function name\n");
1.364 +
1.365 + printf ("Function name is \"%s\" checksum %d\n",
1.366 + _dbus_string_get_const_data (&funcname),
1.367 + checksum);
1.368 +
1.369 + _dbus_string_free (&funcname);
1.370 + }
1.371 +#endif /* DBUS_HAVE_GCC33_GCOV */
1.372 +
1.373 + if (!string_get_int (contents, i, &val))
1.374 + die ("no count of blocks in func found\n");
1.375 +
1.376 + i += 4;
1.377 +
1.378 + n_blocks_in_func = val;
1.379 +
1.380 + if (!string_get_int (contents, i, &n_arcs_in_func))
1.381 + break;
1.382 +
1.383 + i += 4;
1.384 +
1.385 + printf ("Function has %ld blocks and %ld arcs\n",
1.386 + n_blocks_in_func, n_arcs_in_func);
1.387 +
1.388 + n_functions += 1;
1.389 + n_blocks += n_blocks_in_func;
1.390 + n_arcs += n_arcs_in_func;
1.391 +
1.392 + j = 0;
1.393 + while (j < n_blocks_in_func)
1.394 + {
1.395 + long n_arcs_in_block;
1.396 + int k;
1.397 +
1.398 + if (!string_get_int (contents, i, &n_arcs_in_block))
1.399 + break;
1.400 +
1.401 + i += 4;
1.402 +
1.403 + printf (" Block has %ld arcs\n", n_arcs_in_block);
1.404 +
1.405 + k = 0;
1.406 + while (k < n_arcs_in_block)
1.407 + {
1.408 + long destination_block;
1.409 + long flags;
1.410 +
1.411 + if (!string_get_int (contents, i, &destination_block))
1.412 + break;
1.413 +
1.414 + i += 4;
1.415 +
1.416 + if (!string_get_int (contents, i, &flags))
1.417 + break;
1.418 +
1.419 + i += 4;
1.420 +
1.421 + printf (" Arc has destination block %ld flags 0x%lx\n",
1.422 + destination_block, flags);
1.423 +
1.424 + if ((flags & FLAG_ON_TREE) == 0)
1.425 + n_arcs_off_tree += 1;
1.426 +
1.427 + ++k;
1.428 + }
1.429 +
1.430 + if (k < n_arcs_in_block)
1.431 + break;
1.432 +
1.433 + ++j;
1.434 + }
1.435 +
1.436 + if (j < n_blocks_in_func)
1.437 + break;
1.438 +
1.439 + if (!string_get_int (contents, i, &val))
1.440 + break;
1.441 +
1.442 + i += 4;
1.443 +
1.444 + if (val != -1)
1.445 + die ("-1 separator not found\n");
1.446 + }
1.447 +
1.448 + printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
1.449 + n_functions, n_blocks, n_arcs, n_arcs_off_tree);
1.450 +}
1.451 +
1.452 +#ifndef DBUS_HAVE_GCC33_GCOV
1.453 +
1.454 +/* gcc 3.2 version:
1.455 + * The da file contains first a count of arcs in the file,
1.456 + * then a count of executions for all "off tree" arcs
1.457 + * in the file.
1.458 + */
1.459 +static void
1.460 +dump_da_file (const DBusString *contents)
1.461 +{
1.462 + int i;
1.463 + dbus_int64_t val;
1.464 + int n_arcs;
1.465 + int claimed_n_arcs;
1.466 +
1.467 + i = 0;
1.468 + if (!string_get_int64 (contents, i, &val))
1.469 + return;
1.470 +
1.471 + i += 8;
1.472 +
1.473 + printf ("%ld arcs in file\n", (long) val);
1.474 + claimed_n_arcs = val;
1.475 +
1.476 + n_arcs = 0;
1.477 + while (string_get_int64 (contents, i, &val))
1.478 + {
1.479 + i += 8;
1.480 +
1.481 + printf ("%ld executions of arc %d\n",
1.482 + (long) val, n_arcs);
1.483 +
1.484 + ++n_arcs;
1.485 + }
1.486 +
1.487 + if (n_arcs != claimed_n_arcs)
1.488 + {
1.489 + printf ("File claimed to have %d arcs but only had %d\n",
1.490 + claimed_n_arcs, n_arcs);
1.491 + }
1.492 +}
1.493 +
1.494 +#else /* DBUS_HAVE_GCC33_GCOV */
1.495 +
1.496 +/* gcc 3.3 version:
1.497 + * The da file is more complex than 3.2.
1.498 + *
1.499 + * We have a magic value of "-123" only it isn't really
1.500 + * -123, it's -123 as encoded by the crackass gcov-io.h
1.501 + * routines. Anyway, 4 bytes.
1.502 + *
1.503 + * We then have:
1.504 + *
1.505 + * - 4 byte count of how many functions in the following list
1.506 + * - 4 byte length of random extra data
1.507 + * - the random extra data, just skip it, info pages have some
1.508 + * details on what might be in there or see __bb_exit_func in gcc
1.509 + * - then for each function (number of functions given above):
1.510 + * . -1, length, funcname, alignment padding, -1
1.511 + * . checksum
1.512 + * . 4 byte number of arcs in function
1.513 + * . 8 bytes each, a count of execution for each arc
1.514 + *
1.515 + * Now, the whole thing *starting with the magic* can repeat.
1.516 + * This is caused by multiple runs of the profiled app appending
1.517 + * to the file.
1.518 + */
1.519 +static void
1.520 +dump_da_file (const DBusString *contents)
1.521 +{
1.522 + int i;
1.523 + dbus_int64_t v64;
1.524 + long val;
1.525 + int n_sections;
1.526 + int total_functions;
1.527 +
1.528 + total_functions = 0;
1.529 + n_sections = 0;
1.530 +
1.531 + i = 0;
1.532 + while (i < _dbus_string_get_length (contents))
1.533 + {
1.534 + int claimed_n_functions;
1.535 + int n_functions;
1.536 + int total_arcs;
1.537 +
1.538 + printf (".da file section %d\n", n_sections);
1.539 +
1.540 + if (!string_get_int (contents, i, &val))
1.541 + die ("no magic found in .da file\n");
1.542 +
1.543 + i += 4;
1.544 +
1.545 + if (val != -123)
1.546 + die ("wrong file magic in .da file\n");
1.547 +
1.548 + if (!string_get_int (contents, i, &val))
1.549 + die ("no function count in .da file\n");
1.550 + i += 4;
1.551 + claimed_n_functions = val;
1.552 +
1.553 + printf ("%d functions expected in section %d of .da file\n",
1.554 + claimed_n_functions, n_sections);
1.555 +
1.556 + if (!string_get_int (contents, i, &val))
1.557 + die ("no extra data length in .da file\n");
1.558 +
1.559 + i += 4;
1.560 +
1.561 + i += val;
1.562 +
1.563 + total_arcs = 0;
1.564 + n_functions = 0;
1.565 + while (n_functions < claimed_n_functions)
1.566 + {
1.567 + DBusString funcname;
1.568 + int checksum;
1.569 + int claimed_n_arcs;
1.570 + int n_arcs;
1.571 +
1.572 + if (!_dbus_string_init (&funcname))
1.573 + die ("no memory\n");
1.574 +
1.575 + if (!string_get_function (contents, i,
1.576 + &funcname, &checksum, &i))
1.577 + die ("could not read function name\n");
1.578 +
1.579 + if (!string_get_int (contents, i, &val))
1.580 + die ("no arc count for function\n");
1.581 +
1.582 + i += 4;
1.583 + claimed_n_arcs = val;
1.584 +
1.585 + printf (" %d arcs in function %d %s checksum %d\n",
1.586 + claimed_n_arcs, n_functions,
1.587 + _dbus_string_get_const_data (&funcname),
1.588 + checksum);
1.589 +
1.590 + n_arcs = 0;
1.591 + while (n_arcs < claimed_n_arcs)
1.592 + {
1.593 + if (!string_get_int64 (contents, i, &v64))
1.594 + die ("did not get execution count for arc\n");
1.595 +
1.596 + i += 8;
1.597 +
1.598 + printf (" %ld executions of arc %d (total arcs %d)\n",
1.599 + (long) v64, n_arcs, total_arcs + n_arcs);
1.600 +
1.601 + ++n_arcs;
1.602 + }
1.603 +
1.604 + _dbus_string_free (&funcname);
1.605 +
1.606 + total_arcs += n_arcs;
1.607 + ++n_functions;
1.608 + }
1.609 +
1.610 + printf ("total of %d functions and %d arcs in section %d\n",
1.611 + n_functions, total_arcs, n_sections);
1.612 +
1.613 + total_functions += n_functions;
1.614 + ++n_sections;
1.615 + }
1.616 +
1.617 + printf ("%d total function sections in %d total .da file sections\n",
1.618 + total_functions, n_sections);
1.619 +}
1.620 +
1.621 +#endif /* DBUS_HAVE_GCC33_GCOV */
1.622 +
1.623 +typedef struct Arc Arc;
1.624 +typedef struct Block Block;
1.625 +typedef struct Function Function;
1.626 +typedef struct File File;
1.627 +typedef struct Line Line;
1.628 +
1.629 +struct Arc
1.630 +{
1.631 + int source;
1.632 + int target;
1.633 + dbus_int64_t arc_count;
1.634 + unsigned int count_valid : 1;
1.635 + unsigned int on_tree : 1;
1.636 + unsigned int fake : 1;
1.637 + unsigned int fall_through : 1;
1.638 + Arc *pred_next;
1.639 + Arc *succ_next;
1.640 +};
1.641 +
1.642 +struct Block
1.643 +{
1.644 + Arc *succ;
1.645 + Arc *pred;
1.646 + dbus_int64_t succ_count;
1.647 + dbus_int64_t pred_count;
1.648 + dbus_int64_t exec_count;
1.649 + DBusList *lines;
1.650 + unsigned int count_valid : 1;
1.651 + unsigned int on_tree : 1;
1.652 + unsigned int inside_dbus_build_tests : 1;
1.653 +};
1.654 +
1.655 +struct Function
1.656 +{
1.657 + char *name;
1.658 + int checksum;
1.659 + Block *block_graph;
1.660 + int n_blocks;
1.661 + /* number of blocks in DBUS_BUILD_TESTS */
1.662 + int n_test_blocks;
1.663 + int n_test_blocks_executed;
1.664 + /* number of blocks outside DBUS_BUILD_TESTS */
1.665 + int n_nontest_blocks;
1.666 + int n_nontest_blocks_executed;
1.667 + /* Summary result flags */
1.668 + unsigned int unused : 1;
1.669 + unsigned int inside_dbus_build_tests : 1;
1.670 + unsigned int partial : 1; /* only some of the blocks were executed */
1.671 +};
1.672 +
1.673 +struct Line
1.674 +{
1.675 + int number;
1.676 + char *text;
1.677 + DBusList *blocks;
1.678 + unsigned int inside_dbus_build_tests : 1;
1.679 + unsigned int partial : 1; /* only some of the blocks were executed */
1.680 +};
1.681 +
1.682 +struct File
1.683 +{
1.684 + char *name;
1.685 + Line *lines;
1.686 + int n_lines;
1.687 + DBusList *functions;
1.688 +};
1.689 +
1.690 +static void
1.691 +function_add_arc (Function *function,
1.692 + long source,
1.693 + long target,
1.694 + long flags)
1.695 +{
1.696 + Arc *arc;
1.697 +
1.698 + arc = dbus_new0 (Arc, 1);
1.699 + if (arc == NULL)
1.700 + die ("no memory\n");
1.701 +
1.702 + arc->target = target;
1.703 + arc->source = source;
1.704 +
1.705 + arc->succ_next = function->block_graph[source].succ;
1.706 + function->block_graph[source].succ = arc;
1.707 + function->block_graph[source].succ_count += 1;
1.708 +
1.709 + arc->pred_next = function->block_graph[target].pred;
1.710 + function->block_graph[target].pred = arc;
1.711 + function->block_graph[target].pred_count += 1;
1.712 +
1.713 + if ((flags & FLAG_ON_TREE) != 0)
1.714 + arc->on_tree = TRUE;
1.715 +
1.716 + if ((flags & FLAG_FAKE) != 0)
1.717 + arc->fake = TRUE;
1.718 +
1.719 + if ((flags & FLAG_FALL_THROUGH) != 0)
1.720 + arc->fall_through = TRUE;
1.721 +}
1.722 +
1.723 +
1.724 +static Arc*
1.725 +reverse_arcs (Arc *arc)
1.726 +{
1.727 + struct Arc *prev = 0;
1.728 + struct Arc *next;
1.729 +
1.730 + for ( ; arc; arc = next)
1.731 + {
1.732 + next = arc->succ_next;
1.733 + arc->succ_next = prev;
1.734 + prev = arc;
1.735 + }
1.736 +
1.737 + return prev;
1.738 +}
1.739 +
1.740 +static void
1.741 +function_reverse_succ_arcs (Function *func)
1.742 +{
1.743 + /* Must reverse the order of all succ arcs, to ensure that they match
1.744 + * the order of the data in the .da file.
1.745 + */
1.746 + int i;
1.747 +
1.748 + for (i = 0; i < func->n_blocks; i++)
1.749 + if (func->block_graph[i].succ)
1.750 + func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
1.751 +}
1.752 +
1.753 +static void
1.754 +get_functions_from_bbg (const DBusString *contents,
1.755 + DBusList **functions)
1.756 +{
1.757 + int i;
1.758 + long val;
1.759 + int n_functions;
1.760 + int n_arcs;
1.761 + int n_blocks;
1.762 + int n_arcs_off_tree;
1.763 +
1.764 +#if 0
1.765 + printf ("Loading arcs and blocks from .bbg file\n");
1.766 +#endif
1.767 +
1.768 + n_arcs_off_tree = 0;
1.769 + n_blocks = 0;
1.770 + n_arcs = 0;
1.771 + n_functions = 0;
1.772 + i = 0;
1.773 + while (i < _dbus_string_get_length (contents))
1.774 + {
1.775 + Function *func;
1.776 + long n_blocks_in_func;
1.777 + long n_arcs_in_func;
1.778 + int j;
1.779 +
1.780 +#ifdef DBUS_HAVE_GCC33_GCOV
1.781 + DBusString funcname;
1.782 + int checksum;
1.783 +
1.784 + /* In gcc33 .bbg files, there's a function name of the form:
1.785 + * -1, length, name (padded to 4), -1, checksum
1.786 + * after that header on each function description, it's
1.787 + * the same as in gcc32
1.788 + */
1.789 + if (!_dbus_string_init (&funcname))
1.790 + die ("no memory\n");
1.791 +
1.792 + if (!string_get_function (contents, i,
1.793 + &funcname, &checksum, &i))
1.794 + die ("could not read function name\n");
1.795 +#endif /* DBUS_HAVE_GCC33_GCOV */
1.796 +
1.797 + if (!string_get_int (contents, i, &val))
1.798 + break;
1.799 +
1.800 + n_blocks_in_func = val;
1.801 +
1.802 + i += 4;
1.803 +
1.804 + if (!string_get_int (contents, i, &n_arcs_in_func))
1.805 + break;
1.806 +
1.807 + i += 4;
1.808 +
1.809 + n_functions += 1;
1.810 + n_blocks += n_blocks_in_func;
1.811 + n_arcs += n_arcs_in_func;
1.812 +
1.813 + func = dbus_new0 (Function, 1);
1.814 + if (func == NULL)
1.815 + die ("no memory\n");
1.816 +
1.817 +#ifdef DBUS_HAVE_GCC33_GCOV
1.818 + func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
1.819 + func->checksum = checksum;
1.820 + _dbus_string_free (&funcname);
1.821 +#endif
1.822 +
1.823 + func->block_graph = dbus_new0 (Block, n_blocks_in_func);
1.824 + func->n_blocks = n_blocks_in_func;
1.825 +
1.826 + j = 0;
1.827 + while (j < n_blocks_in_func)
1.828 + {
1.829 + long n_arcs_in_block;
1.830 + int k;
1.831 +
1.832 + if (!string_get_int (contents, i, &n_arcs_in_block))
1.833 + break;
1.834 +
1.835 + i += 4;
1.836 +
1.837 + k = 0;
1.838 + while (k < n_arcs_in_block)
1.839 + {
1.840 + long destination_block;
1.841 + long flags;
1.842 +
1.843 + if (!string_get_int (contents, i, &destination_block))
1.844 + break;
1.845 +
1.846 + i += 4;
1.847 +
1.848 + if (!string_get_int (contents, i, &flags))
1.849 + break;
1.850 +
1.851 + i += 4;
1.852 +
1.853 + if ((flags & FLAG_ON_TREE) == 0)
1.854 + n_arcs_off_tree += 1;
1.855 +
1.856 + function_add_arc (func, j, destination_block,
1.857 + flags);
1.858 +
1.859 + ++k;
1.860 + }
1.861 +
1.862 + if (k < n_arcs_in_block)
1.863 + break;
1.864 +
1.865 + ++j;
1.866 + }
1.867 +
1.868 + if (j < n_blocks_in_func)
1.869 + break;
1.870 +
1.871 + function_reverse_succ_arcs (func);
1.872 +
1.873 + if (!_dbus_list_append (functions, func))
1.874 + die ("no memory\n");
1.875 +
1.876 + if (!string_get_int (contents, i, &val))
1.877 + break;
1.878 +
1.879 + i += 4;
1.880 +
1.881 + if (val != -1)
1.882 + die ("-1 separator not found in .bbg file\n");
1.883 + }
1.884 +
1.885 +#if 0
1.886 + printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
1.887 + n_functions, n_blocks, n_arcs, n_arcs_off_tree);
1.888 +#endif
1.889 +
1.890 + _dbus_assert (n_functions == _dbus_list_get_length (functions));
1.891 +}
1.892 +
1.893 +#ifdef DBUS_HAVE_GCC33_GCOV
1.894 +static void
1.895 +add_counts_from_da (const DBusString *contents,
1.896 + DBusList **functions)
1.897 +{
1.898 + int i;
1.899 + dbus_int64_t v64;
1.900 + long val;
1.901 + int n_sections;
1.902 + DBusList *link;
1.903 + Function *current_func;
1.904 + int current_block;
1.905 + Arc *current_arc;
1.906 +
1.907 + n_sections = 0;
1.908 +
1.909 + i = 0;
1.910 + while (i < _dbus_string_get_length (contents))
1.911 + {
1.912 + int claimed_n_functions;
1.913 + int n_functions;
1.914 +
1.915 + if (!string_get_int (contents, i, &val))
1.916 + die ("no magic found in .da file\n");
1.917 +
1.918 + i += 4;
1.919 +
1.920 + if (val != -123)
1.921 + die ("wrong file magic in .da file\n");
1.922 +
1.923 + if (!string_get_int (contents, i, &val))
1.924 + die ("no function count in .da file\n");
1.925 + i += 4;
1.926 + claimed_n_functions = val;
1.927 +
1.928 + if (!string_get_int (contents, i, &val))
1.929 + die ("no extra data length in .da file\n");
1.930 +
1.931 + i += 4;
1.932 +
1.933 + i += val;
1.934 +
1.935 + link = _dbus_list_get_first_link (functions);
1.936 + if (link == NULL)
1.937 + goto no_more_functions;
1.938 +
1.939 + n_functions = 0;
1.940 + while (n_functions < claimed_n_functions && link != NULL)
1.941 + {
1.942 + DBusString funcname;
1.943 + int checksum;
1.944 + int claimed_n_arcs;
1.945 + int n_arcs;
1.946 +
1.947 + current_func = link->data;
1.948 + current_block = 0;
1.949 + current_arc = current_func->block_graph[current_block].succ;
1.950 +
1.951 + if (!_dbus_string_init (&funcname))
1.952 + die ("no memory\n");
1.953 +
1.954 + if (!string_get_function (contents, i,
1.955 + &funcname, &checksum, &i))
1.956 + die ("could not read function name\n");
1.957 +
1.958 + if (!_dbus_string_equal_c_str (&funcname, current_func->name))
1.959 + {
1.960 + fprintf (stderr, "Expecting .da info for %s but got %s\n",
1.961 + current_func->name,
1.962 + _dbus_string_get_const_data (&funcname));
1.963 + exit (1);
1.964 + }
1.965 +
1.966 + if (checksum != current_func->checksum)
1.967 + die (".da file checksum doesn't match checksum from .bbg file\n");
1.968 +
1.969 + if (!string_get_int (contents, i, &val))
1.970 + die ("no arc count for function\n");
1.971 +
1.972 + i += 4;
1.973 + claimed_n_arcs = val;
1.974 +
1.975 + /* For each arc in the profile, find the corresponding
1.976 + * arc in the function and increment its count
1.977 + */
1.978 + n_arcs = 0;
1.979 + while (n_arcs < claimed_n_arcs)
1.980 + {
1.981 + if (!string_get_int64 (contents, i, &v64))
1.982 + die ("did not get execution count for arc\n");
1.983 +
1.984 + i += 8;
1.985 +
1.986 + /* Find the next arc in the function that isn't on tree */
1.987 + while (current_arc == NULL ||
1.988 + current_arc->on_tree)
1.989 + {
1.990 + if (current_arc == NULL)
1.991 + {
1.992 + ++current_block;
1.993 +
1.994 + if (current_block >= current_func->n_blocks)
1.995 + die ("too many blocks in function\n");
1.996 +
1.997 + current_arc = current_func->block_graph[current_block].succ;
1.998 + }
1.999 + else
1.1000 + {
1.1001 + current_arc = current_arc->succ_next;
1.1002 + }
1.1003 + }
1.1004 +
1.1005 + _dbus_assert (current_arc != NULL);
1.1006 + _dbus_assert (!current_arc->on_tree);
1.1007 +
1.1008 + current_arc->arc_count = v64;
1.1009 + current_arc->count_valid = TRUE;
1.1010 + current_func->block_graph[current_block].succ_count -= 1;
1.1011 + current_func->block_graph[current_arc->target].pred_count -= 1;
1.1012 +
1.1013 + ++n_arcs;
1.1014 +
1.1015 + current_arc = current_arc->succ_next;
1.1016 + }
1.1017 +
1.1018 + _dbus_string_free (&funcname);
1.1019 +
1.1020 + link = _dbus_list_get_next_link (functions, link);
1.1021 + ++n_functions;
1.1022 +
1.1023 + if (link == NULL && n_functions < claimed_n_functions)
1.1024 + {
1.1025 + fprintf (stderr, "Ran out of functions loading .da file\n");
1.1026 + goto no_more_functions;
1.1027 + }
1.1028 + }
1.1029 +
1.1030 + no_more_functions:
1.1031 +
1.1032 + ++n_sections;
1.1033 + }
1.1034 +}
1.1035 +#else /* DBUS_HAVE_GCC33_GCOV */
1.1036 +static void
1.1037 +add_counts_from_da (const DBusString *contents,
1.1038 + DBusList **functions)
1.1039 +{
1.1040 + int i;
1.1041 + dbus_int64_t val;
1.1042 + int n_arcs;
1.1043 + int claimed_n_arcs;
1.1044 + DBusList *link;
1.1045 + Function *current_func;
1.1046 + int current_block;
1.1047 + Arc *current_arc;
1.1048 +
1.1049 +#if 0
1.1050 + printf ("Loading execution count for each arc from .da file\n");
1.1051 +#endif
1.1052 +
1.1053 + i = 0;
1.1054 + if (!string_get_int64 (contents, i, &val))
1.1055 + return;
1.1056 +
1.1057 + i += 8;
1.1058 +
1.1059 + claimed_n_arcs = val;
1.1060 +
1.1061 + link = _dbus_list_get_first_link (functions);
1.1062 + if (link == NULL)
1.1063 + goto done;
1.1064 +
1.1065 + current_func = link->data;
1.1066 + current_block = 0;
1.1067 + current_arc = current_func->block_graph[current_block].succ;
1.1068 +
1.1069 + n_arcs = 0;
1.1070 + while (string_get_int64 (contents, i, &val))
1.1071 + {
1.1072 + i += 8;
1.1073 +
1.1074 + while (current_arc == NULL ||
1.1075 + current_arc->on_tree)
1.1076 + {
1.1077 + if (current_arc == NULL)
1.1078 + {
1.1079 + ++current_block;
1.1080 +
1.1081 + if (current_block == current_func->n_blocks)
1.1082 + {
1.1083 + link = _dbus_list_get_next_link (functions, link);
1.1084 + if (link == NULL)
1.1085 + {
1.1086 + fprintf (stderr, "Ran out of functions loading .da file\n");
1.1087 + goto done;
1.1088 + }
1.1089 + current_func = link->data;
1.1090 + current_block = 0;
1.1091 + }
1.1092 +
1.1093 + current_arc = current_func->block_graph[current_block].succ;
1.1094 + }
1.1095 + else
1.1096 + {
1.1097 + current_arc = current_arc->succ_next;
1.1098 + }
1.1099 + }
1.1100 +
1.1101 + _dbus_assert (current_arc != NULL);
1.1102 + _dbus_assert (!current_arc->on_tree);
1.1103 +
1.1104 + current_arc->arc_count = val;
1.1105 + current_arc->count_valid = TRUE;
1.1106 + current_func->block_graph[current_block].succ_count -= 1;
1.1107 + current_func->block_graph[current_arc->target].pred_count -= 1;
1.1108 +
1.1109 + ++n_arcs;
1.1110 +
1.1111 + current_arc = current_arc->succ_next;
1.1112 + }
1.1113 +
1.1114 + done:
1.1115 +
1.1116 + if (n_arcs != claimed_n_arcs)
1.1117 + {
1.1118 + fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
1.1119 + claimed_n_arcs, n_arcs);
1.1120 + exit (1);
1.1121 + }
1.1122 +
1.1123 +#if 0
1.1124 + printf ("%d arcs in file\n", n_arcs);
1.1125 +#endif
1.1126 +}
1.1127 +#endif
1.1128 +
1.1129 +static void
1.1130 +function_solve_graph (Function *func)
1.1131 +{
1.1132 + int passes, changes;
1.1133 + dbus_int64_t total;
1.1134 + int i;
1.1135 + Arc *arc;
1.1136 + Block *block_graph;
1.1137 + int n_blocks;
1.1138 +
1.1139 +#if 0
1.1140 + printf ("Solving function graph\n");
1.1141 +#endif
1.1142 +
1.1143 + n_blocks = func->n_blocks;
1.1144 + block_graph = func->block_graph;
1.1145 +
1.1146 + /* For every block in the file,
1.1147 + - if every exit/entrance arc has a known count, then set the block count
1.1148 + - if the block count is known, and every exit/entrance arc but one has
1.1149 + a known execution count, then set the count of the remaining arc
1.1150 +
1.1151 + As arc counts are set, decrement the succ/pred count, but don't delete
1.1152 + the arc, that way we can easily tell when all arcs are known, or only
1.1153 + one arc is unknown. */
1.1154 +
1.1155 + /* The order that the basic blocks are iterated through is important.
1.1156 + Since the code that finds spanning trees starts with block 0, low numbered
1.1157 + arcs are put on the spanning tree in preference to high numbered arcs.
1.1158 + Hence, most instrumented arcs are at the end. Graph solving works much
1.1159 + faster if we propagate numbers from the end to the start.
1.1160 +
1.1161 + This takes an average of slightly more than 3 passes. */
1.1162 +
1.1163 + changes = 1;
1.1164 + passes = 0;
1.1165 + while (changes)
1.1166 + {
1.1167 + passes++;
1.1168 + changes = 0;
1.1169 +
1.1170 + for (i = n_blocks - 1; i >= 0; i--)
1.1171 + {
1.1172 + if (! block_graph[i].count_valid)
1.1173 + {
1.1174 + if (block_graph[i].succ_count == 0)
1.1175 + {
1.1176 + total = 0;
1.1177 + for (arc = block_graph[i].succ; arc;
1.1178 + arc = arc->succ_next)
1.1179 + total += arc->arc_count;
1.1180 + block_graph[i].exec_count = total;
1.1181 + block_graph[i].count_valid = 1;
1.1182 + changes = 1;
1.1183 + }
1.1184 + else if (block_graph[i].pred_count == 0)
1.1185 + {
1.1186 + total = 0;
1.1187 + for (arc = block_graph[i].pred; arc;
1.1188 + arc = arc->pred_next)
1.1189 + total += arc->arc_count;
1.1190 + block_graph[i].exec_count = total;
1.1191 + block_graph[i].count_valid = 1;
1.1192 + changes = 1;
1.1193 + }
1.1194 + }
1.1195 + if (block_graph[i].count_valid)
1.1196 + {
1.1197 + if (block_graph[i].succ_count == 1)
1.1198 + {
1.1199 + total = 0;
1.1200 + /* One of the counts will be invalid, but it is zero,
1.1201 + so adding it in also doesn't hurt. */
1.1202 + for (arc = block_graph[i].succ; arc;
1.1203 + arc = arc->succ_next)
1.1204 + total += arc->arc_count;
1.1205 + /* Calculate count for remaining arc by conservation. */
1.1206 + total = block_graph[i].exec_count - total;
1.1207 + /* Search for the invalid arc, and set its count. */
1.1208 + for (arc = block_graph[i].succ; arc;
1.1209 + arc = arc->succ_next)
1.1210 + if (! arc->count_valid)
1.1211 + break;
1.1212 + if (! arc)
1.1213 + die ("arc == NULL\n");
1.1214 + arc->count_valid = 1;
1.1215 + arc->arc_count = total;
1.1216 + block_graph[i].succ_count -= 1;
1.1217 +
1.1218 + block_graph[arc->target].pred_count -= 1;
1.1219 + changes = 1;
1.1220 + }
1.1221 + if (block_graph[i].pred_count == 1)
1.1222 + {
1.1223 + total = 0;
1.1224 + /* One of the counts will be invalid, but it is zero,
1.1225 + so adding it in also doesn't hurt. */
1.1226 + for (arc = block_graph[i].pred; arc;
1.1227 + arc = arc->pred_next)
1.1228 + total += arc->arc_count;
1.1229 + /* Calculate count for remaining arc by conservation. */
1.1230 + total = block_graph[i].exec_count - total;
1.1231 + /* Search for the invalid arc, and set its count. */
1.1232 + for (arc = block_graph[i].pred; arc;
1.1233 + arc = arc->pred_next)
1.1234 + if (! arc->count_valid)
1.1235 + break;
1.1236 + if (! arc)
1.1237 + die ("arc == NULL\n");
1.1238 + arc->count_valid = 1;
1.1239 + arc->arc_count = total;
1.1240 + block_graph[i].pred_count -= 1;
1.1241 +
1.1242 + block_graph[arc->source].succ_count -= 1;
1.1243 + changes = 1;
1.1244 + }
1.1245 + }
1.1246 + }
1.1247 + }
1.1248 +
1.1249 + /* If the graph has been correctly solved, every block will have a
1.1250 + * succ and pred count of zero.
1.1251 + */
1.1252 + {
1.1253 + dbus_bool_t header = FALSE;
1.1254 + for (i = 0; i < n_blocks; i++)
1.1255 + {
1.1256 + if (block_graph[i].succ_count || block_graph[i].pred_count)
1.1257 + {
1.1258 + if (!header)
1.1259 + {
1.1260 + fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
1.1261 + func->name);
1.1262 + fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
1.1263 + header = TRUE;
1.1264 + }
1.1265 + fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
1.1266 + i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
1.1267 + }
1.1268 + }
1.1269 + }
1.1270 +}
1.1271 +
1.1272 +static void
1.1273 +solve_graphs (DBusList **functions)
1.1274 +{
1.1275 + DBusList *link;
1.1276 +
1.1277 + link = _dbus_list_get_first_link (functions);
1.1278 + while (link != NULL)
1.1279 + {
1.1280 + Function *func = link->data;
1.1281 +
1.1282 + function_solve_graph (func);
1.1283 +
1.1284 + link = _dbus_list_get_next_link (functions, link);
1.1285 + }
1.1286 +}
1.1287 +
1.1288 +static void
1.1289 +load_functions_for_c_file (const DBusString *filename,
1.1290 + DBusList **functions)
1.1291 +{
1.1292 + DBusString bbg_filename;
1.1293 + DBusString da_filename;
1.1294 + DBusString gcno_filename;
1.1295 + DBusString gcda_filename;
1.1296 + DBusString contents;
1.1297 + DBusString *name;
1.1298 + DBusError error;
1.1299 +
1.1300 + /* With latest gcc it's .gcno instead of .bbg and
1.1301 + * gcda instead of .da
1.1302 + */
1.1303 +
1.1304 + dbus_error_init (&error);
1.1305 +
1.1306 + if (!_dbus_string_init (&bbg_filename) ||
1.1307 + !_dbus_string_init (&da_filename) ||
1.1308 + !_dbus_string_init (&gcno_filename) ||
1.1309 + !_dbus_string_init (&gcda_filename) ||
1.1310 + !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
1.1311 + !_dbus_string_copy (filename, 0, &da_filename, 0) ||
1.1312 + !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
1.1313 + !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
1.1314 + !_dbus_string_init (&contents))
1.1315 + die ("no memory\n");
1.1316 +
1.1317 + _dbus_string_shorten (&bbg_filename, 2);
1.1318 + _dbus_string_shorten (&da_filename, 2);
1.1319 +
1.1320 + if (!_dbus_string_append (&bbg_filename, ".bbg") ||
1.1321 + !_dbus_string_append (&da_filename, ".da") ||
1.1322 + !_dbus_string_append (&bbg_filename, ".gcno") ||
1.1323 + !_dbus_string_append (&bbg_filename, ".gcda"))
1.1324 + die ("no memory\n");
1.1325 +
1.1326 + if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
1.1327 + name = &gcno_filename;
1.1328 + else
1.1329 + name = &bbg_filename;
1.1330 +
1.1331 + if (!_dbus_file_get_contents (&contents, name,
1.1332 + &error))
1.1333 + {
1.1334 + fprintf (stderr, "Could not open file: %s\n",
1.1335 + error.message);
1.1336 + exit (1);
1.1337 + }
1.1338 +
1.1339 + get_functions_from_bbg (&contents, functions);
1.1340 +
1.1341 + _dbus_string_set_length (&contents, 0);
1.1342 +
1.1343 + if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
1.1344 + name = &gcda_filename;
1.1345 + else
1.1346 + name = &da_filename;
1.1347 +
1.1348 + if (!_dbus_file_get_contents (&contents, name,
1.1349 + &error))
1.1350 + {
1.1351 + /* Try .libs/file.da */
1.1352 + int slash;
1.1353 +
1.1354 + if (_dbus_string_find_byte_backward (name,
1.1355 + _dbus_string_get_length (name),
1.1356 + '/',
1.1357 + &slash))
1.1358 + {
1.1359 + DBusString libs;
1.1360 + _dbus_string_init_const (&libs, "/.libs");
1.1361 +
1.1362 + if (!_dbus_string_copy (&libs, 0, name, slash))
1.1363 + die ("no memory");
1.1364 +
1.1365 + dbus_error_free (&error);
1.1366 + if (!_dbus_file_get_contents (&contents, name,
1.1367 + &error))
1.1368 + {
1.1369 + fprintf (stderr, "Could not open file: %s\n",
1.1370 + error.message);
1.1371 + exit (1);
1.1372 + }
1.1373 + }
1.1374 + else
1.1375 + {
1.1376 + fprintf (stderr, "Could not open file: %s\n",
1.1377 + error.message);
1.1378 + exit (1);
1.1379 + }
1.1380 + }
1.1381 +
1.1382 + add_counts_from_da (&contents, functions);
1.1383 +
1.1384 + solve_graphs (functions);
1.1385 +
1.1386 + _dbus_string_free (&contents);
1.1387 + _dbus_string_free (&da_filename);
1.1388 + _dbus_string_free (&bbg_filename);
1.1389 +}
1.1390 +
1.1391 +static void
1.1392 +get_lines_from_bb_file (const DBusString *contents,
1.1393 + File *fl)
1.1394 +{
1.1395 + int i;
1.1396 + long val;
1.1397 + int n_functions;
1.1398 + dbus_bool_t in_our_file;
1.1399 + DBusList *link;
1.1400 + Function *func;
1.1401 + int block;
1.1402 +
1.1403 +#if 0
1.1404 + printf ("Getting line numbers for blocks from .bb file\n");
1.1405 +#endif
1.1406 +
1.1407 + /* There's this "filename" field in the .bb file which
1.1408 + * mysteriously comes *after* the first function in the
1.1409 + * file in the .bb file; and every .bb file seems to
1.1410 + * have only one filename. I don't understand
1.1411 + * what's going on here, so just set in_our_file = TRUE
1.1412 + * at the start categorically.
1.1413 + */
1.1414 +
1.1415 + block = 0;
1.1416 + func = NULL;
1.1417 + in_our_file = TRUE;
1.1418 + link = _dbus_list_get_first_link (&fl->functions);
1.1419 + n_functions = 0;
1.1420 + i = 0;
1.1421 + while (string_get_int (contents, i, &val))
1.1422 + {
1.1423 + i += 4;
1.1424 +
1.1425 + switch (val)
1.1426 + {
1.1427 + case BB_FILENAME:
1.1428 + {
1.1429 + DBusString f;
1.1430 +
1.1431 + if (!_dbus_string_init (&f))
1.1432 + die ("no memory\n");
1.1433 +
1.1434 + if (string_get_string (contents, i,
1.1435 + BB_FILENAME,
1.1436 + &f, &i))
1.1437 + {
1.1438 + /* fl->name is a full path and the filename in .bb is
1.1439 + * not.
1.1440 + */
1.1441 + DBusString tmp_str;
1.1442 +
1.1443 + _dbus_string_init_const (&tmp_str, fl->name);
1.1444 +
1.1445 + if (_dbus_string_ends_with_c_str (&tmp_str,
1.1446 + _dbus_string_get_const_data (&f)))
1.1447 + in_our_file = TRUE;
1.1448 + else
1.1449 + in_our_file = FALSE;
1.1450 +
1.1451 +#if 0
1.1452 + fprintf (stderr,
1.1453 + "File %s in .bb, looking for %s, in_our_file = %d\n",
1.1454 + _dbus_string_get_const_data (&f),
1.1455 + fl->name,
1.1456 + in_our_file);
1.1457 +#endif
1.1458 + }
1.1459 + _dbus_string_free (&f);
1.1460 + }
1.1461 + break;
1.1462 + case BB_FUNCTION:
1.1463 + {
1.1464 + DBusString f;
1.1465 + if (!_dbus_string_init (&f))
1.1466 + die ("no memory\n");
1.1467 +
1.1468 + if (string_get_string (contents, i,
1.1469 + BB_FUNCTION,
1.1470 + &f, &i))
1.1471 + {
1.1472 +#if 0
1.1473 + fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
1.1474 +#endif
1.1475 +
1.1476 + block = 0;
1.1477 +
1.1478 + if (in_our_file)
1.1479 + {
1.1480 + if (link == NULL)
1.1481 + {
1.1482 + fprintf (stderr, "No function object for function %s\n",
1.1483 + _dbus_string_get_const_data (&f));
1.1484 + }
1.1485 + else
1.1486 + {
1.1487 + func = link->data;
1.1488 + link = _dbus_list_get_next_link (&fl->functions, link);
1.1489 +
1.1490 + if (func->name == NULL)
1.1491 + {
1.1492 + if (!_dbus_string_copy_data (&f, &func->name))
1.1493 + die ("no memory\n");
1.1494 + }
1.1495 + else
1.1496 + {
1.1497 + if (!_dbus_string_equal_c_str (&f, func->name))
1.1498 + {
1.1499 + fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
1.1500 + func->name, strlen (func->name),
1.1501 + _dbus_string_get_const_data (&f),
1.1502 + _dbus_string_get_length (&f));
1.1503 +
1.1504 + }
1.1505 + }
1.1506 + }
1.1507 + }
1.1508 + }
1.1509 + _dbus_string_free (&f);
1.1510 +
1.1511 + n_functions += 1;
1.1512 + }
1.1513 + break;
1.1514 + case BB_ENDOFLIST:
1.1515 + block += 1;
1.1516 + break;
1.1517 + default:
1.1518 +#if 0
1.1519 + fprintf (stderr, "Line %ld\n", val);
1.1520 +#endif
1.1521 +
1.1522 + if (val >= fl->n_lines)
1.1523 + {
1.1524 + fprintf (stderr, "Line %ld but file only has %d lines\n",
1.1525 + val, fl->n_lines);
1.1526 + }
1.1527 + else if (func != NULL)
1.1528 + {
1.1529 + val -= 1; /* To convert the 1-based line number to 0-based */
1.1530 + _dbus_assert (val >= 0);
1.1531 +
1.1532 + if (block < func->n_blocks)
1.1533 + {
1.1534 + if (!_dbus_list_append (&func->block_graph[block].lines,
1.1535 + &fl->lines[val]))
1.1536 + die ("no memory\n");
1.1537 +
1.1538 +
1.1539 + if (!_dbus_list_append (&fl->lines[val].blocks,
1.1540 + &func->block_graph[block]))
1.1541 + die ("no memory\n");
1.1542 + }
1.1543 + else
1.1544 + {
1.1545 + fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1.1546 + block, func->n_blocks);
1.1547 + }
1.1548 + }
1.1549 + else
1.1550 + {
1.1551 + fprintf (stderr, "Line %ld given outside of any function\n",
1.1552 + val);
1.1553 + }
1.1554 +
1.1555 + break;
1.1556 + }
1.1557 + }
1.1558 +
1.1559 +#if 0
1.1560 + printf ("%d functions in file\n", n_functions);
1.1561 +#endif
1.1562 +}
1.1563 +
1.1564 +
1.1565 +static void
1.1566 +load_block_line_associations (const DBusString *filename,
1.1567 + File *f)
1.1568 +{
1.1569 + DBusString bb_filename;
1.1570 + DBusString contents;
1.1571 + DBusError error;
1.1572 +
1.1573 + dbus_error_init (&error);
1.1574 +
1.1575 + if (!_dbus_string_init (&bb_filename) ||
1.1576 + !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1.1577 + !_dbus_string_init (&contents))
1.1578 + die ("no memory\n");
1.1579 +
1.1580 + _dbus_string_shorten (&bb_filename, 2);
1.1581 +
1.1582 + if (!_dbus_string_append (&bb_filename, ".bb"))
1.1583 + die ("no memory\n");
1.1584 +
1.1585 + if (!_dbus_file_get_contents (&contents, &bb_filename,
1.1586 + &error))
1.1587 + {
1.1588 + fprintf (stderr, "Could not open file: %s\n",
1.1589 + error.message);
1.1590 + exit (1);
1.1591 + }
1.1592 +
1.1593 + get_lines_from_bb_file (&contents, f);
1.1594 +
1.1595 + _dbus_string_free (&contents);
1.1596 + _dbus_string_free (&bb_filename);
1.1597 +}
1.1598 +
1.1599 +static int
1.1600 +count_lines_in_string (const DBusString *str)
1.1601 +{
1.1602 + int n_lines;
1.1603 + const char *p;
1.1604 + const char *prev;
1.1605 + const char *end;
1.1606 + const char *last_line_end;
1.1607 +
1.1608 +#if 0
1.1609 + printf ("Counting lines in source file\n");
1.1610 +#endif
1.1611 +
1.1612 + n_lines = 0;
1.1613 + prev = NULL;
1.1614 + p = _dbus_string_get_const_data (str);
1.1615 + end = p + _dbus_string_get_length (str);
1.1616 + last_line_end = p;
1.1617 + while (p != end)
1.1618 + {
1.1619 + /* too lazy to handle \r\n as one linebreak */
1.1620 + if (*p == '\n' || *p == '\r')
1.1621 + {
1.1622 + ++n_lines;
1.1623 + last_line_end = p + 1;
1.1624 + }
1.1625 +
1.1626 + prev = p;
1.1627 + ++p;
1.1628 + }
1.1629 +
1.1630 + if (last_line_end != p)
1.1631 + ++n_lines;
1.1632 +
1.1633 + return n_lines;
1.1634 +}
1.1635 +
1.1636 +static void
1.1637 +fill_line_content (const DBusString *str,
1.1638 + Line *lines)
1.1639 +{
1.1640 + int n_lines;
1.1641 + const char *p;
1.1642 + const char *prev;
1.1643 + const char *end;
1.1644 + const char *last_line_end;
1.1645 +
1.1646 +#if 0
1.1647 + printf ("Saving contents of each line in source file\n");
1.1648 +#endif
1.1649 +
1.1650 + n_lines = 0;
1.1651 + prev = NULL;
1.1652 + p = _dbus_string_get_const_data (str);
1.1653 + end = p + _dbus_string_get_length (str);
1.1654 + last_line_end = p;
1.1655 + while (p != end)
1.1656 + {
1.1657 + if (*p == '\n' || *p == '\r')
1.1658 + {
1.1659 + lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1.1660 + if (lines[n_lines].text == NULL)
1.1661 + die ("no memory\n");
1.1662 +
1.1663 + memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1.1664 + lines[n_lines].number = n_lines + 1;
1.1665 +
1.1666 + ++n_lines;
1.1667 +
1.1668 + last_line_end = p + 1;
1.1669 + }
1.1670 +
1.1671 + prev = p;
1.1672 + ++p;
1.1673 + }
1.1674 +
1.1675 + if (p != last_line_end)
1.1676 + {
1.1677 + memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1.1678 + ++n_lines;
1.1679 + }
1.1680 +}
1.1681 +
1.1682 +static void
1.1683 +mark_inside_dbus_build_tests (File *f)
1.1684 +{
1.1685 + int i;
1.1686 + DBusList *link;
1.1687 + int inside_depth;
1.1688 +
1.1689 + inside_depth = 0;
1.1690 + i = 0;
1.1691 + while (i < f->n_lines)
1.1692 + {
1.1693 + Line *l = &f->lines[i];
1.1694 + dbus_bool_t is_verbose;
1.1695 +
1.1696 + is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
1.1697 +
1.1698 + if (inside_depth == 0)
1.1699 + {
1.1700 + const char *a, *b;
1.1701 +
1.1702 + a = strstr (l->text, "#if");
1.1703 + b = strstr (l->text, "DBUS_BUILD_TESTS");
1.1704 + if (a && b && (a < b))
1.1705 + inside_depth += 1;
1.1706 + }
1.1707 + else
1.1708 + {
1.1709 + if (strstr (l->text, "#if") != NULL)
1.1710 + inside_depth += 1;
1.1711 + else if (strstr (l->text, "#endif") != NULL)
1.1712 + inside_depth -= 1;
1.1713 + }
1.1714 +
1.1715 + if (inside_depth > 0 || is_verbose)
1.1716 + {
1.1717 + /* Mark the line and its blocks */
1.1718 + DBusList *blink;
1.1719 +
1.1720 + l->inside_dbus_build_tests = TRUE;
1.1721 +
1.1722 + blink = _dbus_list_get_first_link (&l->blocks);
1.1723 + while (blink != NULL)
1.1724 + {
1.1725 + Block *b = blink->data;
1.1726 +
1.1727 + b->inside_dbus_build_tests = TRUE;
1.1728 +
1.1729 + blink = _dbus_list_get_next_link (&l->blocks, blink);
1.1730 + }
1.1731 + }
1.1732 +
1.1733 + ++i;
1.1734 + }
1.1735 +
1.1736 + /* Now mark functions where for all blocks that are associated
1.1737 + * with a source line, the block is inside_dbus_build_tests.
1.1738 + */
1.1739 + link = _dbus_list_get_first_link (&f->functions);
1.1740 + while (link != NULL)
1.1741 + {
1.1742 + Function *func = link->data;
1.1743 +
1.1744 + /* The issue is that some blocks aren't associated with a source line.
1.1745 + * Assume they are inside/outside tests according to the source
1.1746 + * line of the preceding block. For the first block, make it
1.1747 + * match the first following block with a line associated.
1.1748 + */
1.1749 + if (func->block_graph[0].lines == NULL)
1.1750 + {
1.1751 + /* find first following line */
1.1752 + i = 1;
1.1753 + while (i < func->n_blocks)
1.1754 + {
1.1755 + if (func->block_graph[i].lines != NULL)
1.1756 + {
1.1757 + func->block_graph[0].inside_dbus_build_tests =
1.1758 + func->block_graph[i].inside_dbus_build_tests;
1.1759 + break;
1.1760 + }
1.1761 +
1.1762 + ++i;
1.1763 + }
1.1764 + }
1.1765 +
1.1766 + /* Now mark all blocks but the first */
1.1767 + i = 1;
1.1768 + while (i < func->n_blocks)
1.1769 + {
1.1770 + if (func->block_graph[i].lines == NULL)
1.1771 + {
1.1772 + func->block_graph[i].inside_dbus_build_tests =
1.1773 + func->block_graph[i-1].inside_dbus_build_tests;
1.1774 + }
1.1775 +
1.1776 + ++i;
1.1777 + }
1.1778 +
1.1779 + i = 0;
1.1780 + while (i < func->n_blocks)
1.1781 + {
1.1782 + /* Break as soon as any block is not a test block */
1.1783 + if (func->block_graph[i].lines != NULL &&
1.1784 + !func->block_graph[i].inside_dbus_build_tests)
1.1785 + break;
1.1786 +
1.1787 + ++i;
1.1788 + }
1.1789 +
1.1790 + if (i == func->n_blocks)
1.1791 + func->inside_dbus_build_tests = TRUE;
1.1792 +
1.1793 + link = _dbus_list_get_next_link (&f->functions, link);
1.1794 + }
1.1795 +}
1.1796 +
1.1797 +static void
1.1798 +mark_coverage (File *f)
1.1799 +{
1.1800 + int i;
1.1801 + DBusList *link;
1.1802 +
1.1803 + i = 0;
1.1804 + while (i < f->n_lines)
1.1805 + {
1.1806 + Line *l = &f->lines[i];
1.1807 + DBusList *blink;
1.1808 + int n_blocks;
1.1809 + int n_blocks_executed;
1.1810 +
1.1811 + n_blocks = 0;
1.1812 + n_blocks_executed = 0;
1.1813 + blink = _dbus_list_get_first_link (&l->blocks);
1.1814 + while (blink != NULL)
1.1815 + {
1.1816 + Block *b = blink->data;
1.1817 +
1.1818 + if (b->exec_count > 0)
1.1819 + n_blocks_executed += 1;
1.1820 +
1.1821 + n_blocks += 1;
1.1822 +
1.1823 + blink = _dbus_list_get_next_link (&l->blocks, blink);
1.1824 + }
1.1825 +
1.1826 + if (n_blocks_executed > 0 &&
1.1827 + n_blocks_executed < n_blocks)
1.1828 + l->partial = TRUE;
1.1829 +
1.1830 + ++i;
1.1831 + }
1.1832 +
1.1833 + link = _dbus_list_get_first_link (&f->functions);
1.1834 + while (link != NULL)
1.1835 + {
1.1836 + Function *func = link->data;
1.1837 + int i;
1.1838 + int n_test_blocks;
1.1839 + int n_test_blocks_executed;
1.1840 + int n_nontest_blocks;
1.1841 + int n_nontest_blocks_executed;
1.1842 +
1.1843 + n_test_blocks = 0;
1.1844 + n_test_blocks_executed = 0;
1.1845 + n_nontest_blocks = 0;
1.1846 + n_nontest_blocks_executed = 0;
1.1847 +
1.1848 + i = 0;
1.1849 + while (i < func->n_blocks)
1.1850 + {
1.1851 + if (!func->block_graph[i].inside_dbus_build_tests)
1.1852 + {
1.1853 + n_nontest_blocks += 1;
1.1854 +
1.1855 + if (func->block_graph[i].exec_count > 0)
1.1856 + n_nontest_blocks_executed += 1;
1.1857 + }
1.1858 + else
1.1859 + {
1.1860 + n_test_blocks += 1;
1.1861 +
1.1862 + if (func->block_graph[i].exec_count > 0)
1.1863 + n_test_blocks_executed += 1;
1.1864 + }
1.1865 +
1.1866 + ++i;
1.1867 + }
1.1868 +
1.1869 + if (n_nontest_blocks_executed > 0 &&
1.1870 + n_nontest_blocks_executed < n_nontest_blocks)
1.1871 + func->partial = TRUE;
1.1872 +
1.1873 + if (n_nontest_blocks_executed == 0 &&
1.1874 + n_nontest_blocks > 0)
1.1875 + func->unused = TRUE;
1.1876 +
1.1877 + func->n_test_blocks = n_test_blocks;
1.1878 + func->n_test_blocks_executed = n_test_blocks_executed;
1.1879 + func->n_nontest_blocks = n_nontest_blocks;
1.1880 + func->n_nontest_blocks_executed = n_nontest_blocks_executed;
1.1881 +
1.1882 + link = _dbus_list_get_next_link (&f->functions, link);
1.1883 + }
1.1884 +}
1.1885 +
1.1886 +static File*
1.1887 +load_c_file (const DBusString *filename)
1.1888 +{
1.1889 + DBusString contents;
1.1890 + DBusError error;
1.1891 + File *f;
1.1892 +
1.1893 + f = dbus_new0 (File, 1);
1.1894 + if (f == NULL)
1.1895 + die ("no memory\n");
1.1896 +
1.1897 + if (!_dbus_string_copy_data (filename, &f->name))
1.1898 + die ("no memory\n");
1.1899 +
1.1900 + if (!_dbus_string_init (&contents))
1.1901 + die ("no memory\n");
1.1902 +
1.1903 + dbus_error_init (&error);
1.1904 +
1.1905 + if (!_dbus_file_get_contents (&contents, filename,
1.1906 + &error))
1.1907 + {
1.1908 + fprintf (stderr, "Could not open file: %s\n",
1.1909 + error.message);
1.1910 + dbus_error_free (&error);
1.1911 + exit (1);
1.1912 + }
1.1913 +
1.1914 + load_functions_for_c_file (filename, &f->functions);
1.1915 +
1.1916 + f->n_lines = count_lines_in_string (&contents);
1.1917 + f->lines = dbus_new0 (Line, f->n_lines);
1.1918 + if (f->lines == NULL)
1.1919 + die ("no memory\n");
1.1920 +
1.1921 + fill_line_content (&contents, f->lines);
1.1922 +
1.1923 + _dbus_string_free (&contents);
1.1924 +
1.1925 + load_block_line_associations (filename, f);
1.1926 +
1.1927 + mark_inside_dbus_build_tests (f);
1.1928 + mark_coverage (f);
1.1929 +
1.1930 + return f;
1.1931 +}
1.1932 +
1.1933 +typedef struct Stats Stats;
1.1934 +
1.1935 +struct Stats
1.1936 +{
1.1937 + int n_blocks;
1.1938 + int n_blocks_executed;
1.1939 + int n_blocks_inside_dbus_build_tests;
1.1940 +
1.1941 + int n_lines; /* lines that have blocks on them */
1.1942 + int n_lines_executed;
1.1943 + int n_lines_partial;
1.1944 + int n_lines_inside_dbus_build_tests;
1.1945 +
1.1946 + int n_functions;
1.1947 + int n_functions_executed;
1.1948 + int n_functions_partial;
1.1949 + int n_functions_inside_dbus_build_tests;
1.1950 +};
1.1951 +
1.1952 +static dbus_bool_t
1.1953 +line_was_executed (Line *l)
1.1954 +{
1.1955 + DBusList *link;
1.1956 +
1.1957 + link = _dbus_list_get_first_link (&l->blocks);
1.1958 + while (link != NULL)
1.1959 + {
1.1960 + Block *b = link->data;
1.1961 +
1.1962 + if (b->exec_count > 0)
1.1963 + return TRUE;
1.1964 +
1.1965 + link = _dbus_list_get_next_link (&l->blocks, link);
1.1966 + }
1.1967 +
1.1968 + return FALSE;
1.1969 +}
1.1970 +
1.1971 +
1.1972 +static int
1.1973 +line_exec_count (Line *l)
1.1974 +{
1.1975 + DBusList *link;
1.1976 + dbus_int64_t total;
1.1977 +
1.1978 + total = 0;
1.1979 + link = _dbus_list_get_first_link (&l->blocks);
1.1980 + while (link != NULL)
1.1981 + {
1.1982 + Block *b = link->data;
1.1983 +
1.1984 + total += b->exec_count;
1.1985 +
1.1986 + link = _dbus_list_get_next_link (&l->blocks, link);
1.1987 + }
1.1988 +
1.1989 + return total;
1.1990 +}
1.1991 +
1.1992 +static void
1.1993 +merge_stats_for_file (Stats *stats,
1.1994 + File *f)
1.1995 +{
1.1996 + int i;
1.1997 + DBusList *link;
1.1998 +
1.1999 + for (i = 0; i < f->n_lines; ++i)
1.2000 + {
1.2001 + Line *l = &f->lines[i];
1.2002 +
1.2003 + if (l->inside_dbus_build_tests)
1.2004 + {
1.2005 + stats->n_lines_inside_dbus_build_tests += 1;
1.2006 + continue;
1.2007 + }
1.2008 +
1.2009 + if (line_was_executed (l))
1.2010 + stats->n_lines_executed += 1;
1.2011 +
1.2012 + if (l->blocks != NULL)
1.2013 + stats->n_lines += 1;
1.2014 +
1.2015 + if (l->partial)
1.2016 + stats->n_lines_partial += 1;
1.2017 + }
1.2018 +
1.2019 + link = _dbus_list_get_first_link (&f->functions);
1.2020 + while (link != NULL)
1.2021 + {
1.2022 + Function *func = link->data;
1.2023 +
1.2024 + if (func->inside_dbus_build_tests)
1.2025 + stats->n_functions_inside_dbus_build_tests += 1;
1.2026 + else
1.2027 + {
1.2028 + stats->n_functions += 1;
1.2029 +
1.2030 + if (!func->unused)
1.2031 + stats->n_functions_executed += 1;
1.2032 +
1.2033 + if (func->partial)
1.2034 + stats->n_functions_partial += 1;
1.2035 + }
1.2036 +
1.2037 + stats->n_blocks_inside_dbus_build_tests +=
1.2038 + func->n_test_blocks;
1.2039 +
1.2040 + stats->n_blocks_executed +=
1.2041 + func->n_nontest_blocks_executed;
1.2042 +
1.2043 + stats->n_blocks +=
1.2044 + func->n_nontest_blocks;
1.2045 +
1.2046 + link = _dbus_list_get_next_link (&f->functions, link);
1.2047 + }
1.2048 +}
1.2049 +
1.2050 +/* The output of this matches gcov exactly ("diff" shows no difference) */
1.2051 +static void
1.2052 +print_annotated_source_gcov_format (File *f)
1.2053 +{
1.2054 + int i;
1.2055 +
1.2056 + i = 0;
1.2057 + while (i < f->n_lines)
1.2058 + {
1.2059 + Line *l = &f->lines[i];
1.2060 +
1.2061 + if (l->blocks != NULL)
1.2062 + {
1.2063 + int exec_count;
1.2064 +
1.2065 + exec_count = line_exec_count (l);
1.2066 +
1.2067 + if (exec_count > 0)
1.2068 + printf ("%12d %s\n",
1.2069 + exec_count, l->text);
1.2070 + else
1.2071 + printf (" ###### %s\n", l->text);
1.2072 + }
1.2073 + else
1.2074 + {
1.2075 + printf ("\t\t%s\n", l->text);
1.2076 + }
1.2077 +
1.2078 + ++i;
1.2079 + }
1.2080 +}
1.2081 +
1.2082 +static void
1.2083 +print_annotated_source (File *f)
1.2084 +{
1.2085 + int i;
1.2086 +
1.2087 + i = 0;
1.2088 + while (i < f->n_lines)
1.2089 + {
1.2090 + Line *l = &f->lines[i];
1.2091 +
1.2092 + if (l->inside_dbus_build_tests)
1.2093 + printf ("*");
1.2094 + else
1.2095 + printf (" ");
1.2096 +
1.2097 + if (l->blocks != NULL)
1.2098 + {
1.2099 + int exec_count;
1.2100 +
1.2101 + exec_count = line_exec_count (l);
1.2102 +
1.2103 + if (exec_count > 0)
1.2104 + printf ("%12d %s\n",
1.2105 + exec_count, l->text);
1.2106 + else
1.2107 + printf (" ###### %s\n", l->text);
1.2108 + }
1.2109 + else
1.2110 + {
1.2111 + printf ("\t\t%s\n", l->text);
1.2112 + }
1.2113 +
1.2114 + ++i;
1.2115 + }
1.2116 +}
1.2117 +
1.2118 +static void
1.2119 +print_block_superdetails (File *f)
1.2120 +{
1.2121 + DBusList *link;
1.2122 + int i;
1.2123 +
1.2124 + link = _dbus_list_get_first_link (&f->functions);
1.2125 + while (link != NULL)
1.2126 + {
1.2127 + Function *func = link->data;
1.2128 +
1.2129 + printf ("=== %s():\n", func->name);
1.2130 +
1.2131 + i = 0;
1.2132 + while (i < func->n_blocks)
1.2133 + {
1.2134 + Block *b = &func->block_graph[i];
1.2135 + DBusList *l;
1.2136 +
1.2137 + printf (" %5d executed %d times%s\n", i,
1.2138 + (int) b->exec_count,
1.2139 + b->inside_dbus_build_tests ?
1.2140 + " [inside DBUS_BUILD_TESTS]" : "");
1.2141 +
1.2142 + l = _dbus_list_get_first_link (&b->lines);
1.2143 + while (l != NULL)
1.2144 + {
1.2145 + Line *line = l->data;
1.2146 +
1.2147 + printf ("4%d\t%s\n", line->number, line->text);
1.2148 +
1.2149 + l = _dbus_list_get_next_link (&b->lines, l);
1.2150 + }
1.2151 +
1.2152 + ++i;
1.2153 + }
1.2154 +
1.2155 + link = _dbus_list_get_next_link (&f->functions, link);
1.2156 + }
1.2157 +}
1.2158 +
1.2159 +static void
1.2160 +print_one_file (const DBusString *filename)
1.2161 +{
1.2162 + if (_dbus_string_ends_with_c_str (filename, ".bb"))
1.2163 + {
1.2164 + DBusString contents;
1.2165 + DBusError error;
1.2166 +
1.2167 + if (!_dbus_string_init (&contents))
1.2168 + die ("no memory\n");
1.2169 +
1.2170 + dbus_error_init (&error);
1.2171 +
1.2172 + if (!_dbus_file_get_contents (&contents, filename,
1.2173 + &error))
1.2174 + {
1.2175 + fprintf (stderr, "Could not open file: %s\n",
1.2176 + error.message);
1.2177 + dbus_error_free (&error);
1.2178 + exit (1);
1.2179 + }
1.2180 +
1.2181 + dump_bb_file (&contents);
1.2182 +
1.2183 + _dbus_string_free (&contents);
1.2184 + }
1.2185 + else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
1.2186 + {
1.2187 + DBusString contents;
1.2188 + DBusError error;
1.2189 +
1.2190 + if (!_dbus_string_init (&contents))
1.2191 + die ("no memory\n");
1.2192 +
1.2193 + dbus_error_init (&error);
1.2194 +
1.2195 + if (!_dbus_file_get_contents (&contents, filename,
1.2196 + &error))
1.2197 + {
1.2198 + fprintf (stderr, "Could not open file: %s\n",
1.2199 + error.message);
1.2200 + dbus_error_free (&error);
1.2201 + exit (1);
1.2202 + }
1.2203 +
1.2204 + dump_bbg_file (&contents);
1.2205 +
1.2206 + _dbus_string_free (&contents);
1.2207 + }
1.2208 + else if (_dbus_string_ends_with_c_str (filename, ".da"))
1.2209 + {
1.2210 + DBusString contents;
1.2211 + DBusError error;
1.2212 +
1.2213 + if (!_dbus_string_init (&contents))
1.2214 + die ("no memory\n");
1.2215 +
1.2216 + dbus_error_init (&error);
1.2217 +
1.2218 + if (!_dbus_file_get_contents (&contents, filename,
1.2219 + &error))
1.2220 + {
1.2221 + fprintf (stderr, "Could not open file: %s\n",
1.2222 + error.message);
1.2223 + dbus_error_free (&error);
1.2224 + exit (1);
1.2225 + }
1.2226 +
1.2227 + dump_da_file (&contents);
1.2228 +
1.2229 + _dbus_string_free (&contents);
1.2230 + }
1.2231 + else if (_dbus_string_ends_with_c_str (filename, ".c"))
1.2232 + {
1.2233 + File *f;
1.2234 +
1.2235 + f = load_c_file (filename);
1.2236 +
1.2237 + print_annotated_source (f);
1.2238 + }
1.2239 + else
1.2240 + {
1.2241 + fprintf (stderr, "Unknown file type %s\n",
1.2242 + _dbus_string_get_const_data (filename));
1.2243 + exit (1);
1.2244 + }
1.2245 +}
1.2246 +
1.2247 +static void
1.2248 +print_untested_functions (File *f)
1.2249 +{
1.2250 + DBusList *link;
1.2251 + dbus_bool_t found;
1.2252 +
1.2253 + found = FALSE;
1.2254 + link = _dbus_list_get_first_link (&f->functions);
1.2255 + while (link != NULL)
1.2256 + {
1.2257 + Function *func = link->data;
1.2258 +
1.2259 + if (func->unused &&
1.2260 + !func->inside_dbus_build_tests)
1.2261 + found = TRUE;
1.2262 +
1.2263 + link = _dbus_list_get_next_link (&f->functions, link);
1.2264 + }
1.2265 +
1.2266 + if (!found)
1.2267 + return;
1.2268 +
1.2269 + printf ("Untested functions in %s\n", f->name);
1.2270 + printf ("=======\n");
1.2271 +
1.2272 + link = _dbus_list_get_first_link (&f->functions);
1.2273 + while (link != NULL)
1.2274 + {
1.2275 + Function *func = link->data;
1.2276 +
1.2277 + if (func->unused &&
1.2278 + !func->inside_dbus_build_tests)
1.2279 + printf (" %s\n", func->name);
1.2280 +
1.2281 + link = _dbus_list_get_next_link (&f->functions, link);
1.2282 + }
1.2283 +
1.2284 + printf ("\n");
1.2285 +}
1.2286 +
1.2287 +static void
1.2288 +print_poorly_tested_functions (File *f,
1.2289 + Stats *stats)
1.2290 +{
1.2291 + DBusList *link;
1.2292 + dbus_bool_t found;
1.2293 +
1.2294 +#define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
1.2295 +
1.2296 +#define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
1.2297 +
1.2298 +#define POORLY_TESTED(function) (!(function)->unused && \
1.2299 + (function)->n_nontest_blocks > 0 && \
1.2300 + TEST_FRACTION (function) < AVERAGE_COVERAGE)
1.2301 +
1.2302 + found = FALSE;
1.2303 + link = _dbus_list_get_first_link (&f->functions);
1.2304 + while (link != NULL)
1.2305 + {
1.2306 + Function *func = link->data;
1.2307 +
1.2308 + if (POORLY_TESTED (func))
1.2309 + found = TRUE;
1.2310 +
1.2311 + link = _dbus_list_get_next_link (&f->functions, link);
1.2312 + }
1.2313 +
1.2314 + if (!found)
1.2315 + return;
1.2316 +
1.2317 + printf ("Below average functions in %s\n", f->name);
1.2318 + printf ("=======\n");
1.2319 +
1.2320 + link = _dbus_list_get_first_link (&f->functions);
1.2321 + while (link != NULL)
1.2322 + {
1.2323 + Function *func = link->data;
1.2324 +
1.2325 + if (POORLY_TESTED (func))
1.2326 + printf (" %s (%d%%)\n", func->name,
1.2327 + (int) (TEST_FRACTION (func) * 100));
1.2328 +
1.2329 + link = _dbus_list_get_next_link (&f->functions, link);
1.2330 + }
1.2331 +
1.2332 + printf ("\n");
1.2333 +}
1.2334 +
1.2335 +static int
1.2336 +func_cmp (const void *a,
1.2337 + const void *b)
1.2338 +{
1.2339 + Function *af = *(Function**) a;
1.2340 + Function *bf = *(Function**) b;
1.2341 + int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
1.2342 + int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
1.2343 +
1.2344 + /* Sort by number of untested blocks */
1.2345 + return b_untested - a_untested;
1.2346 +}
1.2347 +
1.2348 +static void
1.2349 +print_n_untested_blocks_by_function (File *f,
1.2350 + Stats *stats)
1.2351 +{
1.2352 + DBusList *link;
1.2353 + Function **funcs;
1.2354 + int n_found;
1.2355 + int i;
1.2356 +
1.2357 + n_found = 0;
1.2358 + link = _dbus_list_get_first_link (&f->functions);
1.2359 + while (link != NULL)
1.2360 + {
1.2361 + Function *func = link->data;
1.2362 +
1.2363 + if (func->n_nontest_blocks_executed <
1.2364 + func->n_nontest_blocks)
1.2365 + n_found += 1;
1.2366 +
1.2367 + link = _dbus_list_get_next_link (&f->functions, link);
1.2368 + }
1.2369 +
1.2370 + if (n_found == 0)
1.2371 + return;
1.2372 +
1.2373 + /* make an array so we can use qsort */
1.2374 +
1.2375 + funcs = dbus_new (Function*, n_found);
1.2376 + if (funcs == NULL)
1.2377 + return;
1.2378 +
1.2379 + i = 0;
1.2380 + link = _dbus_list_get_first_link (&f->functions);
1.2381 + while (link != NULL)
1.2382 + {
1.2383 + Function *func = link->data;
1.2384 +
1.2385 + if (func->n_nontest_blocks_executed <
1.2386 + func->n_nontest_blocks)
1.2387 + {
1.2388 + funcs[i] = func;
1.2389 + ++i;
1.2390 + }
1.2391 +
1.2392 + link = _dbus_list_get_next_link (&f->functions, link);
1.2393 + }
1.2394 +
1.2395 + _dbus_assert (i == n_found);
1.2396 +
1.2397 + qsort (funcs, n_found, sizeof (Function*),
1.2398 + func_cmp);
1.2399 +
1.2400 + printf ("Incomplete functions in %s\n", f->name);
1.2401 + printf ("=======\n");
1.2402 +
1.2403 + i = 0;
1.2404 + while (i < n_found)
1.2405 + {
1.2406 + Function *func = funcs[i];
1.2407 +
1.2408 + printf (" %s (%d/%d untested blocks)\n",
1.2409 + func->name,
1.2410 + func->n_nontest_blocks - func->n_nontest_blocks_executed,
1.2411 + func->n_nontest_blocks);
1.2412 +
1.2413 + ++i;
1.2414 + }
1.2415 +
1.2416 + dbus_free (funcs);
1.2417 +
1.2418 + printf ("\n");
1.2419 +}
1.2420 +
1.2421 +static void
1.2422 +print_stats (Stats *stats,
1.2423 + const char *of_what)
1.2424 +{
1.2425 + int completely;
1.2426 +
1.2427 + printf ("Summary (%s)\n", of_what);
1.2428 + printf ("=======\n");
1.2429 + printf (" %g%% blocks executed (%d of %d)\n",
1.2430 + (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
1.2431 + stats->n_blocks_executed,
1.2432 + stats->n_blocks);
1.2433 +
1.2434 + printf (" (ignored %d blocks of test-only/debug-only code)\n",
1.2435 + stats->n_blocks_inside_dbus_build_tests);
1.2436 +
1.2437 + printf (" %g%% functions executed (%d of %d)\n",
1.2438 + (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
1.2439 + stats->n_functions_executed,
1.2440 + stats->n_functions);
1.2441 +
1.2442 + completely = stats->n_functions_executed - stats->n_functions_partial;
1.2443 + printf (" %g%% functions completely executed (%d of %d)\n",
1.2444 + (completely / (double) stats->n_functions) * 100.0,
1.2445 + completely,
1.2446 + stats->n_functions);
1.2447 +
1.2448 + printf (" (ignored %d functions of test-only/debug-only code)\n",
1.2449 + stats->n_functions_inside_dbus_build_tests);
1.2450 +
1.2451 + printf (" %g%% lines executed (%d of %d)\n",
1.2452 + (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
1.2453 + stats->n_lines_executed,
1.2454 + stats->n_lines);
1.2455 +
1.2456 + completely = stats->n_lines_executed - stats->n_lines_partial;
1.2457 + printf (" %g%% lines completely executed (%d of %d)\n",
1.2458 + (completely / (double) stats->n_lines) * 100.0,
1.2459 + completely,
1.2460 + stats->n_lines);
1.2461 +
1.2462 + printf (" (ignored %d lines of test-only/debug-only code)\n",
1.2463 + stats->n_lines_inside_dbus_build_tests);
1.2464 +
1.2465 + printf ("\n");
1.2466 +}
1.2467 +
1.2468 +typedef enum
1.2469 +{
1.2470 + MODE_PRINT,
1.2471 + MODE_REPORT,
1.2472 + MODE_BLOCKS,
1.2473 + MODE_GCOV
1.2474 +} Mode;
1.2475 +
1.2476 +int
1.2477 +main (int argc, char **argv)
1.2478 +{
1.2479 + DBusString filename;
1.2480 + int i;
1.2481 + Mode m;
1.2482 +
1.2483 + if (argc < 2)
1.2484 + {
1.2485 + fprintf (stderr, "Must specify files on command line\n");
1.2486 + return 1;
1.2487 + }
1.2488 +
1.2489 + m = MODE_PRINT;
1.2490 + i = 1;
1.2491 +
1.2492 + if (strcmp (argv[i], "--report") == 0)
1.2493 + {
1.2494 + m = MODE_REPORT;
1.2495 + ++i;
1.2496 + }
1.2497 + else if (strcmp (argv[i], "--blocks") == 0)
1.2498 + {
1.2499 + m = MODE_BLOCKS;
1.2500 + ++i;
1.2501 + }
1.2502 + else if (strcmp (argv[i], "--gcov") == 0)
1.2503 + {
1.2504 + m = MODE_GCOV;
1.2505 + ++i;
1.2506 + }
1.2507 +
1.2508 +
1.2509 + if (i == argc)
1.2510 + {
1.2511 + fprintf (stderr, "Must specify files on command line\n");
1.2512 + return 1;
1.2513 + }
1.2514 +
1.2515 + if (m == MODE_PRINT)
1.2516 + {
1.2517 + while (i < argc)
1.2518 + {
1.2519 + _dbus_string_init_const (&filename, argv[i]);
1.2520 +
1.2521 + print_one_file (&filename);
1.2522 +
1.2523 + ++i;
1.2524 + }
1.2525 + }
1.2526 + else if (m == MODE_BLOCKS || m == MODE_GCOV)
1.2527 + {
1.2528 + while (i < argc)
1.2529 + {
1.2530 + File *f;
1.2531 +
1.2532 + _dbus_string_init_const (&filename, argv[i]);
1.2533 +
1.2534 + f = load_c_file (&filename);
1.2535 +
1.2536 + if (m == MODE_BLOCKS)
1.2537 + print_block_superdetails (f);
1.2538 + else if (m == MODE_GCOV)
1.2539 + print_annotated_source_gcov_format (f);
1.2540 +
1.2541 + ++i;
1.2542 + }
1.2543 + }
1.2544 + else if (m == MODE_REPORT)
1.2545 + {
1.2546 + Stats stats = { 0, };
1.2547 + DBusList *files;
1.2548 + DBusList *link;
1.2549 + DBusHashTable *stats_by_dir;
1.2550 + DBusHashIter iter;
1.2551 +
1.2552 + files = NULL;
1.2553 + while (i < argc)
1.2554 + {
1.2555 + _dbus_string_init_const (&filename, argv[i]);
1.2556 +
1.2557 + if (_dbus_string_ends_with_c_str (&filename, ".c"))
1.2558 + {
1.2559 + File *f;
1.2560 +
1.2561 + f = load_c_file (&filename);
1.2562 +
1.2563 + if (!_dbus_list_append (&files, f))
1.2564 + die ("no memory\n");
1.2565 + }
1.2566 + else
1.2567 + {
1.2568 + fprintf (stderr, "Unknown file type %s\n",
1.2569 + _dbus_string_get_const_data (&filename));
1.2570 + exit (1);
1.2571 + }
1.2572 +
1.2573 + ++i;
1.2574 + }
1.2575 +
1.2576 + link = _dbus_list_get_first_link (&files);
1.2577 + while (link != NULL)
1.2578 + {
1.2579 + File *f = link->data;
1.2580 +
1.2581 + merge_stats_for_file (&stats, f);
1.2582 +
1.2583 + link = _dbus_list_get_next_link (&files, link);
1.2584 + }
1.2585 +
1.2586 + print_stats (&stats, "all files");
1.2587 +
1.2588 + stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
1.2589 + dbus_free, dbus_free);
1.2590 +
1.2591 + link = _dbus_list_get_first_link (&files);
1.2592 + while (link != NULL)
1.2593 + {
1.2594 + File *f = link->data;
1.2595 + DBusString dirname;
1.2596 + char *dirname_c;
1.2597 + Stats *dir_stats;
1.2598 +
1.2599 + _dbus_string_init_const (&filename, f->name);
1.2600 +
1.2601 + if (!_dbus_string_init (&dirname))
1.2602 + die ("no memory\n");
1.2603 +
1.2604 + if (!_dbus_string_get_dirname (&filename, &dirname) ||
1.2605 + !_dbus_string_copy_data (&dirname, &dirname_c))
1.2606 + die ("no memory\n");
1.2607 +
1.2608 + dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
1.2609 + dirname_c);
1.2610 +
1.2611 + if (dir_stats == NULL)
1.2612 + {
1.2613 + dir_stats = dbus_new0 (Stats, 1);
1.2614 + if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
1.2615 + dir_stats))
1.2616 + die ("no memory\n");
1.2617 + }
1.2618 + else
1.2619 + dbus_free (dirname_c);
1.2620 +
1.2621 + merge_stats_for_file (dir_stats, f);
1.2622 +
1.2623 + link = _dbus_list_get_next_link (&files, link);
1.2624 + }
1.2625 +
1.2626 + _dbus_hash_iter_init (stats_by_dir, &iter);
1.2627 + while (_dbus_hash_iter_next (&iter))
1.2628 + {
1.2629 + const char *dirname = _dbus_hash_iter_get_string_key (&iter);
1.2630 + Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
1.2631 +
1.2632 + print_stats (dir_stats, dirname);
1.2633 + }
1.2634 +
1.2635 + _dbus_hash_table_unref (stats_by_dir);
1.2636 +
1.2637 + link = _dbus_list_get_first_link (&files);
1.2638 + while (link != NULL)
1.2639 + {
1.2640 + File *f = link->data;
1.2641 +
1.2642 + print_untested_functions (f);
1.2643 +
1.2644 + link = _dbus_list_get_next_link (&files, link);
1.2645 + }
1.2646 +
1.2647 + link = _dbus_list_get_first_link (&files);
1.2648 + while (link != NULL)
1.2649 + {
1.2650 + File *f = link->data;
1.2651 +
1.2652 + print_poorly_tested_functions (f, &stats);
1.2653 +
1.2654 + link = _dbus_list_get_next_link (&files, link);
1.2655 + }
1.2656 +
1.2657 + link = _dbus_list_get_first_link (&files);
1.2658 + while (link != NULL)
1.2659 + {
1.2660 + File *f = link->data;
1.2661 +
1.2662 + print_n_untested_blocks_by_function (f, &stats);
1.2663 +
1.2664 + link = _dbus_list_get_next_link (&files, link);
1.2665 + }
1.2666 + }
1.2667 +
1.2668 + return 0;
1.2669 +}