/* Copyright (C) 1992 by Brian Marick. All rights reserved. */ /* * When aggregated with works covered by the GNU General Public License, * that license applies to this file. Brian Marick retains the right to * apply other terms when this file is distributed as a part of other * works. See the GNU General Public License (version 2) for more * explanation. */ #include /* $Header: /usr/export/home/marick/RCS/gct-contro.h,v 1.9 1992/08/29 18:11:33 marick Exp $ */ /* * This file contains the code used to control what GCT does. The * general design is as follows. * * 1. There are four contexts for options. Options can apply globally, * to a particular file, to a particular routine within a particular * file, or from a particular point in a file until the end of the file. * * 2. The first three contexts are specified by the control file; the * last serves as a cache during the instrumentation of a routine. * * 3. The contexts are arranged in a "binding stack". The cache * context is searched first, the routine context next, the file context * next, and the global context last. * * 4. The compiler front end (gct) uses the global context to decide * what files to instrument. CC1 is called on a particular file, which * it pushes on the context stack. As it discovers routines, it pushes * their context on the context stack; however, it always pushes them * *under* the cache context. This is for historical reasons -- the * cache context was once intended to be manipulated by in-line comments: * could involve pushing and popping values of particular options. * * 6. Options have three values, ON, OFF, and NONE. NONE means to * search up the context stack. It is a program error for any option in * the global context to have a NONE value. * * 7. The cache context caches only instrumentation options. Other * options have value NONE, so the search continues in higher-level * context. Thus, the cache can be used invisibly. If you KNOW you're * inside a routine -- and thus that the cache is active -- and you KNOW * the value you're looking for is cached, the cache context can be * accessed directly. * */ /* There are four elements, with distinct names, in the context stack. */ #define GLOBAL_CONTEXT 0 #define FILE_CONTEXT 1 #define ROUTINE_CONTEXT 2 #define CACHE_CONTEXT 3 #define NUM_CONTEXTS 4 #define CONTEXT_IN_RANGE(context)\ ((context)>=0 && (context)options[OPT_INSTRUMENT].value) #define add_writelog_on() (ON == Context_stack[CACHE_CONTEXT]->options[OPT_WRITELOG].value) #define add_readlog_on() (ON == Context_stack[CACHE_CONTEXT]->options[OPT_READLOG].value) /* * Instrumentation values. Note that they return false if * instrumentation_on() is false. This is because a routine may be * processed when instrumentation is OFF - to insert calls to gct_readlog * and gct_writelog. Therefore, you cannot add branch coverage when you * see an IF unless you know that instrumentation is also on. * */ #define branch_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_BRANCH].value) #define multi_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_MULTI].value) #define loop_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_LOOP].value) #define operator_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_OPERATOR].value) #define operand_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_OPERAND].value) #define routine_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_ROUTINE].value) #define relational_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_RELATIONAL].value) #define call_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_CALL].value) #define race_on() ( instrumentation_on() \ && ON == Context_stack[CACHE_CONTEXT]->options[OPT_RACE].value)