home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!cimshop!davidm
- From: davidm@consilium.com (David S. Masterson)
- Newsgroups: comp.lang.c++
- Subject: Re: Debugging output
- Message-ID: <DAVIDM.92Nov7163528@consilium.com>
- Date: 8 Nov 92 00:35:28 GMT
- References: <Bx93Mr.42r@cs.uiuc.edu> <5174@holden.lulea.trab.se>
- Sender: root@cimshop.UUCP
- Distribution: comp
- Organization: Consilium Inc., Mountain View, California
- Lines: 389
- In-reply-to: jbn@lulea.trab.se's message of 6 Nov 92 18:05:07 GMT
- X-Posting-Software: GNUS 3.13 [ NNTP-based News Reader for GNU Emacs ]
-
- >>>>> On 6 Nov 92 18:05:07 GMT, jbn@lulea.trab.se (Johan Bengtsson) said:
-
- > I much prefer saying
-
- > DEBUG( cerr << "here\n" );
-
- > Much easier to see what is going on (IMHO), and useful for other things
- > than printouts.
-
- > #ifndef NDEBUG
- > # define DEBUG(expr) if ( debug ) (expr)
- > #else
- > # define DEBUG(expr) (0)
- > #endif
-
- > Note that DEBUG code is generated per default. Reversing that is trivial.
-
- A very simple approach to debugging, but a very useful one. In that vein, I
- got the idea for the below Tracer object from the ARM (chapter 3, I think) a
- few years ago. Since you wanted to know about debugging and I saw this idea
- recently discussed by Andrew Koenig in JOOP, I thought I'd post this version
- of the Tracer object. The capabilities of this object are:
-
- 1. Print out function entry/exit of interesting functions.
- 2. Print out of interesting information.
- 3. Attach #2 messages to a bit flag.
- 4. Print out messages of specific bit flag(s).
- 5. Print out messages within context of a function.
- 6. Turn on and off tracing temporarily.
- 7. Compile out tracing code altogether.
-
- I've added a number of things since this version of the code:
-
- 1. Messages can be output to other than cout.
- 2. Environment variables can override initial tracing state.
- (tried reading environment variable often so tracing could be changed,
- but the getenv() cost was too great ;-)
-
- Anyway, here's the code. Enjoy!
-
- #!/bin/sh
- # This is a shell archive (produced by shar 3.49)
- # To extract the files from this archive, save it to a file, remove
- # everything above the "!/bin/sh" line above, and type "sh file_name".
- #
- # made 11/08/1992 00:17 UTC by davidm@prometheus
- # Source directory /slab/davidm/tmp
- #
- # existing files will NOT be overwritten unless -c is specified
- #
- # This shar contains:
- # length mode name
- # ------ ---------- ------------------------------------------
- # 5066 -rw-r--r-- tracer.cxx
- # 4466 -rw-r--r-- tracer.hxx
- #
- # ============= tracer.cxx ==============
- if test -f 'tracer.cxx' -a X"$1" != X"-c"; then
- echo 'x - skipping tracer.cxx (File already exists)'
- else
- echo 'x - extracting tracer.cxx (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'tracer.cxx' &&
- /*
- ** File - tracer.cxx
- */
- X
- #ifndef TRACER_HXX
- #include "tracer.hxx"
- #endif
- X
- #include <iostream.h>
- #include <string.h>
- X
- X
- // ****************************************************************:
- // Tracer
- //
- // Description:
- // Initialize local as well as static information. Set up
- // for total cleanup at destruction. Also outputs Tracer
- // to stream using operator<<. Implicit assumption is that
- // this is only called once per run of a program.
- // ****************************************************************:
- Tracer::Tracer(char* s, const int n)
- {
- X prog = func = s; // Set program name
- X mode = n; // Initialize the tracing mode (no default).
- X lmode = 1; // Recognize this as top-level.
- X
- X if (mode) // Should we output?
- X cout << *this << ": entered" << endl;
- }
- X
- X
- // ****************************************************************:
- // Tracer
- //
- // Description:
- // Initialize only local information. No total cleanup
- // at destuction. Also outputs Tracer to stream using
- // operator<<. Also checks to see if input character
- // string contains information that Tracer is watching
- // for and turns tracing on if it does. Implicit assumption
- // is that this is the way Tracer will be set up when needed.
- // ****************************************************************:
- Tracer::Tracer(char* s)
- {
- X func = s; // Leave program alone, but set function
- X
- X if (watch != 0) // Watching something?
- X {
- X if (strstr(func, watch) != 0) // Watching for this?
- X { // yes...
- X lmode = mode; // remember global mode locally
- X mode = -1; // turn tracing on
- X }
- X }
- X else // no...
- X lmode = 0; // set local mode to not top level
- X
- X if (mode) // Should we output?
- X cout << *this << ": entered" << endl;
- }
- X
- X
- // ****************************************************************:
- // ~Tracer
- //
- // Description:
- // Check for totalcleanup flag and cleanup.
- // Also outputs Tracer to stream using operator<<.
- // ****************************************************************:
- Tracer::~Tracer()
- {
- X if (mode) // Should we output?
- X cout << *this << ": exitted" << endl;
- X
- X if (watch != 0) // Watching something?
- X {
- X if (strstr(func, watch) != 0) // Watching for the function?
- X { // yes...
- X mode = lmode; // reset remembered global mode
- X lmode = 0; // this is not the top level
- X }
- X }
- X
- X if (lmode) // Is this top level?
- X TotalCleanup();
- }
- X
- X
- // ****************************************************************:
- // TotalCleanup
- //
- // Description:
- // Do what's needed to finally cleanup Tracer.
- // For instance, might be a close of a log file.
- // ****************************************************************:
- void
- Tracer::TotalCleanup()
- {
- X if (watch)
- X delete watch;
- }
- X
- X
- // ****************************************************************:
- // SetMode
- //
- // Description:
- // Change the global mode of Tracer.
- // ****************************************************************:
- void
- Tracer::SetMode(const int n)
- {
- X mode = n; // new mode
- }
- X
- X
- // ****************************************************************:
- // GetMode
- //
- // Description:
- // Determine the current global mode of Tracer.
- // ****************************************************************:
- int
- Tracer::GetMode()
- {
- X return mode; // what is the mode?
- }
- X
- X
- // ****************************************************************:
- // SetWatch
- //
- // Description:
- // Set a function name to watch trace on.
- // ****************************************************************:
- void
- Tracer::SetWatch(char* name)
- {
- X if (watch)
- X delete watch;
- X
- X watch = new char[strlen(name)];
- X strcpy(watch, name);
- }
- X
- X
- // ****************************************************************:
- // GetWatch
- //
- // Description:
- // Return the current function being watched for.
- // ****************************************************************:
- char*
- Tracer::GetWatch()
- {
- X return watch; // what we're watching for
- }
- X
- X
- // ****************************************************************:
- // Operator<<
- //
- // Description:
- // Puts Tracer into an output stream.
- // ****************************************************************:
- ostream&
- operator<<(ostream& str, Tracer& x)
- {
- X return str << x.func; // output the Tracer object to stream
- }
- SHAR_EOF
- chmod 0644 tracer.cxx ||
- echo 'restore of tracer.cxx failed'
- Wc_c="`wc -c < 'tracer.cxx'`"
- test 5066 -eq "$Wc_c" ||
- echo 'tracer.cxx: original size 5066, current size' "$Wc_c"
- fi
- # ============= tracer.hxx ==============
- if test -f 'tracer.hxx' -a X"$1" != X"-c"; then
- echo 'x - skipping tracer.hxx (File already exists)'
- else
- echo 'x - extracting tracer.hxx (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'tracer.hxx' &&
- /*
- ** Tracer object
- **
- ** Purpose:
- ** Mostly for tracing function calls, but may be adapted for
- ** logging a trace of a program to somewhere else.
- */
- X
- #ifndef TRACER_HXX
- #define TRACER_HXX
- X
- // .NAME Tracer - class to manage providing a trace of functions.
- // .LIBRARY util
- // .HEADER Utility Classes
- // .INCLUDE tracer.hxx
- // .FILE tracer.hxx
- // .FILE tracer.cxx
- X
- // .SECTION Description
- // This class makes use of some of the semantics of C++ to provide
- // a convenient way of tracing function calls. This code was initially
- // suggested by Bjarne Stroustrup, but has now been modified to allow
- // control of when tracing takes place. Tracing messages are sprinkled
- // about the user's code and, at the user's choosing, the type of
- // tracing is enabled. Users of this object class will rarely (if
- // ever) directly see the class. Instead, they will use the macro
- // interface defined with this class.
- X
- // .SECTION Tracing Types
- // Tracer may be set to output its tracing information according to the
- // type of mode it has been put into. At the simplest level, Tracer may
- // be set to output all tracing information by setting its type to -1
- // (which is what TRACE_ON does). At the next level, messages that
- // Tracer is told about may be given a positive integer type < 32.
- // Tracer may also be set to output only messages that are of certain
- // types (via bitwise AND of current type with message type). Users
- // can, therefore, monitor all types of messages, some of the types,
- // or just one of the types depending on the user's interest. The final
- // level is that a user may turn on monitoring of a function call by
- // telling Tracer the name of the function to WATCH. When Tracer hits
- // the function in question, it turns TRACE_ON and turns TRACE_OFF when
- // it leaves the function (so, all lower functions are also traced).
- X
- #include <iostream.h>
- X
- X
- class Tracer
- {
- public:
- X Tracer(char*, const int); // Full tracer invocation
- X Tracer(char*); // Lower level invocation
- X
- X ~Tracer(); // Close tracer invocation
- X
- X void TotalCleanup(); // Clean up when fully done
- X
- X void SetMode(const int); // Set current mode of tracing
- X int GetMode(); // Determine current tracing mode
- X
- X void SetWatch(char*); // Function name to begin tracing in
- X char* GetWatch(); // What we are watching for?
- X
- X friend ostream& operator<<(ostream&, Tracer&);
- X // Output tracing information
- X
- private:
- X char* func; // function being worked on
- X int lmode; // local mode of Tracer
- X static char* prog; // program being worked on
- X static int mode; // global mode of Tracer
- X static char* watch; // function to watch for and trace
- X
- };
- X
- X
- // ****************************************************************
- // Macro Interface to Tracer Object
- // ****************************************************************
- #ifndef NDEBUG
- X
- #define FTRACER(s,n) /* Trace program s with type n */\
- X Tracer _trace(s, n);
- X
- #define TRACER(s) /* Trace function s */\
- X Tracer _trace(s);
- X
- #define TRACE(s) /* If TRACE_ON then output s */\
- X if (_trace.GetMode()) cout << _trace << ": " << s << endl;
- X
- #define TRACEF(f) /* If TRACE_ON then call function f */\
- X if (_trace.GetMode()) f;
- X
- #define TRACE_ON /* Turn tracing on */\
- X _trace.SetMode(-1);
- X
- #define TRACE_OFF /* Turn tracing off */\
- X _trace.SetMode(0);
- X
- #define LTRACE(l,s) /* If (TRACE_ON || type & l) then output s */\
- X if (_trace.GetMode() < 0 || _trace.GetMode() & l) \
- X cout << _trace << ": " << s << endl;
- X
- #define LTRACEF(l,f) /* If (TRACE_ON || type & l) then call function f */\
- X if (_trace.GetMode() < 0 || _trace.GetMode() & l) f;
- X
- #define STRACE(m) /* Set tracing to type m */\
- X _trace.SetMode(m);
- X
- #define WATCH(s) /* Set function to watch to s */\
- X _trace.SetWatch(s);
- X
- #else
- X
- #define FTRACER(s,n) /**/
- #define TRACER(s) /**/
- #define TRACE(s) /**/
- #define TRACE_ON /**/
- #define TRACE_OFF /**/
- #define LTRACE(l,s) /**/
- #define LTRACEF(l,s) /**/
- #define STRACE(m) /**/
- #define WATCH(s) /**/
- X
- #endif
- X
- #endif
- SHAR_EOF
- chmod 0644 tracer.hxx ||
- echo 'restore of tracer.hxx failed'
- Wc_c="`wc -c < 'tracer.hxx'`"
- test 4466 -eq "$Wc_c" ||
- echo 'tracer.hxx: original size 4466, current size' "$Wc_c"
- fi
- exit 0
- --
- ====================================================================
- David Masterson Consilium, Inc.
- (415) 691-6311 640 Clyde Ct.
- davidm@consilium.com Mtn. View, CA 94043
- ====================================================================
- People were out there looting their asses off... When they saw us,
- they shouted, `Viva Bush!'
- -- A US soldier present at the invasion of Panama.
-