






























































                       June 23, 1992





                             2





                Generic Coverage Tool (GCT)
                        User's Guide


                        Brian Marick
                    Testing Foundations

            Documentation for version 1.3 of GCT
                    Document version 1.2





This manual describes the Generic Coverage Tool, a tool that
instruments C code to provide various measures of test suite
completeness.  Readers of this  manual  (and  users  of  the
tool)  should be experienced C programmers.  The tool itself
runs in almost any UNIX[1]  environment.   The  instrumented
code  depends on UNIX library routines and system calls, but
in only certain well-isolated procedures.  It is  relatively
simple to replace those, allowing use of the tool when test-
ing embedded systems.
























9_________________________
9  [1] UNIX is a trademark of Bell Laboratories.




                       June 23, 1992








_P_r_e_f_a_c_e



GCT is free software; you can redistribute it and/or  modify
it under the terms of the GNU General Public License as pub-
lished by the Free Software Foundation; either version 1, or
(at your option) any later version.

GCT is distributed in the hope that it will be  useful,  but
WITHOUT  ANY  WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A  PARTICULAR  PURPOSE.   See
the GNU General Public License for more details.



For more information about  GCT  or  the  other  services  I
offer, contact:

Brian Marick
Testing Foundations
809 Balboa
Champaign, Illinois  61820

(217) 351-7228
Email: marick@cs.uiuc.edu

You can join the GCT mailing list by sending  mail  to  gct-
request@ernie.cs.uiuc.edu.













This document is Copyright 8c9 1992 by Brian Marick.  Portions
are  Copyright  8c9 1991 by Motorola, Inc.  Under an agreement
between Motorola, Inc., and Brian Marick,  Brian  Marick  is
granted rights to these portions.

Brian Marick hereby permits you to reproduce  this  document
for personal use.  You may not reproduce it for profit.

This manual was originally based  on  _B_r_a_n_c_h  _C_o_v_e_r_a_g_e  _T_o_o_l
_D_o_c_u_m_e_n_t_a_t_i_o_n,  by Thomas Hoch, Brian Marick, and K. Wolfram
Schafer.




                       June 23, 1992





User's Manual                2                  Introduction


                       Introduction


This manual describes the  most  common  uses  of  GCT.  You
should  read  _A  _T_u_t_o_r_i_a_l  _I_n_t_r_o_d_u_c_t_i_o_n  _t_o _G_C_T first.  When
using GCT, you'll want  to  refer  to  the  manpages  (which
should  have  been  installed  when  GCT was) and _G_C_T _T_r_o_u_b_-
_l_e_s_h_o_o_t_i_n_g.  For conciseness, this manual does not  describe
some types of instrumentation.  See _U_s_i_n_g _W_e_a_k _M_u_t_a_t_i_o_n _C_o_v_-
_e_r_a_g_e _w_i_t_h _G_C_T and _U_s_i_n_g _R_a_c_e _C_o_v_e_r_a_g_e _w_i_t_h _G_C_T.

_1.  _T_e_s_t _S_u_i_t_e _C_o_v_e_r_a_g_e

How do you tell when you're  done  testing?   You  can  test
until you run out of time, test until you can't think of any
more test cases that seem useful, or test until some  objec-
tive stopping criterion is met.  GCT implements a variety of
such criteria.

_1._1.  _B_r_a_n_c_h _C_o_v_e_r_a_g_e

In branch coverage  [Myers79],  you  measure  whether  every
branch  in  the  program  has  been  taken in every possible
direction.  For example, in

        func(count)
        {
          if (count % 2 == 0)
            printf("count is even.\n");
          for(; count < 5; count++)
            printf("count %d\n", count);
        }

the IF statement would have to be taken in both the true and
false  directions.   The  test  of  the  FOR  loop must have
evaluated true at least once and false at least once.   This
could be accomplished by

        func(4);
        func(13);


_1._2.  _M_u_l_t_i_p_l_e-_C_o_n_d_i_t_i_o_n _C_o_v_e_r_a_g_e

Multiple-condition  coverage  [Myers79]  is  stronger   than
branch  coverage.   It  requires  that every logical operand
take on all possible values.  For example, for

        if (A && B)

multiple condition coverage requires that A be both true and
false and that B be both true and false.  Notice that branch
coverage is satisfied with the two test cases (A=1,B=1)  and
(A=0, B=1), but multiple-condition coverage is not.



                       June 23, 1992





User's Manual                3                  Introduction


_1._3.  _L_o_o_p _c_o_v_e_r_a_g_e

Neither of the two coverage measures above force the  detec-
tion  of  bugs  that  exhibit themselves only when a loop is
executed more than once.  For a loop like

        while (test)
          body

loop  coverage   requires   three   conditions   [Howden78],
[Beizer83]:

     that the test be FALSE on its first  evaluation  (thus,
     the body is not executed).

     that the test be TRUE the first time, then FALSE.  (The
     body is executed exactly once).

     that the test be TRUE at least twice (forcing at  least
     two executions of the loop).

_1._4.  _R_o_u_t_i_n_e _C_o_v_e_r_a_g_e

Routine  coverage  measures  whether  a  routine  has   been
entered.   It is most useful for determining the coverage of
large test suites running against entire systems.

_1._5.  _C_a_l_l _C_o_v_e_r_a_g_e

Call coverage measures whether a certain function  call  has
been  made.  100% call coverage means that all calls between
functions have been exercised at least once:  every function
has called every other that it can call.

_1._6.  _O_t_h_e_r _C_o_v_e_r_a_g_e

Two other types of coverage are described in  the  companion
documents  _U_s_i_n_g  _W_e_a_k  _M_u_t_a_t_i_o_n _C_o_v_e_r_a_g_e _w_i_t_h _G_C_T and _U_s_i_n_g
_R_a_c_e _C_o_v_e_r_a_g_e _w_i_t_h _G_C_T.

_2.  _S_o_m_e _T_e_r_m_i_n_o_l_o_g_y

A test condition is a description of something that must  be
tested.   For  example, "check that the routine handles null
pointers correctly"  or  "check  that  it  handles  negative
values  for  the variable A".   A test case may satisfy many
test conditions, and a single test condition may  be  satis-
fied by many test cases.

Test conditions can be  gotten  from  many  places.   People
often  derive them by looking at the program's user's manual
(or other black-box description).  GCT derives them from the
code. GCT-generated test conditions are called coverage con-
ditions.



                       June 23, 1992





User's Manual                4                  Introduction


The condition count tells how often a program under test has
been  executed in a way that satisfies a particular coverage
condition.  The coverage condition is a characteristic of  a
program;  the  condition count is a characteristic of a test
suite for that program.

Instrumentation is code added to the  program  to  increment
the condition counts.

















































                       June 23, 1992





User's Manual                5                     Checklist


                        A Checklist


This section is to be used as a quick reference  and  check-
list for using GCT.  Refer to later sections for details.

(1)  Copy the source to a test directory.

(2)  Create the control file, _g_c_t-_c_t_r_l.

(3)  Add a call to _g_c_t__r_e_a_d_l_o_g when the program starts.  Add
     calls to _g_c_t__w_r_i_t_e_l_o_g wherever the program exits.

(4)  Add the _g_c_t target to the makefile.  If all the  source
     is  in  a  single  directory, the target will look like
     this:

          gct:
                  gct-init;
                  $(MAKE) all "CC=gct"
                  $(CC) -c gct-ps-defs.c gct-write.c
                  $(MAKE) all "OBJ=$(OBJ) gct-ps-defs.o gct-write.o"
                  grestore

     If you have multiple directories,  your  makefile  will
     look much like this:

          gct:
                  gct-init;
                  $(MAKE) all "CC=gct -test-dir `pwd`"
                  $(CC) -c gct-ps-defs.c gct-write.c
                  $(MAKE) all "OBJ=$(OBJ) gct-ps-defs.o gct-write.o"
                  grestore

     The program is then made by typing "make gct".

(6)  Execute the program to create a log file.

          % a.out < test-script-1
          % a.out < test-script-2


(7)  Use the reporting tools.

          hostname% greport LOG
          hostname% gsummary LOG











                       June 23, 1992





User's Manual                6  Directory and File Structure


                     Instrumenting a Program


This chapter describes how to  instrument  a  program.   The
next describes what the coverage data means.

_3.  _D_i_r_e_c_t_o_r_y _a_n_d _F_i_l_e _S_t_r_u_c_t_u_r_e

In the following sections, we will use this directory struc-
ture   for  the  examples.   The  directory  containing  the
makefile that makes the final executable is called the  mas-
ter  directory.   In  our  example,  the master directory is
named config.


test/
        config/   (the master directory)
                control file   (usually named gct-ctrl)
                map file   (usually named gct-map)
                edit file (usually named gct-edit)
                Makefile   (the master makefile)
                executable
                gct-defs.h
                gct-ps-defs.h
                gct-ps-defs.c
                gct-write.c
                gct-rscript
        src1/
                Makefile
                program1.c
                program2.c
                gct_backup/
                       program1.c
                       program2.c
        src2/
                Makefile
                program3.c
                program4.c
                program5.c

A number of GCT-specific files are added to the directories.
Most of them can be ignored; however, all are described here
for reference.

gct-ctrl
     The control file controls which files and routines  are
     to be instrumented; it also describes what instrumenta-
     tion is to be done.

gct-map
     Each coverage condition is given a unique  number;  the
     map  file  contains the information needed to turn that
     number into comprehensible text.




                       June 23, 1992





User's Manual                7  Directory and File Structure


gct-edit
     Each coverage condition may  be  suppressed  using  the
     gedit(1)  program.  This file identifies the suppressed
     conditions.

gct-defs.h
     This contains  definitions  used  in  the  instrumented
     files  and other GCT-specific files.  It is copied into
     the directory once and is usually never changed.

gct-ps-defs.h
     This file is generated each time the Makefile  is  exe-
     cuted.   Each  invocation of GCT uses this file to tell
     the next what number to use  for  its  first  condition
     count.  (Just as a system build has many calls to the C
     compiler, an instrumentation has many calls to GCT.)

gct-ps-defs.c
     This file contains the definition of the table used  to
     store  condition  counts.   It must be recompiled every
     time a new instrumented executable is built, but it  is
     never edited.

gct-write.c
     This file contains routines to read and write the  con-
     dition  counts.   This file is useful only for applica-
     tion programs; those testing embedded systems will have
     to read and write condition counts some other way.

gct_backup
     When instrumenting a file, a copy  is  stored  in  this
     directory so that the instrumented version can later be
     replaced by the original version.  The makefile usually
     calls grestore to do this automatically.

gct-rscript
     This file tells the grestore program how  to  undo  the
     effects of instrumentation.



















                       June 23, 1992





User's Manual                8              The Control File


_4.  _T_h_e _C_o_n_t_r_o_l _F_i_l_e


The control file is stored  in  the  master  directory.   It
determines  which  files  and  routines are instrumented and
what kind of instrumentation is done.   It is usually called
gct-ctrl, but the name can be changed with the -test-control
option to GCT.

The control file consists of a number of entries,  arbitrary
white  space, and comments.  A comment begins with a '#'; it
persists until the end of the line.  The file  contains  the
following  three  elements,  called  _t_o_p  _l_e_v_e_l  _d_i_r_e_c_t_i_v_e_s,
arranged in any order:

_o_p_t_i_o_n _d_i_r_e_c_t_i_v_e_s
_c_o_v_e_r_a_g_e _d_i_r_e_c_t_i_v_e_s
_f_i_l_e _d_i_r_e_c_t_i_v_e_s

Although none of the directives are required, an empty  con-
trol file is useless.

_4._1.  _O_p_t_i_o_n _D_i_r_e_c_t_i_v_e_s

Options set boolean values within GCT; a list of the options
and  their  default values is given below.  An option direc-
tive has this form:

   (options _o_p_t_i_o_n...)

By naming an option, you turn it on.  By preceding it with a
minus sign, you turn it off.  Hence,

   (options option1 option2)

turns both option1 and option2 on, whereas

   (options -option1 -option2)

turns them off.

A list of options is given after  the  remaining  directives
are described.

_4._2.  _C_o_v_e_r_a_g_e _D_i_r_e_c_t_i_v_e_s

A coverage directive tells GCT what kinds of instrumentation
to  perform  (branch,  loop, etc.).  Coverage directives are
like options: they are turned on by naming them, and  turned
off by preceding their names with a minus sign:

   (coverage branch -loop)

Branch   instrumentation   is   to   be    inserted;    loop



                       June 23, 1992





User's Manual                9              The Control File


instrumentation is not.


All possible coverage[2] would be turned on with

   (coverage branch loop multi relational routine call)


By default, no coverage is turned on.

_4._3.  _F_i_l_e _D_i_r_e_c_t_i_v_e_s

A file directive has three forms:

1) Simply naming  a  file  causes  it  to  be  instrumented.
Filenames  that  do  not  begin with a slash are interpreted
relative to the master directory.  So, file entries for  the
example directory structure given earlier might look like:


     ../src1/program1.c
     ../src1/program2.c

(Remember that the master makefile is  in  the  _c_o_n_f_i_g  sub-
directory.)

2) Preceding a filename with a minus sign causes it  not  to
be instrumented.

3) If a file name is  enclosed  within  parentheses,  it  is
instrumented.    Further,  option  directives  and  coverage
directives may also be specified;  they  override  top-level
directives.  Thus, the following control file specifies that
_o_p_t_i_o_n_1 applies to all files except _m_a_c_r_o_s._c.

(options option1)
(macros.c (options -option1))


_4._4.  _R_o_u_t_i_n_e _D_i_r_e_c_t_i_v_e_s

A file directive may also contain one or more routine direc-
tives.  A routine directive has one of three forms:

1) Simply naming a routine causes it to be instrumented.

2) Preceding its name with a minus sign causes it not to  be
instrumented.

9_________________________
9  [2] I am ignoring race and weak mutation coverage, as
they're not covered by this document.




                       June 23, 1992





User's Manual                10             The Control File


3) If the routine name is within parentheses, it is  instru-
mented.   Option  and coverage directives may also be speci-
fied.  They override those used at the top level  or  within
filename directives.

The routine name may be preceded by the  keyword  "routine";
this  allows  you  to  instrument  routines named "options",
"instrument", or "routine":

(file.c (options option1)
        (routine options (options -option1)))



_4._5.  _O_p_t_i_o_n_s

files   Default: off

     This option can only be used at  the  outermost  level.
     If on, all files are processed, except those explicitly
     turned off.  If off,  all  files  are  ignored,  except
     those  explicitly  turned  on.   If  a file is not pro-
     cessed, it is completely untouched by GCT.

     Example:  An empty control file causes no files  to  be
     processed.   To  process all files except _m_y_f_i_l_e._c, use
     this control file:

     (options files)
     -myfile.c

     The default is "off" because GCT is usually used from a
     makefile.  It is better to explicitly name the files to
     be instrumented than to rely on  the  makefile  calling
     GCT  on  the  right  files.  (See section 6, Changes to
     Makefiles, for details.)



instrument      Default: on

     The previous option told GCT whether to process a file.
     This  option  tells  GCT whether to instrument all rou-
     tines in such a file.  It is on by default.

     Example:  Suppose we want to instrument all routines in
     file1.c,  only  routine instrument_me() in file2.c, all
     routines in file3.c except routine do_not_instrument(),
     and no other files.

         # The default is to process no file.
         file1.c
         (file2.c (options -instrument) instrument_me)
         (file3.c -do_not_instrument)



                       June 23, 1992





User's Manual                11             The Control File


     This option can also be applied to  a  single  routine,
     though  it  is much less useful.  For example, the fol-
     lowing control  file  applies  a  debugging  option  to
     my_routine(), which we do not want instrumented:

        (file2.c
             (my_routine (options -instrument show-decls)))



macros  Default: off

     Consider the getc() macro.  It expands into 298 charac-
     ters  of code.  The results of instrumenting this could
     be quite confusing; for a line like

        for (c = getc(stream); c >= 'A'; c = getc(stream))

     greport might refer to the first ">=" in the line,  and
     you  very  likely  would not realize that the operation
     referred to is in the expansion of getc.   Further,  it
     is  inappropriate to test the expansion of getc: having
     been used millions of times, it's pretty likely  to  be
     correct  and  should  be  treated  just like a function
     call.  Therefore, by default GCT  does  not  instrument
     code within macro expansions.

     The macros option makes GCT instrument even code within
     macros.   The  main use of this option is for function-
     defining macros.  Suppose you want  to  measure  branch
     coverage for this code:

     #define NEWFUNC(NAME, RETURN-TYPE) \
     RETURN-TYPE NAME (stream) \
     FILE *stream; \
     { \
         char a = getc(Stream); \
         if ('0' == a) \
             return 1; \
         return 0; \
     }
     NEWFUNC(myfunc, float)

     Normally myfunc() would be  completely  uninstrumented.
     To instrument it, you must use the macros option:

        (file.c (myfunc (options macros)))

     You will have to put up with greport messages about the
     contents  of _g_e_t_c; this is unavoidable.  If the body of
     the function were not defined  within  the  macro,  the
     option would be unneeded.





                       June 23, 1992





User's Manual                12             The Control File


_4._5._1.  _W_e_a_k _M_u_t_a_t_i_o_n _O_p_t_i_o_n_s

Some options apply only to weak mutation coverage.  They are
documented in _U_s_i_n_g _W_e_a_k _M_u_t_a_t_i_o_n _C_o_v_e_r_a_g_e _w_i_t_h _G_C_T.

_4._5._2.  _D_e_b_u_g_g_i_n_g _O_p_t_i_o_n_s

Some other options are useful when debugging GCT.  They  are
documented in the source file _g_c_t-_o_p_t_s._d_e_f.
















































                       June 23, 1992





User's Manual                13           Editing the Source


_5.  _E_d_i_t_i_n_g _t_h_e _S_o_u_r_c_e

_5._1.  _G_c_t__w_r_i_t_e_l_o_g

For speed,  GCT  uses  in-core  tables  to  store  condition
counts.   To  have them written to disk, you have to add one
line of code per exit to  your  program.   A  call  to  _e_x_i_t
should be replaced with

   gct_writelog("_l_o_g_f_i_l_e");
   exit(3);

This calls the library routine gct_writelog which writes all
information about a particular test run to a log file called
_l_o_g_f_i_l_e.  Other process-terminating  routines  (like  _a_b_o_r_t)
must  be  handled  the same way.  If your program "falls off
the end of main", add a call before the closing bracket.

Often, you can find a  simpler  solution  than  editing  the
whole  program.   One  example is to add the following to an
include file that the whole program uses:

     static
     my_exit(value)
     int value;
     {
       gct_writelog("_l_o_g_f_i_l_e");
       exit(value);
     }
     #define exit my_exit

In a non-terminating program you must use  a  trigger  event
like a signal to call gct_writelog.

_5._2.  _G_c_t__r_e_a_d_l_o_g

     gct_readlog("_l_o_g_f_i_l_e");

reads condition counts from the given _l_o_g_f_i_l_e, if it exists.
If the logfile doesn't exist (or if gct_readlog isn't used),
the counts all start as zero.  The advantage of  gct_readlog
is  that successive runs of the program produce a cumulative
log.  If you don't use it, you can still  create  cumulative
log files as follows:

     % a.out < test-script-1; mv LOG LOG.old
     % a.out < test-script-2
     % gmerge LOG.old LOG > LOG.cumulative

but this is considerably less convenient.







                       June 23, 1992





User's Manual                14         Changes to Makefiles


_6.  _C_h_a_n_g_e_s _t_o _M_a_k_e_f_i_l_e_s

_6._1.  _S_o_u_r_c_e _i_n _O_n_e _D_i_r_e_c_t_o_r_y

GCT was designed to require minimal changes to makefiles and
other system-description scripts.  However, "minimal" is not
"none". For makefiles, you must do the following:

-    The makefiles must use the $(CC) macro. Instrumentation
     is  done by causing the makefile to call GCT instead of
     the standard C compiler: $(CC) allows this global  sub-
     stitution.

-    The makefile must use some  macro  that  describes  the
     object files of the program (often called $(OBJ)).

-    You must make sure that the  makefile  would  recompile
     the  source  files  that  you  want instrumented.  (The
     makefile changes described below  ensure  that  instru-
     mented  files  will be reinstrumented the next time the
     makefile is invoked.)

Consider this makefile:

      all:    program1.o program2.o
              cc -o system program1.o program2.o

      program1.o:     incl.h program1.c
              cc -c program1.c

      program2.o:     incl.h program2.c
              cc -c program2.c

7_________________________________________________|7|7|7|7|7|7|7|7|7__________________________________________________
|
|
|
|
|
|
|
|
|

It must be changed into the following makefile:






















                       June 23, 1992





User's Manual                15         Changes to Makefiles


      OBJ = program1.o program2.o

      all:    $(OBJ)
              $(CC) -o system $(OBJ)

      gct:
              gct-init;
              $(MAKE) all "CC=gct"
              $(CC) -c gct-ps-defs.c
              $(CC) -c gct-write.c
              $(MAKE) all "OBJ=$(OBJ) gct-ps-defs.o gct-write.o"
              grestore

      program1.o:     incl.h program1.c
              $(CC) -c program1.c

      program2.o:     incl.h program2.c
              $(CC)  -c program2.o

7_________________________________________________________________|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7__________________________________________________________________
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

The commands in the _g_c_t: target do the following:

(1)  gct-init
     gct-init  creates  the  files  gct-ps-defs.h,   gct-ps-
     defs.c,   gct-defs.h,  and  gct-write.c.  It  will  not
     overwrite the latter three files if  they  are  already
     there.

     The semicolon after gct-init is needed because of a bug
     in some versions of make.

(2)  $(MAKE) all "CC=gct"
     This commands causes the makefile to invoke GCT on  all
     the  files it would normally compile.  The instrumented
     files will have the same names as the  original  files.
     The original files will be saved in the gct_backup sub-
     directory.

(3)  $(CC) -c gct-ps-defs.c; $(CC) -c gct-write.c
     This compiles the definitions  of  the  instrumentation
     log and the routine that writes the log.  These must be
     compiled at this point because they depend  on  gct-ps-
     defs.h,  which  was  updated to contain the size of the
     log during the previous step.

(4)  $(MAKE) all "OBJ=$(OBJ) gct-lib.o gct-write.o"
     This compiles the instrumented  files  and  links  them
     together with gct-lib.o and gct-write.o into an execut-
     able file.

(5)  grestore
     The grestore command copies all  the  files  back  from
     gct_backup.   greport  output  refers  to  the original
     filenames, so you want those  filenames  to  be  human-



                       June 23, 1992





User's Manual                16         Changes to Makefiles


     readable, not instrumented.

     If the make fails, grestore will not be executed.  This
     can  be useful when diagnosing the problem.  You should
     run grestore by hand before retrying the make.  If  you
     forget,  GCT  will  refuse to reinstrument the already-
     instrumented files.

     BEWARE:  If you don't do the grestore, be  careful  not
     to  remove the files in the gct_backup directory.  They
     may be the only uninstrumented versions.  (This is  why
     you should always instrument a copy of your source.)


A trace of the original makefile would look like this:

     cc -c program1.c
     cc -c program2.c
     cc -o system program1.o program2.o


The modified makefile produces this:

     gct-init;
     make all "CC=gct"
     gct -c program1.c
     gct -c program2.c
     gct -o system program1.o program2.o
     cc -c gct-ps-defs.c
     cc -c gct-write.c
     make all "OBJ=program1.o program2.o gct-lib.o gct-write.o"
     cc -c program1.c
     cc -c program2.c
     cc -o system program1.o program2.o gct-lib.o gct-write.o
     grestore


All files are first instrumented, then the utility  routines
are compiled, then the now-modified files are compiled.  All
the object files, including the utility routines, are linked
together.  Finally,  grestore replaces the instrumented ver-
sions with the original versions.

_6._2.  _M_u_l_t_i_p_l_e _d_i_r_e_c_t_o_r_i_e_s

If source is in several directories, you  must  make  a  few
extra changes.

-    Make sure  that  the  $(CC)  macro  is  passed  to  the
     makefiles  that  are called by the main makefile.  Call
     the sub-makefiles from  the  main  makefile  with  make
     "CC=$(CC)".  Sub-makefiles must also use $(CC).

-    The name of the master directory  where  the  map  file



                       June 23, 1992





User's Manual                17         Changes to Makefiles


     will  be  stored  has  to  be  passed  down to the sub-
     makefile. Use the -test-dir option to GCT.

The main makefile could then look like this, where the addi-
tional changes are highlighted.

      OBJ=    ../src1/program1.o ../src1/program2.o ../src2/program3.o
              ../src2/program4.o ../src2/program5.o

      all:
              cd ../src1; make "CC=$(CC)"
              cd ../src2; make "CC=$(CC)"
              $(CC) -o system $(OBJ)

      gct:
              gct-init;
              $(MAKE) all "CC=gct -test-dir `pwd`"
              $(CC) -c gct-ps-defs.c gct-write.c
              $(MAKE) all "OBJ=$(OBJ) gct-ps-defs.o gct-write.o"
              grestore

7________________________________________________________________________|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7_________________________________________________________________________
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Note: If you are working in a hierarchical directory  struc-
ture,  GCT  will  greate a gct_backup directory in each sub-
directory.  grestore, run in  the  master  directory,  knows
about  all  these  directories  and  will  copy back all the
files.






























                       June 23, 1992





User's Manual                18        The Types of Coverage


                   The Types of Coverage


GCT can instrument the program to measure any of these kinds
of coverage:

branch:   branch coverage
multi:    multi-conditional coverage
loop:     loop coverage
relational:relational operator coverage
routine:  routine entry coverage
call:     call coverage

This chapter describes precisely what is measured  for  each
of  these  kinds.  It also describes what the greport output
will look like.

_6._3.  _M_o_r_e _T_e_r_m_i_n_o_l_o_g_y _a_n_d _B_a_c_k_g_r_o_u_n_d

The condition count is incremented by  instrumentation  code
inserted  into  the  program.   Whether  instrumentation  is
inserted is controlled in two ways:

(1)  The instrumentation option.   Normally,  everything  is
     instrumented if the file is processed.

(2)  The macros option.  Normally, code within the expansion
     of a macro is not instrumented.

When is code "within" a macro's expansion?   Instrumentation
applies  to  whole  statements or expressions in the program
(an IF statement, or a relational expression).  However, GCT
decides  whether  to instrument by examining a single token,
called the _p_o_i_n_t _o_f _i_n_s_t_r_u_m_e_n_t_a_t_i_o_n.

Consider this code:

        #define IF      if

        IF (x < 5)
        then x = 3;

The IF statement will not be instrumented, because the point
of  instrumentation  (the if) is within a macro, even though
the rest of the statement is not.   The  following  sections
define all the points of instrumentation.

The arguments to a macro are part  of  its  expansion.   For
example, in this code

        #define TEST(tst)  if ((tst)) {
        #define ENDTEST    }

        TEST(a < b)



                       June 23, 1992





User's Manual                19        The Types of Coverage


           printf("a is less than b");
        ENDTEST

a<b is not instrumented, for the same reason the if is not.

Most of the time, these subtleties are invisible.  Since the
code  isn't instrumented, it isn't mentioned in greport out-
put, so you never think about it.

_6._4.  _G_e_n_e_r_a_l _N_o_t_e_s _a_b_o_u_t _G_r_e_p_o_r_t _O_u_t_p_u_t

greport lines look like this:

"example1.c", line 9: operator < might be <=. (L == R)
"example1.c", line 10: if was taken TRUE 1, FALSE 1 times.

"if" and "<" are tags that identify what the line refers to.
If  there  were  more  than one "if" or "<" on the line, the
tags would be ambiguous.  In this case, the second and later
instances would be numbered:

"example1.c", line 9: operator < might be <=. (L == R)
"example1.c", line 9: operator < (2) might be <=. (L == R)
"example1.c", line 10: if was taken TRUE 1, FALSE 1 times.
"example1.c", line 10: if (2) was taken TRUE 0, FALSE 1 times.


In some cases, the identification tag is abbreviated to save
space on the line.  See the section on multicondition cover-
age, which is the type of coverage that most uses  abbrevia-
tions.


























                       June 23, 1992





User's Manual                20              Branch Coverage


_7.  _B_r_a_n_c_h _C_o_v_e_r_a_g_e

When branch instrumentation is turned  on,  these  operators
must  have  their  tests  evaluate to both zero and non-zero
values:


8          _______________________________________
           Operator     Point of instrumentation
8          _______________________________________
           if          if
8          _______________________________________
           for         for
8          _______________________________________
           while       while
8          _______________________________________
           do-while    do
8          _______________________________________
           question    ?
8          _______________________________________
7         |7|7|7|7|7|7|7|7|







                    |7|7|7|7|7|7|7|7|







                                                |7|7|7|7|7|7|7|7|










In a switch, each case  label  must  be  branched  to.   The
default  case  must also be taken (even if one is not expli-
citly present).  Fall-throughs and gotos into  a  switch  do
not  increment  condition  counts; only the execution of the
switch expression is considered to cause a true branch.  For
example:

switch(tag)
{
        case 1:
        case 2:
                <some code>
                break;
        case 3:
                goto_target:
                    <more code>
        case 4:
                <more code>
                break;
}


-    If tag equals 1, the  first  case  will  be  marked  as
     taken.   The  second  will not be marked as taken until
     the switch is executed with tag equal to 2.

-    A goto to goto_target does not mean the third case  has
     been  taken.   Even though it will cause a fall-through
     into the fourth case, it does not count as a branch  to
     that case.

-    Since this switch statement has no  default  case,  GCT
     will  insert  one.  That is, you are required to have a
     value for tag different from 1, 2, 3, and 4.

9


                       June 23, 1992





User's Manual                21              Branch Coverage


-    The point of instrumentation is  the  case  or  default
     token.   (In  the  case  of  the automatically inserted
     default, it's the closing bracket of the switch.)






















































                       June 23, 1992





User's Manual                22              Branch Coverage


As an example of the greport  output  for  branch  coverage,
consider this program:

     1    #include <stdio.h>
     2
     3    main ()
     4    {
     5      int arg;
     6
     7      printf (" This is an example\n");
     8      arg = 1;
     9      while ( arg <= 2 ) {
     10        if ( arg == 1 ) { if ( 4 == 2*2 )  printf  ("
     Second \n"); };
     11        arg++;
     12      };
     13      switch (arg) {
     14      case 2: /* some code */  break;
     15      case 3: printf (" Third \n");
     16      }
     17    }


greport's default output describes unsatisfied conditions:

"example1.c", line 10: if (2) was  taken  TRUE  1,  FALSE  0
times.
"example1.c", line 14: case was taken 0 times.
"example1.c", line 16: default was taken 0 times.


There is more than one if statement on line 10,  so  greport
adds "(2)".  The system numbers such ambiguous keywords from
left to right.

Note that a default case is reported for line 16,  the  line
of the switch's closing bracket.

If all conditions are required, greport -all should be used:

"example1.c", line 9: while was taken TRUE 2, FALSE 1 times.
"example1.c", line 10: if was taken TRUE 1, FALSE 1 times.
"example1.c", line 10: if(2)  was  taken  TRUE  1,  FALSE  0
times.
"example1.c", line 14: case was taken 0 times.
"example1.c", line 15: case was taken 1 times.
"example1.c", line 16: default was taken 0 times.

Examining this, we can see that the while loop was  executed
twice, and was left because its test evaluated false.







                       June 23, 1992





User's Manual                23     Multi-condition Coverage


_8.  _M_u_l_t_i-_c_o_n_d_i_t_i_o_n _C_o_v_e_r_a_g_e

For the following operators, both the left-hand  and  right-
hand sides must be both zero and non-zero:

8         _________________________________________
           Operator      Point of instrumentation
8         _________________________________________
          logical and   &&
8         _________________________________________
          logical or    ||
8         _________________________________________
7        |8|7|7|7|


9                     |8|7|7|7|


9                                                 |8|7|7|7|




9
greport reports on each half of each  condition  separately.
For a line of code like

     if (a && (b < 12 || b > c))

greport output would look like:

"test.c", line 4: condition 1 (a, 1) was taken TRUE 1, FALSE 0 times.
"test.c", line 4: condition 2 (b, 1) was taken TRUE 1, FALSE 0 times.
"test.c", line 4: condition 3 (b, 2) was taken TRUE 1, FALSE 0 times.
"test.c", line 4: condition 4 (b, 2) was taken TRUE 0, FALSE 0 times.

The condition number identifies the condition in  the  line,
numbered  from left to right.  The items in parentheses make
it easier to find the condition.   The  first  item  is  the
first  token  in one of the sides of the logical expression.
The second item is the nesting level in the tree of  boolean
operators  that makes up the whole expression.  Thus, in the
above example, we have these conditions:

1       a                       (&&-expression, left side)
2       (b < 12 || c > c)       (&&-expression, right side)
3       b<12                    (||-expression, left side)
4       b>c                     (||-expression, right side)


Another test condition that has proven useful is  to  insist
that  a  function that returns a boolean value should return
both zero and non-zero.  Since C has no  boolean  type,  GCT
must  deduce  when  a  particular integer-returning function
really returns boolean values.  This is done by  considering
the expression that calculates the return value:

        return 1 + 1;           /* Returns integer. */
        return a && b;          /* Returns boolean. */
        return f(a);            /* We don't know. */

Here are the operators that produce boolean return values:

8              ________________________________
               <    <=   >   >=   ==   !=   !
               &&   ||
8              ________________________________



8                       June 23, 1992


9


8User's Manual                24     Multi-condition Coverage


999             |9|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|
777777777777777777777777777777777777777777777777777899                                             |9|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|99|
77777777777777777777777777777777777777777777777778Of these, we need no special instrumentation for && and  ||:
satisfying   multi-condition  coverage  for  the  left-  and
right-hand sides will necessarily yield both true and  false
values for the whole expression.

Of course, a boolean return value might be one that was cal-
culated  earlier.   Therefore,  if the right-hand-side of an
assignment statement  is  one  of  the  following  types  of
expressions, the result must be both zero and non-zero:

8              ________________________________
               <    <=   >   >=   ==   !=   !
               &&   ||
8              ________________________________
7             |8|7|
9                                             |8|7|


9
Again, we need no special instrumentation for && and ||.

Suppose you have this code:

  flag = ! (b || c);
  return !flag;

greport -all might show this:

"test.c", line 4: condition 1 (= expression) was taken TRUE 0, FALSE 3 times.
"test.c", line 4: condition 2 (b, 1) was taken TRUE 2, FALSE 1 times.
"test.c", line 4: condition 3 (c, 1) was taken TRUE 1, FALSE 0 times.
"test.c", line 5: condition 1 (return) was taken TRUE 3, FALSE 0 times.


Declarations are treated like assignment statements.   Given
this (odd) code:

  float c1 = (c < d);

greport -all might show this  if  multicondition  and  rela-
tional operator coverage are turned on:

"multi.c", line 7: condition 1 (declaration) was taken TRUE 1, FALSE 1 times.
"multi.c", line 7: operator < might be >. (L!=R)  [1]
"multi.c", line 7: operator < might be <=. (L==R)  [1]
"multi.c", line 7: operator < is never barely true. (L==R-1)  [0]


_8._1.  _A_b_b_r_e_v_i_a_t_i_o_n_s _i_n _M_u_l_t_i_p_l_e _C_o_n_d_i_t_i_o_n _O_u_t_p_u_t

Operands in C may be arbitrarily complicated:

        Array[x->y.z].m->next

so GCT abbreviates to save space on the line.




                       June 23, 1992





User's Manual                25     Multi-condition Coverage


Array references
     Array references are printed as _a_r_r_a_y_n_a_m_e[...]:

     "example1.c", line 9: condition 1 (A[...], 1) was taken TRUE 2, FALSE 1 times.

     If the arrayname is itself more complex than  a  single
     identifier,  it  is  printed as <...>.  Thus, the array
     reference (p->array)[5] might yield this message:

     "example1.c", line 9: condition 1 (<...>[...], 1) was taken TRUE 2, FALSE 1 times.


Dereference
     If the pointer being dereferenced is an identifier, the
     message will be

     "example1.c", line 9: condition 1 (*p, 1) was taken TRUE 2, FALSE 1 times.

     Otherwise, it will be

     "example1.c", line 9: condition 1 (*<...>, 1) was taken TRUE 2, FALSE 1 times.

     if, say, the C code were "*(p+1)".


Structures and unions
     If the structure is an identifier, its  name  is  used;
     otherwise, the usual <...> notation is used.  The field
     is always explicitly printed.  Examples:

          A.field is printed as "A.field".
          B->field is printed as "B->field".
          A[4]->field is printed as "<...>->field".
























                       June 23, 1992





User's Manual                26         Loop Instrumentation


_9.  _L_o_o_p _I_n_s_t_r_u_m_e_n_t_a_t_i_o_n

These are the looping statements:

8          _______________________________________
           Operator     Point of instrumentation
8          _______________________________________
           for         for
8          _______________________________________
           while       while
8          _______________________________________
           do-while    do
8          _______________________________________
7         |7|7|7|7|7|




                    |7|7|7|7|7|




                                                |7|7|7|7|7|






Loops constructed with gotos are not measured.

The greport message for a while loop might look like this:

"example1.c", line 9: loop zero times: 1, one time: 2, many times: 3.

The output refers to the test of the loop.  The "zero" entry
is  the  number  of  times the loop test failed on the first
try; the "one" entry is the number  of  times  it  succeeded
exactly  once;  the  "many"  entry is the number of times it
succeeded at least twice.

To be precise: a _t_e_s_t _s_e_q_u_e_n_c_e is the series  of  values  of
the  test  in  a single execution of the loop.  Entering the
looping statement from outside (even by a goto)  begins  the
sequence;  it ends when a statement outside the loop is exe-
cuted.  However, the beginning of a sequence will be  missed
if  a  loop  is exited with a goto or break and then entered
with another goto.

These test sequences are  required:  FALSE;  TRUE-FALSE  (or
simply TRUE in the case of a goto or break out of the loop);
TRUE-TRUE-...-FALSE (or simply TRUE-TRUE-... in the case  of
an escape from the loop).

Note that, in the case of a while loop, the greport message

"example1.c", line 9: loop zero times: 1, one time: 0, many times: 0.

means that the body of the loop was never  executed.   In  a
do-while  loop,  it  means  that the body was executed once,
since the loop body is always executed before the loop  test
is  evaluated.  Therefore, the interpretation of a line like
the following is tricky:

"example1.c", line 9: loop zero times: 2, one time: 0, many times: 4.

The body of the loop has been executed exactly once  on  two
occasions,  exactly  twice  on  no  occasions, and more than
twice on four occasions.

This is admittedly confusing and will eventually be fixed.
9


                       June 23, 1992





User's Manual                27 Relational Operator Coverage


_1_0.  _R_e_l_a_t_i_o_n_a_l _O_p_e_r_a_t_o_r _C_o_v_e_r_a_g_e

There are two goals for relational operator coverage:

(1)  Probe off-by-one errors.  For example, for

         if (length >= 100)

     branch coverage requires some length smaller than  100.
     However,  we  don't want to try just any such length --
     we'd like one only slightly smaller, one that makes the
     expression "barely false".  Such a value is more likely
     to discover that 100 is the wrong value.  We also  want
     the  expression  to be "barely true", to have the smal-
     lest value of length that makes  the  expression  true.
     That is, we want length to be exactly 100.

(2)  Force test cases that make the operator  actually  used
     yield  a  different  value  from  another operator that
     might have been used.  Suppose we  have  the  following
     code:

         if (a + b < c + d )

     A common mistake in such code is using "<" when "<=" is
     correct.  Many tests that satisfy branch coverage would
     cause the correct and incorrect programs  to  take  the
     same  branch in the same direction - giving very little
     evidence that the common mistake wasn't make.  A better
     test would cause the two programs to take the branch in
     different directions.  That will  only  happen  if  the
     coverage condition A+B==C+D is satisfied.

Note that these two goals often overlap.

For each of the relational operators, the  following  tables
describe  boundary  conditions and likely mis-uses, together
with the test conditions to rule them out.   In  all  cases,
epsilon is 1 (in the current implementation).

8_______________________________________________________________________
                                 L < R
8_______________________________________________________________________
    Condition           Rule out with        Special case for Integers
8_______________________________________________________________________
 >                  L!=R
8_______________________________________________________________________
 <=, barely false   L==R
8_______________________________________________________________________
 barely true        L < R <= L + epsilon     L == R - 1
8_______________________________________________________________________
7|8|7|7|7|7|7|7|





9                 |7|7|7|7|7|




                                         |7|7|7|7|7|




                                                                      |8|7|7|7|7|7|7|







9







                       June 23, 1992





User's Manual                28 Relational Operator Coverage


8_____________________________________________________________________
                               L <= R
8_____________________________________________________________________
   Condition          Rule out with        Special case for Integers
8_____________________________________________________________________
 <, barely true   L==R
8_____________________________________________________________________
 >=               L!=R
8_____________________________________________________________________
 barely false     L > R >= L - epsilon     L == R + 1
8_____________________________________________________________________
7|8|7|7|7|7|7|7|





9               |7|7|7|7|7|




                                       |7|7|7|7|7|




                                                                    |8|7|7|7|7|7|7|







9

8_______________________________________________________________________
                                 L > R
8_______________________________________________________________________
    Condition           Rule out with        Special case for Integers
8_______________________________________________________________________
 <                  L!=R
8_______________________________________________________________________
 >=, barely false   L==R
8_______________________________________________________________________
 barely true        L > R >= L - epsilon     L == R + 1
8_______________________________________________________________________
7|8|7|7|7|7|7|7|





9                 |7|7|7|7|7|




                                         |7|7|7|7|7|




                                                                      |8|7|7|7|7|7|7|







9

8_____________________________________________________________________
                               L >= R
8_____________________________________________________________________
   Condition          Rule out with        Special case for Integers
8_____________________________________________________________________
 >, barely true   L==R
8_____________________________________________________________________
 <=               L!=R
8_____________________________________________________________________
 barely false     L < R <= L + epsilon     L = R - 1
8_____________________________________________________________________
7|8|7|7|7|7|7|7|





9               |7|7|7|7|7|




                                       |7|7|7|7|7|




                                                                    |8|7|7|7|7|7|7|







9
There are no coverage conditions for == and  !=.   The  most
likely  fault is using one when the other is correct; such a
fault is automatically ruled out whenever  the  operator  is
executed (as is ensured by multi-condition coverage).

The greport output for relational  operator  coverage  looks
like this:

   "example1.c", line 9: operator < might be <=. (L == R)
   "example1.c", line 9: operator < is never barely true. (L == R-1)

The parenthetical comment suggests the test  condition  that
must  be  satisfied.  L stands for the left-hand side of the
relational expression; R for the right-hand side.

Once the coverage condition is satisfied, nothing  regarding
it  will  appear  in  the  report  unless the -all option is
given:

"lc.c", line 275: operator <= might be >=.  (L != R) [1]
"lc.c", line 275: operator <= might be <.  (L == R) [3]




                       June 23, 1992





User's Manual                29 Relational Operator Coverage


The number in brackets is the condition count, the number of
times the test condition has been satisfied.

_1_0._1.  _W_a_r_n_i_n_g_s

GCT issues a warning that many versions of _l_i_n_t(_1) do not:

a == b;

yields

"Warning:  == can have no effect."













































                       June 23, 1992





User's Manual                30    Routine and Call Coverage


_1_1.  _R_o_u_t_i_n_e _C_o_v_e_r_a_g_e

When an instrumented routine is entered, the condition count
is incremented.  Routine coverage is not affected by macros;
coverage is measured  even  for  routines  defined  entirely
within a macro.

The greport output is straightforward:

"example1.c", line 9: routine caller is never entered.

In this case, line 9 is the first statement of  the  routine
(after  any  declarations).   If  greport  -all is used, you
might see

"example1.c", line 9: routine caller is never entered. [0]
"example1.c", line 30: routine main is never entered. [1]

which indicates that  _m_a_i_n  has  been  called  once,  _c_a_l_l_e_r
never.

There is one special case:  routines  containing  no  state-
ments, such as

foo()
{
}

or

foo(a)
int a;
{
  int only_a_declaration = bar(a);
}

do not have routine instrumentation added.


_1_2.  _C_a_l_l _C_o_v_e_r_a_g_e

When a function call is made, its condition count is  incre-
mented.   The  point of instrumentation is the function name
(which may be a complex structure, such as an element of  an
array of function pointers).

greport identifies both the function called and the function
that makes the call:

"example1.c", line 9: call of callme (in caller) never made.

If the function name is complex, it is abbreviated  as  with
multicondition coverage:




                       June 23, 1992





User's Manual                31    Routine and Call Coverage


"example1.c", line 9: call of calltable[...] (in caller) never made.

Note that there is one condition count for all of calltable,
not one for each element of the array (whose size may not be
known at compile time).




















































                       June 23, 1992





User's Manual                32Instrumenting Embedded Systems


              Instrumenting Embedded Systems


For our purposes, an embedded system is one that  can't  use
ordinary  UNIX  I/O.  An example might be a standalone real-
time process on a board that communicates with a server over
a network.  The UNIX kernel itself is another example.

To use GCT on such systems,  you  must  make  two  kinds  of
changes.   First, you must remove those parts of the library
that depend on normal UNIX I/O.  Second,  you  must  provide
another  way  to  extract  the  accumulated  instrumentation
information.

_1_2._1.  _R_e_m_o_v_i_n_g _U_N_I_X _I/_O

Do not use gct_readlog() or  gct_writelog().   Do  not  link
_g_c_t-_w_r_i_t_e._c into the final executable.

_1_2._2.  _A_l_t_e_r_n_a_t_e _I/_O

The instrumentation log is normally stored in  memory  until
written  out  by  _f_p_r_i_n_t_f  calls in _g_c_t__w_r_i_t_e_l_o_g.  Decide on
some other way of extracting the  log.   For  example,  when
instrumenting the UNIX kernel, you might simply read it from
/dev/kmem.

The log is an array named Gct_table, whose size in bytes  is
given  by  Gct_table_size.  The declarations and definitions
can be found in gct-defs.h and gct-ps-defs.c,  respectively.
You need to find a way to transfer that table to the machine
where the map file is stored.  For example,  if  _c_n_n  is  an
open network connection, you might use a call like this:

        result = write(cnn, Gct_table, Gct_table_size);

That table now needs to be  converted  into  the  form  that
greport  and  gsummary  expect.   Write a small program that
uses gct_writelog to do that.


















                       June 23, 1992





User's Manual                33  Implementation Restrictions


                Implementation Restrictions


GCT should be portable  to  any  UNIX  system  derived  from
either  Berkeley  4.X UNIX or System V Release 3 (or later).
It has also been ported to  Apollo  Sr10.3.   The  tool  was
implemented  by modifying the GNU C compiler so that it pro-
duces new C code instead of object  code.   Any  C  language
text  accepted  by that compiler can be instrumented, except
for these restrictions:

o+    The  following   global   identifiers   are   reserved:
     Gct_table,       Gct_group_table,       Gct_table_size,
     Gct_num_flags,  Gct_current_index,  gct_writelog,   and
     gct_readlog.

o+    There can be no more than  100,000,000  instrumentation
     points in the program.







































                       June 23, 1992





User's Manual                34                 Bibliography


                          Bibliography


[Beizer83]
     Boris Beizer.  _S_o_f_t_w_a_r_e _T_e_s_t_i_n_g _T_e_c_h_n_i_q_u_e_s.  New  York:
     Van Nostrand Reinhold, 1983.

[Howden78]
     W. E. Howden. 'An Evaluation of  the  Effectiveness  of
     Symbolic Testing'.  _S_o_f_t_w_a_r_e - _P_r_a_c_t_i_c_e _a_n_d _E_x_p_e_r_i_e_n_c_e,
     vol. 8, no. 4, pp. 381-398, July-August, 1978.

[Marick91]
     Brian Marick. 'Experience with the Cost of  Test  Suite
     Coverage Measures'.  _P_a_c_i_f_i_c _N_o_r_t_h_w_e_s_t _S_o_f_t_w_a_r_e _Q_u_a_l_i_t_y
     _C_o_n_f_e_r_e_n_c_e,  October,  1991.   Also  available   as   a
     compressed          postscript          file         in
     cs.uiuc.edu:/pub/testing/experience.ps.Z.

[Marick92]
     Brian Marick.  _T_h_e _C_r_a_f_t _o_f _S_o_f_t_w_a_r_e _T_e_s_t_i_n_g  and  _T_e_s_t
     _C_o_n_d_i_t_i_o_n _C_a_t_a_l_o_g, Testing Foundations, in revision.

[Myers79]
     Glenford J. Myers.  _T_h_e _A_r_t _o_f _S_o_f_t_w_a_r_e  _T_e_s_t_i_n_g.   New
     York:  John Wiley and Sons, 1979.































                       June 23, 1992





User's Manual                              Table of Contents





                     Table of Contents




Introduction ..........................................    2

A Checklist ...........................................    5

     Instrumenting a Program ..........................    6

   Directory and File Structure .......................    6

   The Control File ...................................    8

         Options ......................................   10

   Editing the Source .................................   13

   Changes to Makefiles ...............................   14

The Types of Coverage .................................   18

   Branch Coverage ....................................   20

   Multi-condition Coverage ...........................   23

   Loop Instrumentation ...............................   26

   Relational Operator Coverage .......................   27

   Routine Coverage ...................................   30

   Call Coverage ......................................   30

Instrumenting Embedded Systems ........................   32

Implementation Restrictions ...........................   33

     Bibliography .....................................   34














                       June 23, 1992


