os/ossrv/ofdbus/dbus/tsrc/testapps/dbus_test_cases/decode-gcov.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
sl@0
     2
 /* -*- mode: C; c-file-style: "gnu" -*- */
sl@0
     3
/* decode-gcov.c gcov decoder program
sl@0
     4
 *
sl@0
     5
 * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
sl@0
     6
 * Copyright (C) 2003  Red Hat Inc.
sl@0
     7
 *
sl@0
     8
 * Partially derived from gcov,
sl@0
     9
 * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
sl@0
    10
 * 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
sl@0
    11
 *
sl@0
    12
 * This file is NOT licensed under the Academic Free License
sl@0
    13
 * as it is largely derived from gcov.c and gcov-io.h in the
sl@0
    14
 * gcc source code.
sl@0
    15
 * 
sl@0
    16
 * This program is free software; you can redistribute it and/or modify
sl@0
    17
 * it under the terms of the GNU General Public License as published by
sl@0
    18
 * the Free Software Foundation; either version 2 of the License, or
sl@0
    19
 * (at your option) any later version.
sl@0
    20
 *
sl@0
    21
 * This program is distributed in the hope that it will be useful,
sl@0
    22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
sl@0
    23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
sl@0
    24
 * GNU General Public License for more details.
sl@0
    25
 * 
sl@0
    26
 * You should have received a copy of the GNU General Public License
sl@0
    27
 * along with this program; if not, write to the Free Software
sl@0
    28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
sl@0
    29
 *
sl@0
    30
 */
sl@0
    31
sl@0
    32
#define DBUS_COMPILATION /* cheat */
sl@0
    33
#ifndef __SYMBIAN32__
sl@0
    34
#include <dbus/dbus-list.h>
sl@0
    35
#include <dbus/dbus-string.h>
sl@0
    36
#include <dbus/dbus-sysdeps.h>
sl@0
    37
#include <dbus/dbus-hash.h>
sl@0
    38
#else
sl@0
    39
#include "dbus-list.h"
sl@0
    40
#include "dbus-string.h"
sl@0
    41
#include "dbus-sysdeps.h"
sl@0
    42
#include "dbus-hash.h"
sl@0
    43
#endif
sl@0
    44
sl@0
    45
sl@0
    46
#undef DBUS_COMPILATION
sl@0
    47
#include <stdio.h>
sl@0
    48
#include <stdlib.h>
sl@0
    49
#include <string.h>
sl@0
    50
sl@0
    51
#ifdef SYMBIAN
sl@0
    52
#define DBUS_HAVE_INT64 1
sl@0
    53
#endif
sl@0
    54
sl@0
    55
#ifndef DBUS_HAVE_INT64
sl@0
    56
#error "gcov support can't be built without 64-bit integer support"
sl@0
    57
#endif
sl@0
    58
sl@0
    59
static void
sl@0
    60
die (const char *message)
sl@0
    61
{
sl@0
    62
  fprintf (stderr, "%s", message);
sl@0
    63
  exit (1);
sl@0
    64
}
sl@0
    65
sl@0
    66
/* This bizarro function is from gcov-io.h in gcc source tree */
sl@0
    67
static int
sl@0
    68
fetch_long (long        *dest,
sl@0
    69
            const char  *source,
sl@0
    70
            size_t       bytes)
sl@0
    71
{
sl@0
    72
  long value = 0;
sl@0
    73
  int i;
sl@0
    74
                                                                                
sl@0
    75
  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
sl@0
    76
    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
sl@0
    77
      return 1;
sl@0
    78
                                                                                
sl@0
    79
  for (; i >= 0; i--)
sl@0
    80
    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
sl@0
    81
                                                                                
sl@0
    82
  if ((source[bytes - 1] & 128) && (value > 0))
sl@0
    83
    value = - value;
sl@0
    84
                                                                                
sl@0
    85
  *dest = value;
sl@0
    86
  return 0;
sl@0
    87
}
sl@0
    88
sl@0
    89
static int
sl@0
    90
fetch_long64 (dbus_int64_t *dest,
sl@0
    91
              const char   *source,
sl@0
    92
              size_t        bytes)
sl@0
    93
{
sl@0
    94
  dbus_int64_t value = 0;
sl@0
    95
  int i;
sl@0
    96
                                                                                
sl@0
    97
  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
sl@0
    98
    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
sl@0
    99
      return 1;
sl@0
   100
                                                                                
sl@0
   101
  for (; i >= 0; i--)
sl@0
   102
    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
sl@0
   103
                                                                                
sl@0
   104
  if ((source[bytes - 1] & 128) && (value > 0))
sl@0
   105
    value = - value;
sl@0
   106
                                                                                
sl@0
   107
  *dest = value;
sl@0
   108
  return 0;
sl@0
   109
}
sl@0
   110
sl@0
   111
#define BB_FILENAME 	(-1)
sl@0
   112
#define BB_FUNCTION 	(-2)
sl@0
   113
#define BB_ENDOFLIST	0
sl@0
   114
sl@0
   115
static dbus_bool_t
sl@0
   116
string_get_int (const DBusString *str,
sl@0
   117
                int               start,
sl@0
   118
                long             *val)
sl@0
   119
{
sl@0
   120
  const char *p;
sl@0
   121
  
sl@0
   122
  if ((_dbus_string_get_length (str) - start) < 4)
sl@0
   123
    return FALSE;
sl@0
   124
sl@0
   125
  p = _dbus_string_get_const_data (str);
sl@0
   126
sl@0
   127
  p += start;
sl@0
   128
sl@0
   129
  fetch_long (val, p, 4);
sl@0
   130
  
sl@0
   131
  return TRUE;
sl@0
   132
}
sl@0
   133
sl@0
   134
static dbus_bool_t
sl@0
   135
string_get_int64 (const DBusString *str,
sl@0
   136
                  int               start,
sl@0
   137
                  dbus_int64_t     *val)
sl@0
   138
{
sl@0
   139
  const char *p;
sl@0
   140
  
sl@0
   141
  if ((_dbus_string_get_length (str) - start) < 8)
sl@0
   142
    return FALSE;
sl@0
   143
sl@0
   144
  p = _dbus_string_get_const_data (str);
sl@0
   145
sl@0
   146
  p += start;
sl@0
   147
sl@0
   148
  fetch_long64 (val, p, 8);
sl@0
   149
  
sl@0
   150
  return TRUE;
sl@0
   151
}
sl@0
   152
sl@0
   153
static dbus_bool_t
sl@0
   154
string_get_string (const DBusString *str,
sl@0
   155
                   int               start,
sl@0
   156
                   long              terminator,
sl@0
   157
                   DBusString       *val,
sl@0
   158
                   int              *end)
sl@0
   159
{
sl@0
   160
  int i;
sl@0
   161
  long n;
sl@0
   162
  
sl@0
   163
  i = start;
sl@0
   164
  while (string_get_int (str, i, &n))
sl@0
   165
    {
sl@0
   166
      unsigned char b;
sl@0
   167
      
sl@0
   168
      i += 4;
sl@0
   169
      
sl@0
   170
      if (n == terminator)
sl@0
   171
        break;
sl@0
   172
sl@0
   173
      b = n & 0xff;
sl@0
   174
      if (b)
sl@0
   175
        {
sl@0
   176
          _dbus_string_append_byte (val, b);
sl@0
   177
          b = (n >> 8) & 0xff;
sl@0
   178
          if (b)
sl@0
   179
            {
sl@0
   180
              _dbus_string_append_byte (val, b);
sl@0
   181
              b = (n >> 16) & 0xff;
sl@0
   182
              if (b)
sl@0
   183
                {
sl@0
   184
                  _dbus_string_append_byte (val, b);
sl@0
   185
                  b = (n >> 24) & 0xff;
sl@0
   186
                  if (b)
sl@0
   187
                    _dbus_string_append_byte (val, b);
sl@0
   188
                }
sl@0
   189
            }
sl@0
   190
        }
sl@0
   191
    }
sl@0
   192
sl@0
   193
  *end = i;
sl@0
   194
  
sl@0
   195
  return TRUE;
sl@0
   196
}
sl@0
   197
sl@0
   198
#ifdef DBUS_HAVE_GCC33_GCOV
sl@0
   199
/* In gcc33 .bbg files, there's a function name of the form:
sl@0
   200
 *   -1, length, name (padded to 4), -1, checksum
sl@0
   201
 */
sl@0
   202
static dbus_bool_t
sl@0
   203
string_get_function (const DBusString *str,
sl@0
   204
                     int               start,
sl@0
   205
                     DBusString       *funcname,
sl@0
   206
                     int              *checksum,
sl@0
   207
                     int              *next)
sl@0
   208
{
sl@0
   209
  int end;
sl@0
   210
  long val;
sl@0
   211
  int i;
sl@0
   212
sl@0
   213
  i = start;
sl@0
   214
  
sl@0
   215
  if (!string_get_int (str, i, &val))
sl@0
   216
    die ("no room for -1 before function name\n");
sl@0
   217
        
sl@0
   218
  i += 4;
sl@0
   219
sl@0
   220
  if (val != -1)
sl@0
   221
    die ("value before function name is not -1\n");
sl@0
   222
  
sl@0
   223
  if (!string_get_int (str, i, &val))
sl@0
   224
    die ("no length found for function name\n");
sl@0
   225
        
sl@0
   226
  i += 4;
sl@0
   227
sl@0
   228
  end = i + val;
sl@0
   229
  if (end > _dbus_string_get_length (str))
sl@0
   230
    die ("Function name length points past end of file\n");
sl@0
   231
sl@0
   232
  if (!_dbus_string_append (funcname,
sl@0
   233
                            _dbus_string_get_const_data (str) + i))
sl@0
   234
    die ("no memory\n");
sl@0
   235
        
sl@0
   236
  /* skip alignment padding the length doesn't include the nul so add 1
sl@0
   237
   */
sl@0
   238
  i = _DBUS_ALIGN_VALUE (end + 1, 4);
sl@0
   239
        
sl@0
   240
  if (!string_get_int (str, i, &val) ||
sl@0
   241
      val != -1)
sl@0
   242
    die ("-1 at end of function name not found\n");
sl@0
   243
        
sl@0
   244
  i += 4;
sl@0
   245
sl@0
   246
  if (!string_get_int (str, i, &val))
sl@0
   247
    die ("no checksum found at end of function name\n");
sl@0
   248
        
sl@0
   249
  i += 4;
sl@0
   250
sl@0
   251
  *checksum = val;
sl@0
   252
sl@0
   253
  *next = i;
sl@0
   254
sl@0
   255
  return TRUE;
sl@0
   256
}
sl@0
   257
#endif /* DBUS_HAVE_GCC33_GCOV */
sl@0
   258
sl@0
   259
static void
sl@0
   260
dump_bb_file (const DBusString *contents)
sl@0
   261
{
sl@0
   262
  int i;
sl@0
   263
  long val;
sl@0
   264
  int n_functions;
sl@0
   265
sl@0
   266
  n_functions = 0;
sl@0
   267
  i = 0;
sl@0
   268
  while (string_get_int (contents, i, &val))
sl@0
   269
    {
sl@0
   270
      i += 4;
sl@0
   271
      
sl@0
   272
      switch (val)
sl@0
   273
        {
sl@0
   274
        case BB_FILENAME:
sl@0
   275
          {
sl@0
   276
            DBusString f;
sl@0
   277
sl@0
   278
            if (!_dbus_string_init (&f))
sl@0
   279
              die ("no memory\n");
sl@0
   280
sl@0
   281
            if (string_get_string (contents, i,
sl@0
   282
                                   BB_FILENAME,
sl@0
   283
                                   &f, &i))
sl@0
   284
              {
sl@0
   285
                printf ("File %s\n", _dbus_string_get_const_data (&f));
sl@0
   286
              }
sl@0
   287
            _dbus_string_free (&f);
sl@0
   288
          }
sl@0
   289
          break;
sl@0
   290
        case BB_FUNCTION:
sl@0
   291
          {
sl@0
   292
            DBusString f;
sl@0
   293
            if (!_dbus_string_init (&f))
sl@0
   294
              die ("no memory\n");
sl@0
   295
sl@0
   296
            if (string_get_string (contents, i,
sl@0
   297
                                   BB_FUNCTION,
sl@0
   298
                                   &f, &i))
sl@0
   299
              {
sl@0
   300
                printf ("Function %s\n", _dbus_string_get_const_data (&f));
sl@0
   301
              }
sl@0
   302
            _dbus_string_free (&f);
sl@0
   303
sl@0
   304
            n_functions += 1;
sl@0
   305
          }
sl@0
   306
          break;
sl@0
   307
        case BB_ENDOFLIST:
sl@0
   308
          printf ("End of block\n");
sl@0
   309
          break;
sl@0
   310
        default:
sl@0
   311
          printf ("Line %ld\n", val);
sl@0
   312
          break;
sl@0
   313
        }
sl@0
   314
    }
sl@0
   315
sl@0
   316
  printf ("%d functions in file\n", n_functions);
sl@0
   317
}
sl@0
   318
sl@0
   319
#define FLAG_ON_TREE 0x1
sl@0
   320
#define FLAG_FAKE 0x2
sl@0
   321
#define FLAG_FALL_THROUGH 0x4
sl@0
   322
sl@0
   323
static void
sl@0
   324
dump_bbg_file (const DBusString *contents)
sl@0
   325
{
sl@0
   326
  int i;
sl@0
   327
  long val;
sl@0
   328
  int n_functions;
sl@0
   329
  int n_arcs;
sl@0
   330
  int n_blocks;
sl@0
   331
  int n_arcs_off_tree;
sl@0
   332
  
sl@0
   333
  n_arcs_off_tree = 0;
sl@0
   334
  n_blocks = 0;
sl@0
   335
  n_arcs = 0;
sl@0
   336
  n_functions = 0;
sl@0
   337
  i = 0;
sl@0
   338
  while (i < _dbus_string_get_length (contents))
sl@0
   339
    {
sl@0
   340
      long n_blocks_in_func;
sl@0
   341
      long n_arcs_in_func; 
sl@0
   342
      int j;
sl@0
   343
sl@0
   344
#ifdef DBUS_HAVE_GCC33_GCOV
sl@0
   345
      /* In gcc33 .bbg files, there's a function name of the form:
sl@0
   346
       *   -1, length, name (padded to 4), -1, checksum
sl@0
   347
       * after that header on each function description, it's
sl@0
   348
       * the same as in gcc32
sl@0
   349
       */
sl@0
   350
sl@0
   351
      {
sl@0
   352
        DBusString funcname;
sl@0
   353
        int checksum;
sl@0
   354
        
sl@0
   355
        if (!_dbus_string_init (&funcname))
sl@0
   356
          die ("no memory\n");
sl@0
   357
sl@0
   358
        if (!string_get_function (contents, i,
sl@0
   359
                                  &funcname, &checksum, &i))
sl@0
   360
          die ("could not read function name\n");
sl@0
   361
        
sl@0
   362
        printf ("Function name is \"%s\" checksum %d\n",
sl@0
   363
                _dbus_string_get_const_data (&funcname),
sl@0
   364
                checksum);
sl@0
   365
        
sl@0
   366
        _dbus_string_free (&funcname);
sl@0
   367
      }
sl@0
   368
#endif /* DBUS_HAVE_GCC33_GCOV */
sl@0
   369
      
sl@0
   370
      if (!string_get_int (contents, i, &val))
sl@0
   371
        die ("no count of blocks in func found\n");
sl@0
   372
      
sl@0
   373
      i += 4;
sl@0
   374
      
sl@0
   375
      n_blocks_in_func = val;
sl@0
   376
sl@0
   377
      if (!string_get_int (contents, i, &n_arcs_in_func))
sl@0
   378
        break;
sl@0
   379
sl@0
   380
      i += 4;
sl@0
   381
sl@0
   382
      printf ("Function has %ld blocks and %ld arcs\n",
sl@0
   383
              n_blocks_in_func, n_arcs_in_func);
sl@0
   384
sl@0
   385
      n_functions += 1;
sl@0
   386
      n_blocks += n_blocks_in_func;
sl@0
   387
      n_arcs += n_arcs_in_func;
sl@0
   388
      
sl@0
   389
      j = 0;
sl@0
   390
      while (j < n_blocks_in_func)
sl@0
   391
        {
sl@0
   392
          long n_arcs_in_block;
sl@0
   393
          int k;
sl@0
   394
          
sl@0
   395
          if (!string_get_int (contents, i, &n_arcs_in_block))
sl@0
   396
            break;
sl@0
   397
sl@0
   398
          i += 4;
sl@0
   399
sl@0
   400
          printf ("  Block has %ld arcs\n", n_arcs_in_block);
sl@0
   401
          
sl@0
   402
          k = 0;
sl@0
   403
          while (k < n_arcs_in_block)
sl@0
   404
            {
sl@0
   405
              long destination_block;
sl@0
   406
              long flags;
sl@0
   407
              
sl@0
   408
              if (!string_get_int (contents, i, &destination_block))
sl@0
   409
                break;
sl@0
   410
sl@0
   411
              i += 4;
sl@0
   412
              
sl@0
   413
              if (!string_get_int (contents, i, &flags))
sl@0
   414
                break;
sl@0
   415
sl@0
   416
              i += 4;
sl@0
   417
sl@0
   418
              printf ("    Arc has destination block %ld flags 0x%lx\n",
sl@0
   419
                      destination_block, flags);
sl@0
   420
sl@0
   421
              if ((flags & FLAG_ON_TREE) == 0)
sl@0
   422
                n_arcs_off_tree += 1;
sl@0
   423
              
sl@0
   424
              ++k;
sl@0
   425
            }
sl@0
   426
sl@0
   427
          if (k < n_arcs_in_block)
sl@0
   428
            break;
sl@0
   429
          
sl@0
   430
          ++j;
sl@0
   431
        }
sl@0
   432
sl@0
   433
      if (j < n_blocks_in_func)
sl@0
   434
        break;
sl@0
   435
sl@0
   436
      if (!string_get_int (contents, i, &val))
sl@0
   437
        break;
sl@0
   438
sl@0
   439
      i += 4;
sl@0
   440
sl@0
   441
      if (val != -1)
sl@0
   442
        die ("-1 separator not found\n");
sl@0
   443
    }
sl@0
   444
sl@0
   445
  printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
sl@0
   446
          n_functions, n_blocks, n_arcs, n_arcs_off_tree);
sl@0
   447
}
sl@0
   448
sl@0
   449
#ifndef DBUS_HAVE_GCC33_GCOV
sl@0
   450
sl@0
   451
/* gcc 3.2 version:
sl@0
   452
 * The da file contains first a count of arcs in the file,
sl@0
   453
 * then a count of executions for all "off tree" arcs
sl@0
   454
 * in the file.
sl@0
   455
 */
sl@0
   456
static void
sl@0
   457
dump_da_file (const DBusString *contents)
sl@0
   458
{
sl@0
   459
  int i;
sl@0
   460
  dbus_int64_t val;
sl@0
   461
  int n_arcs;
sl@0
   462
  int claimed_n_arcs;
sl@0
   463
sl@0
   464
  i = 0;
sl@0
   465
  if (!string_get_int64 (contents, i, &val))
sl@0
   466
    return;
sl@0
   467
sl@0
   468
  i += 8;
sl@0
   469
  
sl@0
   470
  printf ("%ld arcs in file\n", (long) val);
sl@0
   471
  claimed_n_arcs = val;
sl@0
   472
  
sl@0
   473
  n_arcs = 0;
sl@0
   474
  while (string_get_int64 (contents, i, &val))
sl@0
   475
    {
sl@0
   476
      i += 8;
sl@0
   477
sl@0
   478
      printf ("%ld executions of arc %d\n",
sl@0
   479
              (long) val, n_arcs);
sl@0
   480
sl@0
   481
      ++n_arcs;
sl@0
   482
    }
sl@0
   483
sl@0
   484
  if (n_arcs != claimed_n_arcs)
sl@0
   485
    {
sl@0
   486
      printf ("File claimed to have %d arcs but only had %d\n",
sl@0
   487
              claimed_n_arcs, n_arcs);
sl@0
   488
    }
sl@0
   489
}
sl@0
   490
sl@0
   491
#else /* DBUS_HAVE_GCC33_GCOV */
sl@0
   492
sl@0
   493
/* gcc 3.3 version:
sl@0
   494
 * The da file is more complex than 3.2.
sl@0
   495
 *
sl@0
   496
 * We have a magic value of "-123" only it isn't really
sl@0
   497
 * -123, it's -123 as encoded by the crackass gcov-io.h
sl@0
   498
 * routines. Anyway, 4 bytes.
sl@0
   499
 *
sl@0
   500
 * We then have:
sl@0
   501
 *
sl@0
   502
 *   - 4 byte count of how many functions in the following list
sl@0
   503
 *   - 4 byte length of random extra data
sl@0
   504
 *   - the random extra data, just skip it, info pages have some
sl@0
   505
 *     details on what might be in there or see __bb_exit_func in gcc
sl@0
   506
 *   - then for each function (number of functions given above):
sl@0
   507
 *     . -1, length, funcname, alignment padding, -1
sl@0
   508
 *     . checksum
sl@0
   509
 *     . 4 byte number of arcs in function
sl@0
   510
 *     . 8 bytes each, a count of execution for each arc
sl@0
   511
 *
sl@0
   512
 * Now, the whole thing *starting with the magic* can repeat.
sl@0
   513
 * This is caused by multiple runs of the profiled app appending
sl@0
   514
 * to the file.
sl@0
   515
 */
sl@0
   516
static void
sl@0
   517
dump_da_file (const DBusString *contents)
sl@0
   518
{
sl@0
   519
  int i;
sl@0
   520
  dbus_int64_t v64;
sl@0
   521
  long val;
sl@0
   522
  int n_sections;
sl@0
   523
  int total_functions;
sl@0
   524
sl@0
   525
  total_functions = 0;
sl@0
   526
  n_sections = 0;
sl@0
   527
sl@0
   528
  i = 0;
sl@0
   529
  while (i < _dbus_string_get_length (contents))
sl@0
   530
    {
sl@0
   531
      int claimed_n_functions;
sl@0
   532
      int n_functions;
sl@0
   533
      int total_arcs;
sl@0
   534
sl@0
   535
      printf (".da file section %d\n", n_sections);
sl@0
   536
      
sl@0
   537
      if (!string_get_int (contents, i, &val))
sl@0
   538
        die ("no magic found in .da file\n");
sl@0
   539
sl@0
   540
      i += 4;
sl@0
   541
sl@0
   542
      if (val != -123)
sl@0
   543
        die ("wrong file magic in .da file\n");
sl@0
   544
sl@0
   545
      if (!string_get_int (contents, i, &val))
sl@0
   546
        die ("no function count in .da file\n");
sl@0
   547
      i += 4;
sl@0
   548
      claimed_n_functions = val;
sl@0
   549
sl@0
   550
      printf ("%d functions expected in section %d of .da file\n",
sl@0
   551
              claimed_n_functions, n_sections);
sl@0
   552
      
sl@0
   553
      if (!string_get_int (contents, i, &val))
sl@0
   554
        die ("no extra data length in .da file\n");
sl@0
   555
sl@0
   556
      i += 4;
sl@0
   557
sl@0
   558
      i += val;
sl@0
   559
sl@0
   560
      total_arcs = 0;
sl@0
   561
      n_functions = 0;
sl@0
   562
      while (n_functions < claimed_n_functions)
sl@0
   563
        {
sl@0
   564
          DBusString funcname;
sl@0
   565
          int checksum;
sl@0
   566
          int claimed_n_arcs;
sl@0
   567
          int n_arcs;
sl@0
   568
          
sl@0
   569
          if (!_dbus_string_init (&funcname))
sl@0
   570
            die ("no memory\n");
sl@0
   571
          
sl@0
   572
          if (!string_get_function (contents, i,
sl@0
   573
                                    &funcname, &checksum, &i))
sl@0
   574
            die ("could not read function name\n");
sl@0
   575
          
sl@0
   576
          if (!string_get_int (contents, i, &val))
sl@0
   577
            die ("no arc count for function\n");
sl@0
   578
          
sl@0
   579
          i += 4;
sl@0
   580
          claimed_n_arcs = val;
sl@0
   581
          
sl@0
   582
          printf ("  %d arcs in function %d %s checksum %d\n",
sl@0
   583
                  claimed_n_arcs, n_functions,
sl@0
   584
                  _dbus_string_get_const_data (&funcname),
sl@0
   585
                  checksum);
sl@0
   586
          
sl@0
   587
          n_arcs = 0;
sl@0
   588
          while (n_arcs < claimed_n_arcs)
sl@0
   589
            {
sl@0
   590
              if (!string_get_int64 (contents, i, &v64))
sl@0
   591
                die ("did not get execution count for arc\n");
sl@0
   592
              
sl@0
   593
              i += 8;
sl@0
   594
              
sl@0
   595
              printf ("    %ld executions of arc %d (total arcs %d)\n",
sl@0
   596
                      (long) v64, n_arcs, total_arcs + n_arcs);
sl@0
   597
              
sl@0
   598
              ++n_arcs;
sl@0
   599
            }
sl@0
   600
sl@0
   601
          _dbus_string_free (&funcname);
sl@0
   602
sl@0
   603
          total_arcs += n_arcs;
sl@0
   604
          ++n_functions;
sl@0
   605
        }
sl@0
   606
sl@0
   607
      printf ("total of %d functions and %d arcs in section %d\n",
sl@0
   608
              n_functions, total_arcs, n_sections);
sl@0
   609
      
sl@0
   610
      total_functions += n_functions;
sl@0
   611
      ++n_sections;
sl@0
   612
    }
sl@0
   613
sl@0
   614
  printf ("%d total function sections in %d total .da file sections\n",
sl@0
   615
          total_functions, n_sections);
sl@0
   616
}
sl@0
   617
sl@0
   618
#endif /* DBUS_HAVE_GCC33_GCOV */
sl@0
   619
sl@0
   620
typedef struct Arc Arc;
sl@0
   621
typedef struct Block Block;
sl@0
   622
typedef struct Function Function;
sl@0
   623
typedef struct File File;
sl@0
   624
typedef struct Line Line;
sl@0
   625
sl@0
   626
struct Arc
sl@0
   627
{
sl@0
   628
  int source;
sl@0
   629
  int target;
sl@0
   630
  dbus_int64_t arc_count;
sl@0
   631
  unsigned int count_valid : 1;
sl@0
   632
  unsigned int on_tree : 1;
sl@0
   633
  unsigned int fake : 1;
sl@0
   634
  unsigned int fall_through : 1;
sl@0
   635
  Arc *pred_next;
sl@0
   636
  Arc *succ_next;
sl@0
   637
};
sl@0
   638
sl@0
   639
struct Block
sl@0
   640
{
sl@0
   641
  Arc *succ;
sl@0
   642
  Arc *pred;
sl@0
   643
  dbus_int64_t succ_count;
sl@0
   644
  dbus_int64_t pred_count;
sl@0
   645
  dbus_int64_t exec_count;
sl@0
   646
  DBusList *lines;
sl@0
   647
  unsigned int count_valid : 1;
sl@0
   648
  unsigned int on_tree : 1;
sl@0
   649
  unsigned int inside_dbus_build_tests : 1;
sl@0
   650
};
sl@0
   651
sl@0
   652
struct Function
sl@0
   653
{
sl@0
   654
  char *name;
sl@0
   655
  int checksum;
sl@0
   656
  Block *block_graph;
sl@0
   657
  int n_blocks;
sl@0
   658
  /* number of blocks in DBUS_BUILD_TESTS */
sl@0
   659
  int n_test_blocks;
sl@0
   660
  int n_test_blocks_executed;
sl@0
   661
  /* number of blocks outside DBUS_BUILD_TESTS */
sl@0
   662
  int n_nontest_blocks;
sl@0
   663
  int n_nontest_blocks_executed;
sl@0
   664
  /* Summary result flags */
sl@0
   665
  unsigned int unused : 1;
sl@0
   666
  unsigned int inside_dbus_build_tests : 1;
sl@0
   667
  unsigned int partial : 1; /* only some of the blocks were executed */
sl@0
   668
};
sl@0
   669
sl@0
   670
struct Line
sl@0
   671
{
sl@0
   672
  int    number;
sl@0
   673
  char  *text;
sl@0
   674
  DBusList *blocks;
sl@0
   675
  unsigned int inside_dbus_build_tests : 1;
sl@0
   676
  unsigned int partial : 1; /* only some of the blocks were executed */
sl@0
   677
};
sl@0
   678
sl@0
   679
struct File
sl@0
   680
{
sl@0
   681
  char *name;
sl@0
   682
  Line *lines;
sl@0
   683
  int   n_lines;
sl@0
   684
  DBusList *functions;
sl@0
   685
};
sl@0
   686
sl@0
   687
static void
sl@0
   688
function_add_arc (Function *function,
sl@0
   689
                  long      source,
sl@0
   690
                  long      target,
sl@0
   691
                  long      flags)
sl@0
   692
{
sl@0
   693
  Arc *arc;
sl@0
   694
sl@0
   695
  arc = dbus_new0 (Arc, 1);
sl@0
   696
  if (arc == NULL)
sl@0
   697
    die ("no memory\n");
sl@0
   698
  
sl@0
   699
  arc->target = target;
sl@0
   700
  arc->source = source;
sl@0
   701
sl@0
   702
  arc->succ_next = function->block_graph[source].succ;
sl@0
   703
  function->block_graph[source].succ = arc;
sl@0
   704
  function->block_graph[source].succ_count += 1;
sl@0
   705
sl@0
   706
  arc->pred_next = function->block_graph[target].pred;
sl@0
   707
  function->block_graph[target].pred = arc;
sl@0
   708
  function->block_graph[target].pred_count += 1;
sl@0
   709
sl@0
   710
  if ((flags & FLAG_ON_TREE) != 0)
sl@0
   711
    arc->on_tree = TRUE;
sl@0
   712
sl@0
   713
  if ((flags & FLAG_FAKE) != 0)
sl@0
   714
    arc->fake = TRUE;
sl@0
   715
sl@0
   716
  if ((flags & FLAG_FALL_THROUGH) != 0)
sl@0
   717
    arc->fall_through = TRUE;
sl@0
   718
}
sl@0
   719
sl@0
   720
sl@0
   721
static Arc*
sl@0
   722
reverse_arcs (Arc *arc)
sl@0
   723
{
sl@0
   724
  struct Arc *prev = 0;
sl@0
   725
  struct Arc *next;
sl@0
   726
sl@0
   727
  for ( ; arc; arc = next)
sl@0
   728
    {
sl@0
   729
      next = arc->succ_next;
sl@0
   730
      arc->succ_next = prev;
sl@0
   731
      prev = arc;
sl@0
   732
    }
sl@0
   733
sl@0
   734
  return prev;
sl@0
   735
}
sl@0
   736
sl@0
   737
static void
sl@0
   738
function_reverse_succ_arcs (Function *func)
sl@0
   739
{
sl@0
   740
  /* Must reverse the order of all succ arcs, to ensure that they match
sl@0
   741
   * the order of the data in the .da file.
sl@0
   742
   */
sl@0
   743
  int i;
sl@0
   744
  
sl@0
   745
  for (i = 0; i < func->n_blocks; i++)
sl@0
   746
    if (func->block_graph[i].succ)
sl@0
   747
      func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
sl@0
   748
}
sl@0
   749
sl@0
   750
static void
sl@0
   751
get_functions_from_bbg (const DBusString  *contents,
sl@0
   752
                        DBusList         **functions)
sl@0
   753
{
sl@0
   754
  int i;
sl@0
   755
  long val;
sl@0
   756
  int n_functions;
sl@0
   757
  int n_arcs;
sl@0
   758
  int n_blocks;
sl@0
   759
  int n_arcs_off_tree;
sl@0
   760
sl@0
   761
#if 0
sl@0
   762
  printf ("Loading arcs and blocks from .bbg file\n");
sl@0
   763
#endif
sl@0
   764
  
sl@0
   765
  n_arcs_off_tree = 0;
sl@0
   766
  n_blocks = 0;
sl@0
   767
  n_arcs = 0;
sl@0
   768
  n_functions = 0;
sl@0
   769
  i = 0;
sl@0
   770
  while (i < _dbus_string_get_length (contents))
sl@0
   771
    {
sl@0
   772
      Function *func;
sl@0
   773
      long n_blocks_in_func;
sl@0
   774
      long n_arcs_in_func; 
sl@0
   775
      int j;
sl@0
   776
sl@0
   777
#ifdef DBUS_HAVE_GCC33_GCOV
sl@0
   778
      DBusString funcname;
sl@0
   779
      int checksum;
sl@0
   780
sl@0
   781
      /* In gcc33 .bbg files, there's a function name of the form:
sl@0
   782
       *   -1, length, name (padded to 4), -1, checksum
sl@0
   783
       * after that header on each function description, it's
sl@0
   784
       * the same as in gcc32
sl@0
   785
       */
sl@0
   786
      if (!_dbus_string_init (&funcname))
sl@0
   787
        die ("no memory\n");
sl@0
   788
      
sl@0
   789
      if (!string_get_function (contents, i,
sl@0
   790
                                &funcname, &checksum, &i))
sl@0
   791
        die ("could not read function name\n");
sl@0
   792
#endif /* DBUS_HAVE_GCC33_GCOV */
sl@0
   793
sl@0
   794
      if (!string_get_int (contents, i, &val))
sl@0
   795
        break;
sl@0
   796
      
sl@0
   797
      n_blocks_in_func = val;
sl@0
   798
      
sl@0
   799
      i += 4;
sl@0
   800
sl@0
   801
      if (!string_get_int (contents, i, &n_arcs_in_func))
sl@0
   802
        break;
sl@0
   803
sl@0
   804
      i += 4;
sl@0
   805
sl@0
   806
      n_functions += 1;
sl@0
   807
      n_blocks += n_blocks_in_func;
sl@0
   808
      n_arcs += n_arcs_in_func;
sl@0
   809
sl@0
   810
      func = dbus_new0 (Function, 1);
sl@0
   811
      if (func == NULL)
sl@0
   812
        die ("no memory\n");
sl@0
   813
sl@0
   814
#ifdef DBUS_HAVE_GCC33_GCOV
sl@0
   815
      func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
sl@0
   816
      func->checksum = checksum;
sl@0
   817
      _dbus_string_free (&funcname);
sl@0
   818
#endif
sl@0
   819
      
sl@0
   820
      func->block_graph = dbus_new0 (Block, n_blocks_in_func);
sl@0
   821
      func->n_blocks = n_blocks_in_func;
sl@0
   822
      
sl@0
   823
      j = 0;
sl@0
   824
      while (j < n_blocks_in_func)
sl@0
   825
        {
sl@0
   826
          long n_arcs_in_block;
sl@0
   827
          int k;
sl@0
   828
          
sl@0
   829
          if (!string_get_int (contents, i, &n_arcs_in_block))
sl@0
   830
            break;
sl@0
   831
sl@0
   832
          i += 4;
sl@0
   833
          
sl@0
   834
          k = 0;
sl@0
   835
          while (k < n_arcs_in_block)
sl@0
   836
            {
sl@0
   837
              long destination_block;
sl@0
   838
              long flags;
sl@0
   839
              
sl@0
   840
              if (!string_get_int (contents, i, &destination_block))
sl@0
   841
                break;
sl@0
   842
sl@0
   843
              i += 4;
sl@0
   844
              
sl@0
   845
              if (!string_get_int (contents, i, &flags))
sl@0
   846
                break;
sl@0
   847
sl@0
   848
              i += 4;
sl@0
   849
sl@0
   850
              if ((flags & FLAG_ON_TREE) == 0)
sl@0
   851
                n_arcs_off_tree += 1;
sl@0
   852
sl@0
   853
              function_add_arc (func, j, destination_block,
sl@0
   854
                                flags);
sl@0
   855
              
sl@0
   856
              ++k;
sl@0
   857
            }
sl@0
   858
sl@0
   859
          if (k < n_arcs_in_block)
sl@0
   860
            break;
sl@0
   861
          
sl@0
   862
          ++j;
sl@0
   863
        }
sl@0
   864
sl@0
   865
      if (j < n_blocks_in_func)
sl@0
   866
        break;
sl@0
   867
sl@0
   868
      function_reverse_succ_arcs (func);
sl@0
   869
      
sl@0
   870
      if (!_dbus_list_append (functions, func))
sl@0
   871
        die ("no memory\n");
sl@0
   872
      
sl@0
   873
      if (!string_get_int (contents, i, &val))
sl@0
   874
        break;
sl@0
   875
sl@0
   876
      i += 4;
sl@0
   877
sl@0
   878
      if (val != -1)
sl@0
   879
        die ("-1 separator not found in .bbg file\n");
sl@0
   880
    }
sl@0
   881
sl@0
   882
#if 0
sl@0
   883
  printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
sl@0
   884
          n_functions, n_blocks, n_arcs, n_arcs_off_tree);
sl@0
   885
#endif
sl@0
   886
  
sl@0
   887
  _dbus_assert (n_functions == _dbus_list_get_length (functions));
sl@0
   888
}
sl@0
   889
sl@0
   890
#ifdef DBUS_HAVE_GCC33_GCOV
sl@0
   891
static void
sl@0
   892
add_counts_from_da (const DBusString  *contents,
sl@0
   893
                    DBusList         **functions)
sl@0
   894
{
sl@0
   895
  int i;
sl@0
   896
  dbus_int64_t v64;
sl@0
   897
  long val;
sl@0
   898
  int n_sections;
sl@0
   899
  DBusList *link;
sl@0
   900
  Function *current_func;  
sl@0
   901
  int current_block;
sl@0
   902
  Arc *current_arc;
sl@0
   903
sl@0
   904
  n_sections = 0;
sl@0
   905
sl@0
   906
  i = 0;
sl@0
   907
  while (i < _dbus_string_get_length (contents))
sl@0
   908
    {
sl@0
   909
      int claimed_n_functions;
sl@0
   910
      int n_functions;
sl@0
   911
      
sl@0
   912
      if (!string_get_int (contents, i, &val))
sl@0
   913
        die ("no magic found in .da file\n");
sl@0
   914
sl@0
   915
      i += 4;
sl@0
   916
sl@0
   917
      if (val != -123)
sl@0
   918
        die ("wrong file magic in .da file\n");
sl@0
   919
sl@0
   920
      if (!string_get_int (contents, i, &val))
sl@0
   921
        die ("no function count in .da file\n");
sl@0
   922
      i += 4;
sl@0
   923
      claimed_n_functions = val;
sl@0
   924
      
sl@0
   925
      if (!string_get_int (contents, i, &val))
sl@0
   926
        die ("no extra data length in .da file\n");
sl@0
   927
sl@0
   928
      i += 4;
sl@0
   929
sl@0
   930
      i += val;
sl@0
   931
sl@0
   932
      link = _dbus_list_get_first_link (functions);
sl@0
   933
      if (link == NULL)
sl@0
   934
        goto no_more_functions;
sl@0
   935
      
sl@0
   936
      n_functions = 0;
sl@0
   937
      while (n_functions < claimed_n_functions && link != NULL)
sl@0
   938
        {
sl@0
   939
          DBusString funcname;
sl@0
   940
          int checksum;
sl@0
   941
          int claimed_n_arcs;
sl@0
   942
          int n_arcs;
sl@0
   943
sl@0
   944
          current_func = link->data;
sl@0
   945
          current_block = 0;
sl@0
   946
          current_arc = current_func->block_graph[current_block].succ;
sl@0
   947
          
sl@0
   948
          if (!_dbus_string_init (&funcname))
sl@0
   949
            die ("no memory\n");
sl@0
   950
          
sl@0
   951
          if (!string_get_function (contents, i,
sl@0
   952
                                    &funcname, &checksum, &i))
sl@0
   953
            die ("could not read function name\n");
sl@0
   954
sl@0
   955
          if (!_dbus_string_equal_c_str (&funcname, current_func->name))
sl@0
   956
            {
sl@0
   957
              fprintf (stderr, "Expecting .da info for %s but got %s\n",
sl@0
   958
                       current_func->name,
sl@0
   959
                       _dbus_string_get_const_data (&funcname));
sl@0
   960
              exit (1);
sl@0
   961
            }
sl@0
   962
          
sl@0
   963
          if (checksum != current_func->checksum)
sl@0
   964
            die (".da file checksum doesn't match checksum from .bbg file\n");
sl@0
   965
          
sl@0
   966
          if (!string_get_int (contents, i, &val))
sl@0
   967
            die ("no arc count for function\n");
sl@0
   968
          
sl@0
   969
          i += 4;
sl@0
   970
          claimed_n_arcs = val;
sl@0
   971
sl@0
   972
          /* For each arc in the profile, find the corresponding
sl@0
   973
           * arc in the function and increment its count
sl@0
   974
           */
sl@0
   975
          n_arcs = 0;
sl@0
   976
          while (n_arcs < claimed_n_arcs)
sl@0
   977
            {
sl@0
   978
              if (!string_get_int64 (contents, i, &v64))
sl@0
   979
                die ("did not get execution count for arc\n");
sl@0
   980
              
sl@0
   981
              i += 8;
sl@0
   982
sl@0
   983
              /* Find the next arc in the function that isn't on tree */
sl@0
   984
              while (current_arc == NULL ||
sl@0
   985
                     current_arc->on_tree)
sl@0
   986
                {
sl@0
   987
                  if (current_arc == NULL)
sl@0
   988
                    {
sl@0
   989
                      ++current_block;
sl@0
   990
              
sl@0
   991
                      if (current_block >= current_func->n_blocks)
sl@0
   992
                        die ("too many blocks in function\n");
sl@0
   993
              
sl@0
   994
                      current_arc = current_func->block_graph[current_block].succ;
sl@0
   995
                    }
sl@0
   996
                  else
sl@0
   997
                    {
sl@0
   998
                      current_arc = current_arc->succ_next;
sl@0
   999
                    }
sl@0
  1000
                }
sl@0
  1001
              
sl@0
  1002
              _dbus_assert (current_arc != NULL);
sl@0
  1003
              _dbus_assert (!current_arc->on_tree);
sl@0
  1004
              
sl@0
  1005
              current_arc->arc_count = v64;
sl@0
  1006
              current_arc->count_valid = TRUE;
sl@0
  1007
              current_func->block_graph[current_block].succ_count -= 1;
sl@0
  1008
              current_func->block_graph[current_arc->target].pred_count -= 1;
sl@0
  1009
              
sl@0
  1010
              ++n_arcs;
sl@0
  1011
              
sl@0
  1012
              current_arc = current_arc->succ_next;
sl@0
  1013
            }
sl@0
  1014
sl@0
  1015
          _dbus_string_free (&funcname);
sl@0
  1016
sl@0
  1017
          link = _dbus_list_get_next_link (functions, link);
sl@0
  1018
          ++n_functions;
sl@0
  1019
sl@0
  1020
          if (link == NULL && n_functions < claimed_n_functions)
sl@0
  1021
            {
sl@0
  1022
              fprintf (stderr, "Ran out of functions loading .da file\n");
sl@0
  1023
              goto no_more_functions;
sl@0
  1024
            }
sl@0
  1025
        }
sl@0
  1026
sl@0
  1027
    no_more_functions:
sl@0
  1028
      
sl@0
  1029
      ++n_sections;
sl@0
  1030
    }
sl@0
  1031
}
sl@0
  1032
#else /* DBUS_HAVE_GCC33_GCOV */
sl@0
  1033
static void
sl@0
  1034
add_counts_from_da (const DBusString  *contents,
sl@0
  1035
                    DBusList         **functions)
sl@0
  1036
{
sl@0
  1037
  int i;
sl@0
  1038
  dbus_int64_t val;
sl@0
  1039
  int n_arcs;
sl@0
  1040
  int claimed_n_arcs;
sl@0
  1041
  DBusList *link;
sl@0
  1042
  Function *current_func;  
sl@0
  1043
  int current_block;
sl@0
  1044
  Arc *current_arc;
sl@0
  1045
sl@0
  1046
#if 0
sl@0
  1047
  printf ("Loading execution count for each arc from .da file\n");
sl@0
  1048
#endif
sl@0
  1049
  
sl@0
  1050
  i = 0;
sl@0
  1051
  if (!string_get_int64 (contents, i, &val))
sl@0
  1052
    return;
sl@0
  1053
sl@0
  1054
  i += 8;
sl@0
  1055
  
sl@0
  1056
  claimed_n_arcs = val;
sl@0
  1057
sl@0
  1058
  link = _dbus_list_get_first_link (functions);
sl@0
  1059
  if (link == NULL)
sl@0
  1060
    goto done;
sl@0
  1061
sl@0
  1062
  current_func = link->data;
sl@0
  1063
  current_block = 0;
sl@0
  1064
  current_arc = current_func->block_graph[current_block].succ;
sl@0
  1065
  
sl@0
  1066
  n_arcs = 0;
sl@0
  1067
  while (string_get_int64 (contents, i, &val))
sl@0
  1068
    {
sl@0
  1069
      i += 8;
sl@0
  1070
sl@0
  1071
      while (current_arc == NULL ||
sl@0
  1072
             current_arc->on_tree)
sl@0
  1073
        {
sl@0
  1074
          if (current_arc == NULL)
sl@0
  1075
            {
sl@0
  1076
              ++current_block;
sl@0
  1077
              
sl@0
  1078
              if (current_block == current_func->n_blocks)
sl@0
  1079
                {
sl@0
  1080
                  link = _dbus_list_get_next_link (functions, link);
sl@0
  1081
                  if (link == NULL)
sl@0
  1082
                    {
sl@0
  1083
                      fprintf (stderr, "Ran out of functions loading .da file\n");
sl@0
  1084
                      goto done;
sl@0
  1085
                    }
sl@0
  1086
                  current_func = link->data;
sl@0
  1087
                  current_block = 0;
sl@0
  1088
                }
sl@0
  1089
              
sl@0
  1090
              current_arc = current_func->block_graph[current_block].succ;
sl@0
  1091
            }
sl@0
  1092
          else
sl@0
  1093
            {
sl@0
  1094
              current_arc = current_arc->succ_next;
sl@0
  1095
            }
sl@0
  1096
        }
sl@0
  1097
sl@0
  1098
      _dbus_assert (current_arc != NULL);
sl@0
  1099
      _dbus_assert (!current_arc->on_tree);
sl@0
  1100
sl@0
  1101
      current_arc->arc_count = val;
sl@0
  1102
      current_arc->count_valid = TRUE;
sl@0
  1103
      current_func->block_graph[current_block].succ_count -= 1;
sl@0
  1104
      current_func->block_graph[current_arc->target].pred_count -= 1;
sl@0
  1105
      
sl@0
  1106
      ++n_arcs;
sl@0
  1107
sl@0
  1108
      current_arc = current_arc->succ_next;
sl@0
  1109
    }
sl@0
  1110
sl@0
  1111
 done:
sl@0
  1112
  
sl@0
  1113
  if (n_arcs != claimed_n_arcs)
sl@0
  1114
    {
sl@0
  1115
      fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
sl@0
  1116
               claimed_n_arcs, n_arcs);
sl@0
  1117
      exit (1);
sl@0
  1118
    }
sl@0
  1119
sl@0
  1120
#if 0
sl@0
  1121
  printf ("%d arcs in file\n", n_arcs);
sl@0
  1122
#endif
sl@0
  1123
}
sl@0
  1124
#endif
sl@0
  1125
sl@0
  1126
static void
sl@0
  1127
function_solve_graph (Function *func)
sl@0
  1128
{
sl@0
  1129
  int passes, changes;
sl@0
  1130
  dbus_int64_t total;
sl@0
  1131
  int i;
sl@0
  1132
  Arc *arc;
sl@0
  1133
  Block *block_graph;
sl@0
  1134
  int n_blocks;
sl@0
  1135
sl@0
  1136
#if 0
sl@0
  1137
  printf ("Solving function graph\n");
sl@0
  1138
#endif
sl@0
  1139
  
sl@0
  1140
  n_blocks = func->n_blocks;
sl@0
  1141
  block_graph = func->block_graph;
sl@0
  1142
sl@0
  1143
  /* For every block in the file,
sl@0
  1144
     - if every exit/entrance arc has a known count, then set the block count
sl@0
  1145
     - if the block count is known, and every exit/entrance arc but one has
sl@0
  1146
     a known execution count, then set the count of the remaining arc
sl@0
  1147
sl@0
  1148
     As arc counts are set, decrement the succ/pred count, but don't delete
sl@0
  1149
     the arc, that way we can easily tell when all arcs are known, or only
sl@0
  1150
     one arc is unknown.  */
sl@0
  1151
sl@0
  1152
  /* The order that the basic blocks are iterated through is important.
sl@0
  1153
     Since the code that finds spanning trees starts with block 0, low numbered
sl@0
  1154
     arcs are put on the spanning tree in preference to high numbered arcs.
sl@0
  1155
     Hence, most instrumented arcs are at the end.  Graph solving works much
sl@0
  1156
     faster if we propagate numbers from the end to the start.
sl@0
  1157
sl@0
  1158
     This takes an average of slightly more than 3 passes.  */
sl@0
  1159
sl@0
  1160
  changes = 1;
sl@0
  1161
  passes = 0;
sl@0
  1162
  while (changes)
sl@0
  1163
    {
sl@0
  1164
      passes++;
sl@0
  1165
      changes = 0;
sl@0
  1166
sl@0
  1167
      for (i = n_blocks - 1; i >= 0; i--)
sl@0
  1168
	{
sl@0
  1169
	  if (! block_graph[i].count_valid)
sl@0
  1170
	    {
sl@0
  1171
	      if (block_graph[i].succ_count == 0)
sl@0
  1172
		{
sl@0
  1173
		  total = 0;
sl@0
  1174
		  for (arc = block_graph[i].succ; arc;
sl@0
  1175
		       arc = arc->succ_next)
sl@0
  1176
		    total += arc->arc_count;
sl@0
  1177
		  block_graph[i].exec_count = total;
sl@0
  1178
		  block_graph[i].count_valid = 1;
sl@0
  1179
		  changes = 1;
sl@0
  1180
		}
sl@0
  1181
	      else if (block_graph[i].pred_count == 0)
sl@0
  1182
		{
sl@0
  1183
		  total = 0;
sl@0
  1184
		  for (arc = block_graph[i].pred; arc;
sl@0
  1185
		       arc = arc->pred_next)
sl@0
  1186
		    total += arc->arc_count;
sl@0
  1187
		  block_graph[i].exec_count = total;
sl@0
  1188
		  block_graph[i].count_valid = 1;
sl@0
  1189
		  changes = 1;
sl@0
  1190
		}
sl@0
  1191
	    }
sl@0
  1192
	  if (block_graph[i].count_valid)
sl@0
  1193
	    {
sl@0
  1194
	      if (block_graph[i].succ_count == 1)
sl@0
  1195
		{
sl@0
  1196
		  total = 0;
sl@0
  1197
		  /* One of the counts will be invalid, but it is zero,
sl@0
  1198
		     so adding it in also doesn't hurt.  */
sl@0
  1199
		  for (arc = block_graph[i].succ; arc;
sl@0
  1200
		       arc = arc->succ_next)
sl@0
  1201
		    total += arc->arc_count;
sl@0
  1202
		  /* Calculate count for remaining arc by conservation.  */
sl@0
  1203
		  total = block_graph[i].exec_count - total;
sl@0
  1204
		  /* Search for the invalid arc, and set its count.  */
sl@0
  1205
		  for (arc = block_graph[i].succ; arc;
sl@0
  1206
		       arc = arc->succ_next)
sl@0
  1207
		    if (! arc->count_valid)
sl@0
  1208
		      break;
sl@0
  1209
		  if (! arc)
sl@0
  1210
		    die ("arc == NULL\n");
sl@0
  1211
		  arc->count_valid = 1;
sl@0
  1212
		  arc->arc_count = total;
sl@0
  1213
		  block_graph[i].succ_count -= 1;
sl@0
  1214
sl@0
  1215
		  block_graph[arc->target].pred_count -= 1;
sl@0
  1216
		  changes = 1;
sl@0
  1217
		}
sl@0
  1218
	      if (block_graph[i].pred_count == 1)
sl@0
  1219
		{
sl@0
  1220
		  total = 0;
sl@0
  1221
		  /* One of the counts will be invalid, but it is zero,
sl@0
  1222
		     so adding it in also doesn't hurt.  */
sl@0
  1223
		  for (arc = block_graph[i].pred; arc;
sl@0
  1224
		       arc = arc->pred_next)
sl@0
  1225
		    total += arc->arc_count;
sl@0
  1226
		  /* Calculate count for remaining arc by conservation.  */
sl@0
  1227
		  total = block_graph[i].exec_count - total;
sl@0
  1228
		  /* Search for the invalid arc, and set its count.  */
sl@0
  1229
		  for (arc = block_graph[i].pred; arc;
sl@0
  1230
		       arc = arc->pred_next)
sl@0
  1231
		    if (! arc->count_valid)
sl@0
  1232
		      break;
sl@0
  1233
		  if (! arc)
sl@0
  1234
                    die ("arc == NULL\n");
sl@0
  1235
		  arc->count_valid = 1;
sl@0
  1236
		  arc->arc_count = total;
sl@0
  1237
		  block_graph[i].pred_count -= 1;
sl@0
  1238
sl@0
  1239
		  block_graph[arc->source].succ_count -= 1;
sl@0
  1240
		  changes = 1;
sl@0
  1241
		}
sl@0
  1242
	    }
sl@0
  1243
	}
sl@0
  1244
    }
sl@0
  1245
sl@0
  1246
  /* If the graph has been correctly solved, every block will have a
sl@0
  1247
   * succ and pred count of zero.
sl@0
  1248
   */
sl@0
  1249
  {
sl@0
  1250
    dbus_bool_t header = FALSE;
sl@0
  1251
    for (i = 0; i < n_blocks; i++)
sl@0
  1252
      {
sl@0
  1253
        if (block_graph[i].succ_count || block_graph[i].pred_count)
sl@0
  1254
          {
sl@0
  1255
            if (!header)
sl@0
  1256
              {
sl@0
  1257
                fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
sl@0
  1258
                         func->name);
sl@0
  1259
                fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
sl@0
  1260
                header = TRUE;
sl@0
  1261
              }
sl@0
  1262
            fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
sl@0
  1263
                     i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
sl@0
  1264
          }
sl@0
  1265
      }
sl@0
  1266
  }
sl@0
  1267
}
sl@0
  1268
sl@0
  1269
static void
sl@0
  1270
solve_graphs (DBusList **functions)
sl@0
  1271
{
sl@0
  1272
  DBusList *link;
sl@0
  1273
sl@0
  1274
  link = _dbus_list_get_first_link (functions);
sl@0
  1275
  while (link != NULL)
sl@0
  1276
    {
sl@0
  1277
      Function *func = link->data;
sl@0
  1278
sl@0
  1279
      function_solve_graph (func);
sl@0
  1280
      
sl@0
  1281
      link = _dbus_list_get_next_link (functions, link);
sl@0
  1282
    }
sl@0
  1283
}
sl@0
  1284
sl@0
  1285
static void
sl@0
  1286
load_functions_for_c_file (const DBusString *filename,
sl@0
  1287
                           DBusList        **functions)
sl@0
  1288
{
sl@0
  1289
  DBusString bbg_filename;
sl@0
  1290
  DBusString da_filename;
sl@0
  1291
  DBusString gcno_filename;
sl@0
  1292
  DBusString gcda_filename;
sl@0
  1293
  DBusString contents;
sl@0
  1294
  DBusString *name;
sl@0
  1295
  DBusError error;
sl@0
  1296
sl@0
  1297
  /* With latest gcc it's .gcno instead of .bbg and
sl@0
  1298
   * gcda instead of .da
sl@0
  1299
   */
sl@0
  1300
  
sl@0
  1301
  dbus_error_init (&error);
sl@0
  1302
  
sl@0
  1303
  if (!_dbus_string_init (&bbg_filename) ||
sl@0
  1304
      !_dbus_string_init (&da_filename) ||
sl@0
  1305
      !_dbus_string_init (&gcno_filename) ||
sl@0
  1306
      !_dbus_string_init (&gcda_filename) ||
sl@0
  1307
      !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
sl@0
  1308
      !_dbus_string_copy (filename, 0, &da_filename, 0) ||
sl@0
  1309
      !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
sl@0
  1310
      !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
sl@0
  1311
      !_dbus_string_init (&contents))
sl@0
  1312
    die ("no memory\n");
sl@0
  1313
sl@0
  1314
  _dbus_string_shorten (&bbg_filename, 2);
sl@0
  1315
  _dbus_string_shorten (&da_filename, 2);
sl@0
  1316
sl@0
  1317
  if (!_dbus_string_append (&bbg_filename, ".bbg") ||
sl@0
  1318
      !_dbus_string_append (&da_filename, ".da") ||
sl@0
  1319
      !_dbus_string_append (&bbg_filename, ".gcno") ||
sl@0
  1320
      !_dbus_string_append (&bbg_filename, ".gcda"))
sl@0
  1321
    die ("no memory\n");
sl@0
  1322
sl@0
  1323
  if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
sl@0
  1324
    name = &gcno_filename;
sl@0
  1325
  else
sl@0
  1326
    name = &bbg_filename;
sl@0
  1327
  
sl@0
  1328
  if (!_dbus_file_get_contents (&contents, name,
sl@0
  1329
                                &error))
sl@0
  1330
    {
sl@0
  1331
      fprintf (stderr, "Could not open file: %s\n",
sl@0
  1332
               error.message);
sl@0
  1333
      exit (1);
sl@0
  1334
    }
sl@0
  1335
sl@0
  1336
  get_functions_from_bbg (&contents, functions);
sl@0
  1337
sl@0
  1338
  _dbus_string_set_length (&contents, 0);
sl@0
  1339
sl@0
  1340
  if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
sl@0
  1341
    name = &gcda_filename;
sl@0
  1342
  else
sl@0
  1343
    name = &da_filename;
sl@0
  1344
  
sl@0
  1345
  if (!_dbus_file_get_contents (&contents, name,
sl@0
  1346
                                &error))
sl@0
  1347
    {
sl@0
  1348
      /* Try .libs/file.da */
sl@0
  1349
      int slash;
sl@0
  1350
sl@0
  1351
      if (_dbus_string_find_byte_backward (name,
sl@0
  1352
                                           _dbus_string_get_length (name),
sl@0
  1353
                                           '/',
sl@0
  1354
                                           &slash))
sl@0
  1355
        {
sl@0
  1356
          DBusString libs;
sl@0
  1357
          _dbus_string_init_const (&libs, "/.libs");
sl@0
  1358
sl@0
  1359
          if (!_dbus_string_copy (&libs, 0, name, slash))
sl@0
  1360
            die ("no memory");
sl@0
  1361
sl@0
  1362
          dbus_error_free (&error);
sl@0
  1363
          if (!_dbus_file_get_contents (&contents, name,
sl@0
  1364
                                        &error))
sl@0
  1365
            {
sl@0
  1366
              fprintf (stderr, "Could not open file: %s\n",
sl@0
  1367
                       error.message);
sl@0
  1368
              exit (1);
sl@0
  1369
            }
sl@0
  1370
        }
sl@0
  1371
      else
sl@0
  1372
        {
sl@0
  1373
          fprintf (stderr, "Could not open file: %s\n",
sl@0
  1374
                   error.message);
sl@0
  1375
          exit (1);
sl@0
  1376
        }
sl@0
  1377
    }
sl@0
  1378
  
sl@0
  1379
  add_counts_from_da (&contents, functions);
sl@0
  1380
  
sl@0
  1381
  solve_graphs (functions);
sl@0
  1382
sl@0
  1383
  _dbus_string_free (&contents);
sl@0
  1384
  _dbus_string_free (&da_filename);
sl@0
  1385
  _dbus_string_free (&bbg_filename);
sl@0
  1386
}
sl@0
  1387
sl@0
  1388
static void
sl@0
  1389
get_lines_from_bb_file (const DBusString *contents,
sl@0
  1390
                        File             *fl)
sl@0
  1391
{
sl@0
  1392
  int i;
sl@0
  1393
  long val;
sl@0
  1394
  int n_functions;
sl@0
  1395
  dbus_bool_t in_our_file;
sl@0
  1396
  DBusList *link;
sl@0
  1397
  Function *func;
sl@0
  1398
  int block;
sl@0
  1399
sl@0
  1400
#if 0
sl@0
  1401
  printf ("Getting line numbers for blocks from .bb file\n");
sl@0
  1402
#endif
sl@0
  1403
  
sl@0
  1404
  /* There's this "filename" field in the .bb file which
sl@0
  1405
   * mysteriously comes *after* the first function in the
sl@0
  1406
   * file in the .bb file; and every .bb file seems to
sl@0
  1407
   * have only one filename. I don't understand
sl@0
  1408
   * what's going on here, so just set in_our_file = TRUE
sl@0
  1409
   * at the start categorically.
sl@0
  1410
   */
sl@0
  1411
  
sl@0
  1412
  block = 0;
sl@0
  1413
  func = NULL;
sl@0
  1414
  in_our_file = TRUE;
sl@0
  1415
  link = _dbus_list_get_first_link (&fl->functions);
sl@0
  1416
  n_functions = 0;
sl@0
  1417
  i = 0;
sl@0
  1418
  while (string_get_int (contents, i, &val))
sl@0
  1419
    {
sl@0
  1420
      i += 4;
sl@0
  1421
      
sl@0
  1422
      switch (val)
sl@0
  1423
        {
sl@0
  1424
        case BB_FILENAME:
sl@0
  1425
          {
sl@0
  1426
            DBusString f;
sl@0
  1427
sl@0
  1428
            if (!_dbus_string_init (&f))
sl@0
  1429
              die ("no memory\n");
sl@0
  1430
sl@0
  1431
            if (string_get_string (contents, i,
sl@0
  1432
                                   BB_FILENAME,
sl@0
  1433
                                   &f, &i))
sl@0
  1434
              {
sl@0
  1435
                /* fl->name is a full path and the filename in .bb is
sl@0
  1436
                 * not.
sl@0
  1437
                 */
sl@0
  1438
                DBusString tmp_str;
sl@0
  1439
sl@0
  1440
                _dbus_string_init_const (&tmp_str, fl->name);
sl@0
  1441
                
sl@0
  1442
                if (_dbus_string_ends_with_c_str (&tmp_str,
sl@0
  1443
                                                  _dbus_string_get_const_data (&f)))
sl@0
  1444
                  in_our_file = TRUE;
sl@0
  1445
                else
sl@0
  1446
                  in_our_file = FALSE;
sl@0
  1447
                
sl@0
  1448
#if 0
sl@0
  1449
                fprintf (stderr,
sl@0
  1450
                         "File %s in .bb, looking for %s, in_our_file = %d\n",
sl@0
  1451
                         _dbus_string_get_const_data (&f),
sl@0
  1452
                         fl->name,
sl@0
  1453
                         in_our_file);
sl@0
  1454
#endif
sl@0
  1455
              }
sl@0
  1456
            _dbus_string_free (&f);
sl@0
  1457
          }
sl@0
  1458
          break;
sl@0
  1459
        case BB_FUNCTION:
sl@0
  1460
          {
sl@0
  1461
            DBusString f;
sl@0
  1462
            if (!_dbus_string_init (&f))
sl@0
  1463
              die ("no memory\n");
sl@0
  1464
sl@0
  1465
            if (string_get_string (contents, i,
sl@0
  1466
                                   BB_FUNCTION,
sl@0
  1467
                                   &f, &i))
sl@0
  1468
              {
sl@0
  1469
#if 0
sl@0
  1470
                fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
sl@0
  1471
#endif
sl@0
  1472
sl@0
  1473
                block = 0;
sl@0
  1474
                
sl@0
  1475
                if (in_our_file)
sl@0
  1476
                  {
sl@0
  1477
                    if (link == NULL)
sl@0
  1478
                      {
sl@0
  1479
                        fprintf (stderr, "No function object for function %s\n",
sl@0
  1480
                                 _dbus_string_get_const_data (&f));
sl@0
  1481
                      }
sl@0
  1482
                    else
sl@0
  1483
                      {
sl@0
  1484
                        func = link->data;
sl@0
  1485
                        link = _dbus_list_get_next_link (&fl->functions, link);
sl@0
  1486
sl@0
  1487
                        if (func->name == NULL)
sl@0
  1488
                          {
sl@0
  1489
                            if (!_dbus_string_copy_data (&f, &func->name))
sl@0
  1490
                              die ("no memory\n");
sl@0
  1491
                          }
sl@0
  1492
                        else
sl@0
  1493
                          {
sl@0
  1494
                            if (!_dbus_string_equal_c_str (&f, func->name))
sl@0
  1495
                              {
sl@0
  1496
                                fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
sl@0
  1497
                                         func->name, strlen (func->name),
sl@0
  1498
                                         _dbus_string_get_const_data (&f),
sl@0
  1499
                                         _dbus_string_get_length (&f));
sl@0
  1500
sl@0
  1501
                              }
sl@0
  1502
                          }
sl@0
  1503
                      }
sl@0
  1504
                  }
sl@0
  1505
              }
sl@0
  1506
            _dbus_string_free (&f);
sl@0
  1507
sl@0
  1508
            n_functions += 1;
sl@0
  1509
          }
sl@0
  1510
          break;
sl@0
  1511
        case BB_ENDOFLIST:
sl@0
  1512
          block += 1;
sl@0
  1513
          break;
sl@0
  1514
        default:
sl@0
  1515
#if 0
sl@0
  1516
          fprintf (stderr, "Line %ld\n", val);
sl@0
  1517
#endif
sl@0
  1518
sl@0
  1519
          if (val >= fl->n_lines)
sl@0
  1520
            {
sl@0
  1521
              fprintf (stderr, "Line %ld but file only has %d lines\n",
sl@0
  1522
                       val, fl->n_lines);
sl@0
  1523
            }
sl@0
  1524
          else if (func != NULL)
sl@0
  1525
            {
sl@0
  1526
              val -= 1; /* To convert the 1-based line number to 0-based */
sl@0
  1527
              _dbus_assert (val >= 0);
sl@0
  1528
              
sl@0
  1529
              if (block < func->n_blocks)
sl@0
  1530
                {
sl@0
  1531
                  if (!_dbus_list_append (&func->block_graph[block].lines,
sl@0
  1532
                                          &fl->lines[val]))
sl@0
  1533
                    die ("no memory\n");
sl@0
  1534
                  
sl@0
  1535
                  
sl@0
  1536
                  if (!_dbus_list_append (&fl->lines[val].blocks,
sl@0
  1537
                                          &func->block_graph[block]))
sl@0
  1538
                    die ("no memory\n");
sl@0
  1539
                }
sl@0
  1540
              else
sl@0
  1541
                {
sl@0
  1542
                  fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
sl@0
  1543
                           block, func->n_blocks);
sl@0
  1544
                }
sl@0
  1545
            }
sl@0
  1546
          else
sl@0
  1547
            {
sl@0
  1548
              fprintf (stderr, "Line %ld given outside of any function\n",
sl@0
  1549
                       val);
sl@0
  1550
            }
sl@0
  1551
          
sl@0
  1552
          break;
sl@0
  1553
        }
sl@0
  1554
    }
sl@0
  1555
sl@0
  1556
#if 0
sl@0
  1557
  printf ("%d functions in file\n", n_functions);
sl@0
  1558
#endif
sl@0
  1559
}
sl@0
  1560
sl@0
  1561
sl@0
  1562
static void
sl@0
  1563
load_block_line_associations (const DBusString *filename,
sl@0
  1564
                              File             *f)
sl@0
  1565
{
sl@0
  1566
  DBusString bb_filename;
sl@0
  1567
  DBusString contents;
sl@0
  1568
  DBusError error;
sl@0
  1569
sl@0
  1570
  dbus_error_init (&error);
sl@0
  1571
  
sl@0
  1572
  if (!_dbus_string_init (&bb_filename) ||
sl@0
  1573
      !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
sl@0
  1574
      !_dbus_string_init (&contents))
sl@0
  1575
    die ("no memory\n");
sl@0
  1576
sl@0
  1577
  _dbus_string_shorten (&bb_filename, 2);
sl@0
  1578
sl@0
  1579
  if (!_dbus_string_append (&bb_filename, ".bb"))
sl@0
  1580
    die ("no memory\n");
sl@0
  1581
      
sl@0
  1582
  if (!_dbus_file_get_contents (&contents, &bb_filename,
sl@0
  1583
                                &error))
sl@0
  1584
    {
sl@0
  1585
      fprintf (stderr, "Could not open file: %s\n",
sl@0
  1586
               error.message);
sl@0
  1587
      exit (1);
sl@0
  1588
    }
sl@0
  1589
  
sl@0
  1590
  get_lines_from_bb_file (&contents, f);
sl@0
  1591
sl@0
  1592
  _dbus_string_free (&contents);
sl@0
  1593
  _dbus_string_free (&bb_filename);
sl@0
  1594
}
sl@0
  1595
sl@0
  1596
static int
sl@0
  1597
count_lines_in_string (const DBusString *str)
sl@0
  1598
{
sl@0
  1599
  int n_lines;
sl@0
  1600
  const char *p;
sl@0
  1601
  const char *prev;
sl@0
  1602
  const char *end;
sl@0
  1603
  const char *last_line_end;
sl@0
  1604
sl@0
  1605
#if 0
sl@0
  1606
  printf ("Counting lines in source file\n");
sl@0
  1607
#endif
sl@0
  1608
  
sl@0
  1609
  n_lines = 0;  
sl@0
  1610
  prev = NULL;
sl@0
  1611
  p = _dbus_string_get_const_data (str);
sl@0
  1612
  end = p + _dbus_string_get_length (str);
sl@0
  1613
  last_line_end = p;
sl@0
  1614
  while (p != end)
sl@0
  1615
    {
sl@0
  1616
      /* too lazy to handle \r\n as one linebreak */
sl@0
  1617
      if (*p == '\n' || *p == '\r')
sl@0
  1618
        {
sl@0
  1619
          ++n_lines;
sl@0
  1620
          last_line_end = p + 1;
sl@0
  1621
        }
sl@0
  1622
sl@0
  1623
      prev = p;
sl@0
  1624
      ++p;
sl@0
  1625
    }
sl@0
  1626
sl@0
  1627
  if (last_line_end != p)
sl@0
  1628
    ++n_lines;
sl@0
  1629
  
sl@0
  1630
  return n_lines;
sl@0
  1631
}
sl@0
  1632
sl@0
  1633
static void
sl@0
  1634
fill_line_content (const DBusString *str,
sl@0
  1635
                   Line             *lines)
sl@0
  1636
{
sl@0
  1637
  int n_lines;
sl@0
  1638
  const char *p;
sl@0
  1639
  const char *prev;
sl@0
  1640
  const char *end;
sl@0
  1641
  const char *last_line_end;
sl@0
  1642
sl@0
  1643
#if 0
sl@0
  1644
  printf ("Saving contents of each line in source file\n");
sl@0
  1645
#endif
sl@0
  1646
  
sl@0
  1647
  n_lines = 0;
sl@0
  1648
  prev = NULL;
sl@0
  1649
  p = _dbus_string_get_const_data (str);
sl@0
  1650
  end = p + _dbus_string_get_length (str);
sl@0
  1651
  last_line_end = p;
sl@0
  1652
  while (p != end)
sl@0
  1653
    {
sl@0
  1654
      if (*p == '\n' || *p == '\r')
sl@0
  1655
        {
sl@0
  1656
          lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
sl@0
  1657
          if (lines[n_lines].text == NULL)
sl@0
  1658
            die ("no memory\n");
sl@0
  1659
sl@0
  1660
          memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
sl@0
  1661
          lines[n_lines].number = n_lines + 1;
sl@0
  1662
          
sl@0
  1663
          ++n_lines;
sl@0
  1664
sl@0
  1665
          last_line_end = p + 1;
sl@0
  1666
        }
sl@0
  1667
sl@0
  1668
      prev = p;
sl@0
  1669
      ++p;
sl@0
  1670
    }
sl@0
  1671
sl@0
  1672
  if (p != last_line_end)
sl@0
  1673
    {
sl@0
  1674
      memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
sl@0
  1675
      ++n_lines;
sl@0
  1676
    }
sl@0
  1677
}
sl@0
  1678
sl@0
  1679
static void
sl@0
  1680
mark_inside_dbus_build_tests (File  *f)
sl@0
  1681
{
sl@0
  1682
  int i;
sl@0
  1683
  DBusList *link;
sl@0
  1684
  int inside_depth;
sl@0
  1685
sl@0
  1686
  inside_depth = 0;
sl@0
  1687
  i = 0;
sl@0
  1688
  while (i < f->n_lines)
sl@0
  1689
    {
sl@0
  1690
      Line *l = &f->lines[i];
sl@0
  1691
      dbus_bool_t is_verbose;
sl@0
  1692
sl@0
  1693
      is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
sl@0
  1694
sl@0
  1695
      if (inside_depth == 0)
sl@0
  1696
        {
sl@0
  1697
          const char *a, *b;
sl@0
  1698
          
sl@0
  1699
          a = strstr (l->text, "#if");
sl@0
  1700
          b = strstr (l->text, "DBUS_BUILD_TESTS");
sl@0
  1701
          if (a && b && (a < b))
sl@0
  1702
            inside_depth += 1;
sl@0
  1703
        }
sl@0
  1704
      else
sl@0
  1705
        {
sl@0
  1706
          if (strstr (l->text, "#if") != NULL)
sl@0
  1707
            inside_depth += 1;
sl@0
  1708
          else if (strstr (l->text, "#endif") != NULL)
sl@0
  1709
            inside_depth -= 1;
sl@0
  1710
        }
sl@0
  1711
sl@0
  1712
      if (inside_depth > 0 || is_verbose)
sl@0
  1713
        {
sl@0
  1714
          /* Mark the line and its blocks */
sl@0
  1715
          DBusList *blink;
sl@0
  1716
sl@0
  1717
          l->inside_dbus_build_tests = TRUE;
sl@0
  1718
          
sl@0
  1719
          blink = _dbus_list_get_first_link (&l->blocks);
sl@0
  1720
          while (blink != NULL)
sl@0
  1721
            {
sl@0
  1722
              Block *b = blink->data;
sl@0
  1723
sl@0
  1724
              b->inside_dbus_build_tests = TRUE;
sl@0
  1725
              
sl@0
  1726
              blink = _dbus_list_get_next_link (&l->blocks, blink);
sl@0
  1727
            }
sl@0
  1728
        }
sl@0
  1729
      
sl@0
  1730
      ++i;
sl@0
  1731
    }
sl@0
  1732
sl@0
  1733
  /* Now mark functions where for all blocks that are associated
sl@0
  1734
   * with a source line, the block is inside_dbus_build_tests.
sl@0
  1735
   */
sl@0
  1736
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  1737
  while (link != NULL)
sl@0
  1738
    {
sl@0
  1739
      Function *func = link->data;
sl@0
  1740
sl@0
  1741
      /* The issue is that some blocks aren't associated with a source line.
sl@0
  1742
       * Assume they are inside/outside tests according to the source
sl@0
  1743
       * line of the preceding block. For the first block, make it
sl@0
  1744
       * match the first following block with a line associated.
sl@0
  1745
       */
sl@0
  1746
      if (func->block_graph[0].lines == NULL)
sl@0
  1747
        {
sl@0
  1748
          /* find first following line */
sl@0
  1749
          i = 1;
sl@0
  1750
          while (i < func->n_blocks)
sl@0
  1751
            {
sl@0
  1752
              if (func->block_graph[i].lines != NULL)
sl@0
  1753
                {
sl@0
  1754
                  func->block_graph[0].inside_dbus_build_tests =
sl@0
  1755
                    func->block_graph[i].inside_dbus_build_tests;
sl@0
  1756
                  break;
sl@0
  1757
                }
sl@0
  1758
              
sl@0
  1759
              ++i;
sl@0
  1760
            }
sl@0
  1761
        }
sl@0
  1762
sl@0
  1763
      /* Now mark all blocks but the first */
sl@0
  1764
      i = 1;
sl@0
  1765
      while (i < func->n_blocks)
sl@0
  1766
        {
sl@0
  1767
          if (func->block_graph[i].lines == NULL)
sl@0
  1768
            {
sl@0
  1769
              func->block_graph[i].inside_dbus_build_tests =
sl@0
  1770
                func->block_graph[i-1].inside_dbus_build_tests;
sl@0
  1771
            }
sl@0
  1772
          
sl@0
  1773
          ++i;
sl@0
  1774
        }
sl@0
  1775
      
sl@0
  1776
      i = 0;
sl@0
  1777
      while (i < func->n_blocks)
sl@0
  1778
        {
sl@0
  1779
          /* Break as soon as any block is not a test block */
sl@0
  1780
          if (func->block_graph[i].lines != NULL &&
sl@0
  1781
              !func->block_graph[i].inside_dbus_build_tests)
sl@0
  1782
            break;
sl@0
  1783
          
sl@0
  1784
          ++i;
sl@0
  1785
        }
sl@0
  1786
sl@0
  1787
      if (i == func->n_blocks)
sl@0
  1788
        func->inside_dbus_build_tests = TRUE;
sl@0
  1789
      
sl@0
  1790
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  1791
    } 
sl@0
  1792
}
sl@0
  1793
sl@0
  1794
static void
sl@0
  1795
mark_coverage (File  *f)
sl@0
  1796
{
sl@0
  1797
  int i;
sl@0
  1798
  DBusList *link;
sl@0
  1799
  
sl@0
  1800
  i = 0;
sl@0
  1801
  while (i < f->n_lines)
sl@0
  1802
    {
sl@0
  1803
      Line *l = &f->lines[i];
sl@0
  1804
      DBusList *blink;
sl@0
  1805
      int n_blocks;
sl@0
  1806
      int n_blocks_executed;
sl@0
  1807
sl@0
  1808
      n_blocks = 0;
sl@0
  1809
      n_blocks_executed = 0;
sl@0
  1810
      blink = _dbus_list_get_first_link (&l->blocks);
sl@0
  1811
      while (blink != NULL)
sl@0
  1812
        {
sl@0
  1813
          Block *b = blink->data;
sl@0
  1814
          
sl@0
  1815
          if (b->exec_count > 0)
sl@0
  1816
            n_blocks_executed += 1;
sl@0
  1817
sl@0
  1818
          n_blocks += 1;
sl@0
  1819
          
sl@0
  1820
          blink = _dbus_list_get_next_link (&l->blocks, blink);
sl@0
  1821
        }
sl@0
  1822
sl@0
  1823
      if (n_blocks_executed > 0 &&
sl@0
  1824
          n_blocks_executed < n_blocks)
sl@0
  1825
        l->partial = TRUE;
sl@0
  1826
sl@0
  1827
      ++i;
sl@0
  1828
    }
sl@0
  1829
sl@0
  1830
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  1831
  while (link != NULL)
sl@0
  1832
    {
sl@0
  1833
      Function *func = link->data;
sl@0
  1834
      int i;
sl@0
  1835
      int n_test_blocks;
sl@0
  1836
      int n_test_blocks_executed;
sl@0
  1837
      int n_nontest_blocks;
sl@0
  1838
      int n_nontest_blocks_executed;
sl@0
  1839
      
sl@0
  1840
      n_test_blocks = 0;
sl@0
  1841
      n_test_blocks_executed = 0;
sl@0
  1842
      n_nontest_blocks = 0;
sl@0
  1843
      n_nontest_blocks_executed = 0;      
sl@0
  1844
sl@0
  1845
      i = 0;
sl@0
  1846
      while (i < func->n_blocks)
sl@0
  1847
        {
sl@0
  1848
          if (!func->block_graph[i].inside_dbus_build_tests)
sl@0
  1849
            {
sl@0
  1850
              n_nontest_blocks += 1;
sl@0
  1851
sl@0
  1852
              if (func->block_graph[i].exec_count > 0)
sl@0
  1853
                n_nontest_blocks_executed += 1;
sl@0
  1854
            }
sl@0
  1855
          else
sl@0
  1856
            {
sl@0
  1857
              n_test_blocks += 1;
sl@0
  1858
sl@0
  1859
              if (func->block_graph[i].exec_count > 0)
sl@0
  1860
                n_test_blocks_executed += 1;
sl@0
  1861
            }
sl@0
  1862
sl@0
  1863
          ++i;
sl@0
  1864
        }
sl@0
  1865
      
sl@0
  1866
      if (n_nontest_blocks_executed > 0 &&
sl@0
  1867
          n_nontest_blocks_executed < n_nontest_blocks)
sl@0
  1868
        func->partial = TRUE;
sl@0
  1869
sl@0
  1870
      if (n_nontest_blocks_executed == 0 &&
sl@0
  1871
          n_nontest_blocks > 0)
sl@0
  1872
        func->unused = TRUE;
sl@0
  1873
      
sl@0
  1874
      func->n_test_blocks = n_test_blocks;
sl@0
  1875
      func->n_test_blocks_executed = n_test_blocks_executed;
sl@0
  1876
      func->n_nontest_blocks = n_nontest_blocks;
sl@0
  1877
      func->n_nontest_blocks_executed = n_nontest_blocks_executed;
sl@0
  1878
      
sl@0
  1879
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  1880
    }
sl@0
  1881
}
sl@0
  1882
sl@0
  1883
static File*
sl@0
  1884
load_c_file (const DBusString *filename)
sl@0
  1885
{
sl@0
  1886
  DBusString contents;
sl@0
  1887
  DBusError error;
sl@0
  1888
  File *f;
sl@0
  1889
  
sl@0
  1890
  f = dbus_new0 (File, 1);
sl@0
  1891
  if (f == NULL)
sl@0
  1892
    die ("no memory\n");
sl@0
  1893
sl@0
  1894
  if (!_dbus_string_copy_data (filename, &f->name))
sl@0
  1895
    die ("no memory\n");
sl@0
  1896
  
sl@0
  1897
  if (!_dbus_string_init (&contents))
sl@0
  1898
    die ("no memory\n");
sl@0
  1899
      
sl@0
  1900
  dbus_error_init (&error);
sl@0
  1901
sl@0
  1902
  if (!_dbus_file_get_contents (&contents, filename,
sl@0
  1903
                                &error))
sl@0
  1904
    {
sl@0
  1905
      fprintf (stderr, "Could not open file: %s\n",
sl@0
  1906
               error.message);
sl@0
  1907
      dbus_error_free (&error);
sl@0
  1908
      exit (1);
sl@0
  1909
    }
sl@0
  1910
      
sl@0
  1911
  load_functions_for_c_file (filename, &f->functions);
sl@0
  1912
sl@0
  1913
  f->n_lines = count_lines_in_string (&contents);
sl@0
  1914
  f->lines = dbus_new0 (Line, f->n_lines);
sl@0
  1915
  if (f->lines == NULL)
sl@0
  1916
    die ("no memory\n");
sl@0
  1917
sl@0
  1918
  fill_line_content (&contents, f->lines);
sl@0
  1919
  
sl@0
  1920
  _dbus_string_free (&contents);
sl@0
  1921
sl@0
  1922
  load_block_line_associations (filename, f);
sl@0
  1923
sl@0
  1924
  mark_inside_dbus_build_tests (f);
sl@0
  1925
  mark_coverage (f);
sl@0
  1926
  
sl@0
  1927
  return f;
sl@0
  1928
}
sl@0
  1929
sl@0
  1930
typedef struct Stats Stats;
sl@0
  1931
sl@0
  1932
struct Stats
sl@0
  1933
{
sl@0
  1934
  int n_blocks;
sl@0
  1935
  int n_blocks_executed;
sl@0
  1936
  int n_blocks_inside_dbus_build_tests;
sl@0
  1937
  
sl@0
  1938
  int n_lines; /* lines that have blocks on them */
sl@0
  1939
  int n_lines_executed;
sl@0
  1940
  int n_lines_partial;
sl@0
  1941
  int n_lines_inside_dbus_build_tests;
sl@0
  1942
  
sl@0
  1943
  int n_functions;
sl@0
  1944
  int n_functions_executed;
sl@0
  1945
  int n_functions_partial;
sl@0
  1946
  int n_functions_inside_dbus_build_tests;
sl@0
  1947
};
sl@0
  1948
sl@0
  1949
static dbus_bool_t
sl@0
  1950
line_was_executed (Line *l)
sl@0
  1951
{
sl@0
  1952
  DBusList *link;
sl@0
  1953
sl@0
  1954
  link = _dbus_list_get_first_link (&l->blocks);
sl@0
  1955
  while (link != NULL)
sl@0
  1956
    {
sl@0
  1957
      Block *b = link->data;
sl@0
  1958
sl@0
  1959
      if (b->exec_count > 0)
sl@0
  1960
        return TRUE;
sl@0
  1961
      
sl@0
  1962
      link = _dbus_list_get_next_link (&l->blocks, link);
sl@0
  1963
    }
sl@0
  1964
sl@0
  1965
  return FALSE;
sl@0
  1966
}
sl@0
  1967
sl@0
  1968
sl@0
  1969
static int
sl@0
  1970
line_exec_count (Line *l)
sl@0
  1971
{
sl@0
  1972
  DBusList *link;
sl@0
  1973
  dbus_int64_t total;
sl@0
  1974
sl@0
  1975
  total = 0;
sl@0
  1976
  link = _dbus_list_get_first_link (&l->blocks);
sl@0
  1977
  while (link != NULL)
sl@0
  1978
    {
sl@0
  1979
      Block *b = link->data;
sl@0
  1980
sl@0
  1981
      total += b->exec_count;
sl@0
  1982
      
sl@0
  1983
      link = _dbus_list_get_next_link (&l->blocks, link);
sl@0
  1984
    }
sl@0
  1985
sl@0
  1986
  return total;
sl@0
  1987
}
sl@0
  1988
sl@0
  1989
static void
sl@0
  1990
merge_stats_for_file (Stats *stats,
sl@0
  1991
                      File  *f)
sl@0
  1992
{
sl@0
  1993
  int i;
sl@0
  1994
  DBusList *link;
sl@0
  1995
  
sl@0
  1996
  for (i = 0; i < f->n_lines; ++i)
sl@0
  1997
    {
sl@0
  1998
      Line *l = &f->lines[i];
sl@0
  1999
      
sl@0
  2000
      if (l->inside_dbus_build_tests)
sl@0
  2001
        {
sl@0
  2002
          stats->n_lines_inside_dbus_build_tests += 1;
sl@0
  2003
          continue;
sl@0
  2004
        }
sl@0
  2005
      
sl@0
  2006
      if (line_was_executed (l))
sl@0
  2007
        stats->n_lines_executed += 1;
sl@0
  2008
sl@0
  2009
      if (l->blocks != NULL)
sl@0
  2010
        stats->n_lines += 1;
sl@0
  2011
sl@0
  2012
      if (l->partial)
sl@0
  2013
        stats->n_lines_partial += 1;
sl@0
  2014
    }
sl@0
  2015
sl@0
  2016
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2017
  while (link != NULL)
sl@0
  2018
    {
sl@0
  2019
      Function *func = link->data;
sl@0
  2020
sl@0
  2021
      if (func->inside_dbus_build_tests)
sl@0
  2022
        stats->n_functions_inside_dbus_build_tests += 1;
sl@0
  2023
      else
sl@0
  2024
        {
sl@0
  2025
          stats->n_functions += 1;
sl@0
  2026
sl@0
  2027
          if (!func->unused)
sl@0
  2028
            stats->n_functions_executed += 1;
sl@0
  2029
          
sl@0
  2030
          if (func->partial)
sl@0
  2031
            stats->n_functions_partial += 1;
sl@0
  2032
        }
sl@0
  2033
sl@0
  2034
      stats->n_blocks_inside_dbus_build_tests +=
sl@0
  2035
        func->n_test_blocks;
sl@0
  2036
      
sl@0
  2037
      stats->n_blocks_executed +=
sl@0
  2038
        func->n_nontest_blocks_executed;
sl@0
  2039
      
sl@0
  2040
      stats->n_blocks +=
sl@0
  2041
        func->n_nontest_blocks;
sl@0
  2042
sl@0
  2043
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2044
    }
sl@0
  2045
}
sl@0
  2046
sl@0
  2047
/* The output of this matches gcov exactly ("diff" shows no difference) */
sl@0
  2048
static void
sl@0
  2049
print_annotated_source_gcov_format (File *f)
sl@0
  2050
{
sl@0
  2051
  int i;
sl@0
  2052
  
sl@0
  2053
  i = 0;
sl@0
  2054
  while (i < f->n_lines)
sl@0
  2055
    {
sl@0
  2056
      Line *l = &f->lines[i];
sl@0
  2057
sl@0
  2058
      if (l->blocks != NULL)
sl@0
  2059
        {
sl@0
  2060
          int exec_count;
sl@0
  2061
          
sl@0
  2062
          exec_count = line_exec_count (l);
sl@0
  2063
          
sl@0
  2064
          if (exec_count > 0)
sl@0
  2065
            printf ("%12d    %s\n",
sl@0
  2066
                    exec_count, l->text);
sl@0
  2067
          else
sl@0
  2068
            printf ("      ######    %s\n", l->text);
sl@0
  2069
        }
sl@0
  2070
      else
sl@0
  2071
        {
sl@0
  2072
          printf ("\t\t%s\n", l->text);
sl@0
  2073
        }
sl@0
  2074
          
sl@0
  2075
      ++i;
sl@0
  2076
    }
sl@0
  2077
}
sl@0
  2078
sl@0
  2079
static void
sl@0
  2080
print_annotated_source (File *f)
sl@0
  2081
{
sl@0
  2082
  int i;
sl@0
  2083
  
sl@0
  2084
  i = 0;
sl@0
  2085
  while (i < f->n_lines)
sl@0
  2086
    {
sl@0
  2087
      Line *l = &f->lines[i];
sl@0
  2088
sl@0
  2089
      if (l->inside_dbus_build_tests)
sl@0
  2090
        printf ("*");
sl@0
  2091
      else
sl@0
  2092
        printf (" ");
sl@0
  2093
      
sl@0
  2094
      if (l->blocks != NULL)
sl@0
  2095
        {
sl@0
  2096
          int exec_count;
sl@0
  2097
          
sl@0
  2098
          exec_count = line_exec_count (l);
sl@0
  2099
          
sl@0
  2100
          if (exec_count > 0)
sl@0
  2101
            printf ("%12d    %s\n",
sl@0
  2102
                    exec_count, l->text);
sl@0
  2103
          else
sl@0
  2104
            printf ("      ######    %s\n", l->text);
sl@0
  2105
        }
sl@0
  2106
      else
sl@0
  2107
        {
sl@0
  2108
          printf ("\t\t%s\n", l->text);
sl@0
  2109
        }
sl@0
  2110
          
sl@0
  2111
      ++i;
sl@0
  2112
    }
sl@0
  2113
}
sl@0
  2114
sl@0
  2115
static void
sl@0
  2116
print_block_superdetails (File *f)
sl@0
  2117
{
sl@0
  2118
  DBusList *link;
sl@0
  2119
  int i;
sl@0
  2120
  
sl@0
  2121
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2122
  while (link != NULL)
sl@0
  2123
    {
sl@0
  2124
      Function *func = link->data;
sl@0
  2125
sl@0
  2126
      printf ("=== %s():\n", func->name);
sl@0
  2127
sl@0
  2128
      i = 0;
sl@0
  2129
      while (i < func->n_blocks)
sl@0
  2130
        {
sl@0
  2131
          Block *b = &func->block_graph[i];
sl@0
  2132
          DBusList *l;
sl@0
  2133
          
sl@0
  2134
          printf ("  %5d executed %d times%s\n", i,
sl@0
  2135
                  (int) b->exec_count,
sl@0
  2136
                  b->inside_dbus_build_tests ?
sl@0
  2137
                  " [inside DBUS_BUILD_TESTS]" : "");
sl@0
  2138
                  
sl@0
  2139
          l = _dbus_list_get_first_link (&b->lines);
sl@0
  2140
          while (l != NULL)
sl@0
  2141
            {
sl@0
  2142
              Line *line = l->data;
sl@0
  2143
sl@0
  2144
              printf ("4%d\t%s\n", line->number, line->text);
sl@0
  2145
sl@0
  2146
              l = _dbus_list_get_next_link (&b->lines, l);
sl@0
  2147
            }
sl@0
  2148
          
sl@0
  2149
          ++i;
sl@0
  2150
        }
sl@0
  2151
      
sl@0
  2152
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2153
    }
sl@0
  2154
}
sl@0
  2155
sl@0
  2156
static void
sl@0
  2157
print_one_file (const DBusString *filename)
sl@0
  2158
{
sl@0
  2159
  if (_dbus_string_ends_with_c_str (filename, ".bb"))
sl@0
  2160
    {
sl@0
  2161
      DBusString contents;
sl@0
  2162
      DBusError error;
sl@0
  2163
      
sl@0
  2164
      if (!_dbus_string_init (&contents))
sl@0
  2165
        die ("no memory\n");
sl@0
  2166
      
sl@0
  2167
      dbus_error_init (&error);
sl@0
  2168
sl@0
  2169
      if (!_dbus_file_get_contents (&contents, filename,
sl@0
  2170
                                    &error))
sl@0
  2171
        {
sl@0
  2172
          fprintf (stderr, "Could not open file: %s\n",
sl@0
  2173
                   error.message);
sl@0
  2174
          dbus_error_free (&error);
sl@0
  2175
          exit (1);
sl@0
  2176
        }
sl@0
  2177
      
sl@0
  2178
      dump_bb_file (&contents);
sl@0
  2179
sl@0
  2180
      _dbus_string_free (&contents);
sl@0
  2181
    }
sl@0
  2182
  else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
sl@0
  2183
    {
sl@0
  2184
      DBusString contents;
sl@0
  2185
      DBusError error;
sl@0
  2186
      
sl@0
  2187
      if (!_dbus_string_init (&contents))
sl@0
  2188
        die ("no memory\n");
sl@0
  2189
      
sl@0
  2190
      dbus_error_init (&error);
sl@0
  2191
sl@0
  2192
      if (!_dbus_file_get_contents (&contents, filename,
sl@0
  2193
                                    &error))
sl@0
  2194
        {
sl@0
  2195
          fprintf (stderr, "Could not open file: %s\n",
sl@0
  2196
                   error.message);
sl@0
  2197
          dbus_error_free (&error);
sl@0
  2198
          exit (1);
sl@0
  2199
        }
sl@0
  2200
      
sl@0
  2201
      dump_bbg_file (&contents);
sl@0
  2202
sl@0
  2203
      _dbus_string_free (&contents);
sl@0
  2204
    }
sl@0
  2205
  else if (_dbus_string_ends_with_c_str (filename, ".da"))
sl@0
  2206
    {
sl@0
  2207
      DBusString contents;
sl@0
  2208
      DBusError error;
sl@0
  2209
      
sl@0
  2210
      if (!_dbus_string_init (&contents))
sl@0
  2211
        die ("no memory\n");
sl@0
  2212
      
sl@0
  2213
      dbus_error_init (&error);
sl@0
  2214
sl@0
  2215
      if (!_dbus_file_get_contents (&contents, filename,
sl@0
  2216
                                    &error))
sl@0
  2217
        {
sl@0
  2218
          fprintf (stderr, "Could not open file: %s\n",
sl@0
  2219
                   error.message);
sl@0
  2220
          dbus_error_free (&error);
sl@0
  2221
          exit (1);
sl@0
  2222
        }
sl@0
  2223
      
sl@0
  2224
      dump_da_file (&contents);
sl@0
  2225
sl@0
  2226
      _dbus_string_free (&contents);
sl@0
  2227
    }
sl@0
  2228
  else if (_dbus_string_ends_with_c_str (filename, ".c"))
sl@0
  2229
    {
sl@0
  2230
      File *f;
sl@0
  2231
      
sl@0
  2232
      f = load_c_file (filename);
sl@0
  2233
sl@0
  2234
      print_annotated_source (f);
sl@0
  2235
    }
sl@0
  2236
  else
sl@0
  2237
    {
sl@0
  2238
      fprintf (stderr, "Unknown file type %s\n",
sl@0
  2239
               _dbus_string_get_const_data (filename));
sl@0
  2240
      exit (1);
sl@0
  2241
    }
sl@0
  2242
}
sl@0
  2243
sl@0
  2244
static void
sl@0
  2245
print_untested_functions (File *f)
sl@0
  2246
{
sl@0
  2247
  DBusList *link;
sl@0
  2248
  dbus_bool_t found;
sl@0
  2249
sl@0
  2250
  found = FALSE;
sl@0
  2251
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2252
  while (link != NULL)
sl@0
  2253
    {
sl@0
  2254
      Function *func = link->data;
sl@0
  2255
sl@0
  2256
      if (func->unused &&
sl@0
  2257
          !func->inside_dbus_build_tests)
sl@0
  2258
        found = TRUE;
sl@0
  2259
      
sl@0
  2260
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2261
    }
sl@0
  2262
sl@0
  2263
  if (!found)
sl@0
  2264
    return;
sl@0
  2265
  
sl@0
  2266
  printf ("Untested functions in %s\n", f->name);
sl@0
  2267
  printf ("=======\n");
sl@0
  2268
  
sl@0
  2269
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2270
  while (link != NULL)
sl@0
  2271
    {
sl@0
  2272
      Function *func = link->data;
sl@0
  2273
sl@0
  2274
      if (func->unused &&
sl@0
  2275
          !func->inside_dbus_build_tests)
sl@0
  2276
        printf ("  %s\n", func->name);
sl@0
  2277
      
sl@0
  2278
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2279
    }
sl@0
  2280
sl@0
  2281
  printf ("\n");
sl@0
  2282
}
sl@0
  2283
sl@0
  2284
static void
sl@0
  2285
print_poorly_tested_functions (File  *f,
sl@0
  2286
                               Stats *stats)
sl@0
  2287
{
sl@0
  2288
  DBusList *link;
sl@0
  2289
  dbus_bool_t found;
sl@0
  2290
sl@0
  2291
#define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
sl@0
  2292
sl@0
  2293
#define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
sl@0
  2294
  
sl@0
  2295
#define POORLY_TESTED(function) (!(function)->unused &&                 \
sl@0
  2296
                                 (function)->n_nontest_blocks > 0 &&    \
sl@0
  2297
                                 TEST_FRACTION (function) < AVERAGE_COVERAGE)
sl@0
  2298
  
sl@0
  2299
  found = FALSE;
sl@0
  2300
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2301
  while (link != NULL)
sl@0
  2302
    {
sl@0
  2303
      Function *func = link->data;
sl@0
  2304
sl@0
  2305
      if (POORLY_TESTED (func))
sl@0
  2306
        found = TRUE;
sl@0
  2307
      
sl@0
  2308
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2309
    }
sl@0
  2310
sl@0
  2311
  if (!found)
sl@0
  2312
    return;
sl@0
  2313
sl@0
  2314
  printf ("Below average functions in %s\n", f->name);
sl@0
  2315
  printf ("=======\n");
sl@0
  2316
  
sl@0
  2317
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2318
  while (link != NULL)
sl@0
  2319
    {
sl@0
  2320
      Function *func = link->data;
sl@0
  2321
sl@0
  2322
      if (POORLY_TESTED (func))
sl@0
  2323
        printf ("  %s (%d%%)\n", func->name,
sl@0
  2324
                (int) (TEST_FRACTION (func) * 100));
sl@0
  2325
      
sl@0
  2326
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2327
    }
sl@0
  2328
sl@0
  2329
  printf ("\n");
sl@0
  2330
}
sl@0
  2331
sl@0
  2332
static int
sl@0
  2333
func_cmp (const void *a,
sl@0
  2334
          const void *b)
sl@0
  2335
{
sl@0
  2336
  Function *af = *(Function**) a;
sl@0
  2337
  Function *bf = *(Function**) b;
sl@0
  2338
  int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
sl@0
  2339
  int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
sl@0
  2340
  
sl@0
  2341
  /* Sort by number of untested blocks */
sl@0
  2342
  return b_untested - a_untested;
sl@0
  2343
}
sl@0
  2344
sl@0
  2345
static void
sl@0
  2346
print_n_untested_blocks_by_function (File  *f,
sl@0
  2347
                                     Stats *stats)
sl@0
  2348
{
sl@0
  2349
  DBusList *link;
sl@0
  2350
  Function **funcs;
sl@0
  2351
  int n_found;
sl@0
  2352
  int i;
sl@0
  2353
  
sl@0
  2354
  n_found = 0;
sl@0
  2355
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2356
  while (link != NULL)
sl@0
  2357
    {
sl@0
  2358
      Function *func = link->data;
sl@0
  2359
sl@0
  2360
      if (func->n_nontest_blocks_executed <
sl@0
  2361
          func->n_nontest_blocks)
sl@0
  2362
        n_found += 1;
sl@0
  2363
      
sl@0
  2364
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2365
    }
sl@0
  2366
sl@0
  2367
  if (n_found == 0)
sl@0
  2368
    return;
sl@0
  2369
sl@0
  2370
  /* make an array so we can use qsort */
sl@0
  2371
  
sl@0
  2372
  funcs = dbus_new (Function*, n_found);
sl@0
  2373
  if (funcs == NULL)
sl@0
  2374
    return;
sl@0
  2375
  
sl@0
  2376
  i = 0;
sl@0
  2377
  link = _dbus_list_get_first_link (&f->functions);
sl@0
  2378
  while (link != NULL)
sl@0
  2379
    {
sl@0
  2380
      Function *func = link->data;
sl@0
  2381
sl@0
  2382
      if (func->n_nontest_blocks_executed <
sl@0
  2383
          func->n_nontest_blocks)
sl@0
  2384
        {
sl@0
  2385
          funcs[i] = func;
sl@0
  2386
          ++i;
sl@0
  2387
        }
sl@0
  2388
sl@0
  2389
      link = _dbus_list_get_next_link (&f->functions, link);
sl@0
  2390
    }
sl@0
  2391
sl@0
  2392
  _dbus_assert (i == n_found);
sl@0
  2393
  
sl@0
  2394
  qsort (funcs, n_found, sizeof (Function*),
sl@0
  2395
         func_cmp);
sl@0
  2396
  
sl@0
  2397
  printf ("Incomplete functions in %s\n", f->name);
sl@0
  2398
  printf ("=======\n");
sl@0
  2399
sl@0
  2400
  i = 0;
sl@0
  2401
  while (i < n_found)
sl@0
  2402
    {
sl@0
  2403
      Function *func = funcs[i];
sl@0
  2404
sl@0
  2405
      printf ("  %s (%d/%d untested blocks)\n",
sl@0
  2406
              func->name,
sl@0
  2407
              func->n_nontest_blocks - func->n_nontest_blocks_executed,
sl@0
  2408
              func->n_nontest_blocks);
sl@0
  2409
      
sl@0
  2410
      ++i;
sl@0
  2411
    }
sl@0
  2412
sl@0
  2413
  dbus_free (funcs);
sl@0
  2414
sl@0
  2415
  printf ("\n");
sl@0
  2416
}
sl@0
  2417
sl@0
  2418
static void
sl@0
  2419
print_stats (Stats      *stats,
sl@0
  2420
             const char *of_what)
sl@0
  2421
{
sl@0
  2422
  int completely;
sl@0
  2423
  
sl@0
  2424
  printf ("Summary (%s)\n", of_what);
sl@0
  2425
  printf ("=======\n");
sl@0
  2426
  printf ("  %g%% blocks executed (%d of %d)\n",
sl@0
  2427
          (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
sl@0
  2428
          stats->n_blocks_executed,
sl@0
  2429
          stats->n_blocks);
sl@0
  2430
sl@0
  2431
  printf ("     (ignored %d blocks of test-only/debug-only code)\n",
sl@0
  2432
          stats->n_blocks_inside_dbus_build_tests);
sl@0
  2433
      
sl@0
  2434
  printf ("  %g%% functions executed (%d of %d)\n",
sl@0
  2435
          (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
sl@0
  2436
          stats->n_functions_executed,
sl@0
  2437
          stats->n_functions);
sl@0
  2438
sl@0
  2439
  completely = stats->n_functions_executed - stats->n_functions_partial;
sl@0
  2440
  printf ("  %g%% functions completely executed (%d of %d)\n",
sl@0
  2441
          (completely / (double) stats->n_functions) * 100.0,
sl@0
  2442
          completely,
sl@0
  2443
          stats->n_functions);
sl@0
  2444
sl@0
  2445
  printf ("     (ignored %d functions of test-only/debug-only code)\n",
sl@0
  2446
          stats->n_functions_inside_dbus_build_tests);
sl@0
  2447
      
sl@0
  2448
  printf ("  %g%% lines executed (%d of %d)\n",
sl@0
  2449
          (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
sl@0
  2450
          stats->n_lines_executed,
sl@0
  2451
          stats->n_lines);
sl@0
  2452
sl@0
  2453
  completely = stats->n_lines_executed - stats->n_lines_partial;
sl@0
  2454
  printf ("  %g%% lines completely executed (%d of %d)\n",
sl@0
  2455
          (completely / (double) stats->n_lines) * 100.0,
sl@0
  2456
          completely,
sl@0
  2457
          stats->n_lines);
sl@0
  2458
sl@0
  2459
  printf ("     (ignored %d lines of test-only/debug-only code)\n",
sl@0
  2460
          stats->n_lines_inside_dbus_build_tests);
sl@0
  2461
sl@0
  2462
  printf ("\n");
sl@0
  2463
}
sl@0
  2464
sl@0
  2465
typedef enum
sl@0
  2466
{
sl@0
  2467
  MODE_PRINT,
sl@0
  2468
  MODE_REPORT,
sl@0
  2469
  MODE_BLOCKS,
sl@0
  2470
  MODE_GCOV
sl@0
  2471
} Mode;
sl@0
  2472
sl@0
  2473
int
sl@0
  2474
main (int argc, char **argv)
sl@0
  2475
{
sl@0
  2476
  DBusString filename;
sl@0
  2477
  int i;
sl@0
  2478
  Mode m;
sl@0
  2479
  
sl@0
  2480
  if (argc < 2)
sl@0
  2481
    {
sl@0
  2482
      fprintf (stderr, "Must specify files on command line\n");
sl@0
  2483
      return 1;
sl@0
  2484
    }
sl@0
  2485
sl@0
  2486
  m = MODE_PRINT;
sl@0
  2487
  i = 1;
sl@0
  2488
sl@0
  2489
  if (strcmp (argv[i], "--report") == 0)
sl@0
  2490
    {
sl@0
  2491
      m = MODE_REPORT;
sl@0
  2492
      ++i;
sl@0
  2493
    }
sl@0
  2494
  else if (strcmp (argv[i], "--blocks") == 0)
sl@0
  2495
    {
sl@0
  2496
      m = MODE_BLOCKS;
sl@0
  2497
      ++i;
sl@0
  2498
    }
sl@0
  2499
  else if (strcmp (argv[i], "--gcov") == 0)
sl@0
  2500
    {
sl@0
  2501
      m = MODE_GCOV;
sl@0
  2502
      ++i;
sl@0
  2503
    }
sl@0
  2504
sl@0
  2505
  
sl@0
  2506
  if (i == argc)
sl@0
  2507
    {
sl@0
  2508
      fprintf (stderr, "Must specify files on command line\n");
sl@0
  2509
      return 1;
sl@0
  2510
    }
sl@0
  2511
sl@0
  2512
  if (m == MODE_PRINT)
sl@0
  2513
    {
sl@0
  2514
      while (i < argc)
sl@0
  2515
        {
sl@0
  2516
          _dbus_string_init_const (&filename, argv[i]);
sl@0
  2517
          
sl@0
  2518
          print_one_file (&filename);
sl@0
  2519
          
sl@0
  2520
          ++i;
sl@0
  2521
        }
sl@0
  2522
    }
sl@0
  2523
  else if (m == MODE_BLOCKS || m == MODE_GCOV)
sl@0
  2524
    {
sl@0
  2525
      while (i < argc)
sl@0
  2526
        {
sl@0
  2527
          File *f;
sl@0
  2528
          
sl@0
  2529
          _dbus_string_init_const (&filename, argv[i]);
sl@0
  2530
      
sl@0
  2531
          f = load_c_file (&filename);
sl@0
  2532
sl@0
  2533
          if (m == MODE_BLOCKS)
sl@0
  2534
            print_block_superdetails (f);
sl@0
  2535
          else if (m == MODE_GCOV)
sl@0
  2536
            print_annotated_source_gcov_format (f);
sl@0
  2537
          
sl@0
  2538
          ++i;
sl@0
  2539
        }
sl@0
  2540
    }
sl@0
  2541
  else if (m == MODE_REPORT)
sl@0
  2542
    {
sl@0
  2543
      Stats stats = { 0, };
sl@0
  2544
      DBusList *files;
sl@0
  2545
      DBusList *link;
sl@0
  2546
      DBusHashTable *stats_by_dir;
sl@0
  2547
      DBusHashIter iter;
sl@0
  2548
      
sl@0
  2549
      files = NULL;
sl@0
  2550
      while (i < argc)
sl@0
  2551
        {
sl@0
  2552
          _dbus_string_init_const (&filename, argv[i]);
sl@0
  2553
sl@0
  2554
          if (_dbus_string_ends_with_c_str (&filename, ".c"))
sl@0
  2555
            {
sl@0
  2556
              File *f;
sl@0
  2557
              
sl@0
  2558
              f = load_c_file (&filename);
sl@0
  2559
              
sl@0
  2560
              if (!_dbus_list_append (&files, f))
sl@0
  2561
                die ("no memory\n");
sl@0
  2562
            }
sl@0
  2563
          else
sl@0
  2564
            {
sl@0
  2565
              fprintf (stderr, "Unknown file type %s\n",
sl@0
  2566
                       _dbus_string_get_const_data (&filename));
sl@0
  2567
              exit (1);
sl@0
  2568
            }
sl@0
  2569
          
sl@0
  2570
          ++i;
sl@0
  2571
        }
sl@0
  2572
sl@0
  2573
      link = _dbus_list_get_first_link (&files);
sl@0
  2574
      while (link != NULL)
sl@0
  2575
        {
sl@0
  2576
          File *f = link->data;
sl@0
  2577
sl@0
  2578
          merge_stats_for_file (&stats, f);
sl@0
  2579
          
sl@0
  2580
          link = _dbus_list_get_next_link (&files, link);
sl@0
  2581
        }
sl@0
  2582
sl@0
  2583
      print_stats (&stats, "all files");
sl@0
  2584
sl@0
  2585
      stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
sl@0
  2586
                                           dbus_free, dbus_free);
sl@0
  2587
      
sl@0
  2588
      link = _dbus_list_get_first_link (&files);
sl@0
  2589
      while (link != NULL)
sl@0
  2590
        {
sl@0
  2591
          File *f = link->data;
sl@0
  2592
          DBusString dirname;
sl@0
  2593
          char *dirname_c;
sl@0
  2594
          Stats *dir_stats;
sl@0
  2595
          
sl@0
  2596
          _dbus_string_init_const (&filename, f->name);
sl@0
  2597
            
sl@0
  2598
          if (!_dbus_string_init (&dirname))
sl@0
  2599
            die ("no memory\n");
sl@0
  2600
sl@0
  2601
          if (!_dbus_string_get_dirname (&filename, &dirname) ||
sl@0
  2602
              !_dbus_string_copy_data (&dirname, &dirname_c))
sl@0
  2603
            die ("no memory\n");
sl@0
  2604
sl@0
  2605
          dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
sl@0
  2606
                                                      dirname_c);
sl@0
  2607
sl@0
  2608
          if (dir_stats == NULL)
sl@0
  2609
            {
sl@0
  2610
              dir_stats = dbus_new0 (Stats, 1);
sl@0
  2611
              if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
sl@0
  2612
                                                   dir_stats))
sl@0
  2613
                die ("no memory\n");
sl@0
  2614
            }
sl@0
  2615
          else
sl@0
  2616
            dbus_free (dirname_c);
sl@0
  2617
          
sl@0
  2618
          merge_stats_for_file (dir_stats, f);
sl@0
  2619
          
sl@0
  2620
          link = _dbus_list_get_next_link (&files, link);
sl@0
  2621
        }
sl@0
  2622
sl@0
  2623
      _dbus_hash_iter_init (stats_by_dir, &iter);
sl@0
  2624
      while (_dbus_hash_iter_next (&iter))
sl@0
  2625
        {
sl@0
  2626
          const char *dirname = _dbus_hash_iter_get_string_key (&iter);
sl@0
  2627
          Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
sl@0
  2628
sl@0
  2629
          print_stats (dir_stats, dirname);
sl@0
  2630
        }
sl@0
  2631
sl@0
  2632
      _dbus_hash_table_unref (stats_by_dir);
sl@0
  2633
sl@0
  2634
      link = _dbus_list_get_first_link (&files);
sl@0
  2635
      while (link != NULL)
sl@0
  2636
        {
sl@0
  2637
          File *f = link->data;
sl@0
  2638
sl@0
  2639
          print_untested_functions (f);
sl@0
  2640
          
sl@0
  2641
          link = _dbus_list_get_next_link (&files, link);
sl@0
  2642
        }
sl@0
  2643
sl@0
  2644
      link = _dbus_list_get_first_link (&files);
sl@0
  2645
      while (link != NULL)
sl@0
  2646
        {
sl@0
  2647
          File *f = link->data;
sl@0
  2648
sl@0
  2649
          print_poorly_tested_functions (f, &stats);
sl@0
  2650
          
sl@0
  2651
          link = _dbus_list_get_next_link (&files, link);
sl@0
  2652
        }
sl@0
  2653
sl@0
  2654
      link = _dbus_list_get_first_link (&files);
sl@0
  2655
      while (link != NULL)
sl@0
  2656
        {
sl@0
  2657
          File *f = link->data;
sl@0
  2658
          
sl@0
  2659
          print_n_untested_blocks_by_function (f, &stats);
sl@0
  2660
          
sl@0
  2661
          link = _dbus_list_get_next_link (&files, link);
sl@0
  2662
        }
sl@0
  2663
    }
sl@0
  2664
  
sl@0
  2665
  return 0;
sl@0
  2666
}