home *** CD-ROM | disk | FTP | other *** search
- _A MINIMAL OBJECT-ORIENTED DEBUGGER FOR C++_
- by William M. Miller
-
- [LISTING ONE]
-
- // MOOD.hxx by William M. Miller, 8/3/91. MOOD user declarations.
-
- /* This header file is included in every module which is to be metered
- * by MOOD. Its actions are controlled by the preprocessor variable
- * DEBUGGER_ON. If not this is not defined, no debugger actions will occur.
- */
- #ifndef _DEBUGGER_DEFS
- #define _DEBUGGER_DEFS
- // Conditions under which cond_break may be called:
- enum break_condition {
- PROG_START, PROG_END, FCN_ENTRY, FCN_EXIT, OBJ_CTOR, OBJ_DTOR,
- USER_BP
- };
-
- /* The cond_break() function is called in all the above contexts for two
- * purposes: 1) to display trace information when verbose mode is on, and
- * 2) to break under the appropriate conditions to allow the user to
- * interact with the debugger. The default arguments are to allow a user
- * program to contain the call "cond_break();" with no arguments to perform
- * an unconditional breakpoint into the debugger's interactive mode.
- */
- void cond_break(break_condition cond = USER_BP, const char* name = 0,
- void* addr = 0);
-
- /* The trace class is intended to allow function tracing. Each function or
- * block which should be included in the trace should declare an object of
- * class trace at the very beginning. The result, in verbose mode, will be
- * to display the function/block name at entry and exit; this name can also
- * be used to set a breakpoint from the debugger's interactive mode.
- */
- class trace {
- public:
- #ifdef DEBUGGER_ON
- trace( const char* fcn_name): _name(fcn_name)
- { cond_break( FCN_ENTRY, _name); }
- ~trace( ) { cond_break( FCN_EXIT, _name); }
- private:
- const char* _name;
- #else
- trace( const char* ) { }
- #endif
- };
-
- /* The monitored class is intended for use as a virtual base class of any
- * classes whose construction/destruction is to be traced in verbose mode
- * or whose values are to be displayed interactively. Derived classes must
- * pass the object or class name to the constructor and must supply an
- * override to the display() member function.
- */
- class monitored {
- public:
- #ifdef DEBUGGER_ON
- monitored( const char* obj_name ): _name(obj_name)
- { cond_break(OBJ_CTOR, _name, this); };
- ~monitored( ) { cond_break(OBJ_DTOR, _name, this); }
- virtual void display() = 0;
- private:
- monitored() { } // keep cfront 2.0 happy -- it requires a default
- // constructor in virtual base classes for no good reason.
- const char* _name;
- #else
- monitored( const char* ) { }
- monitored( ) { }
- #endif
- };
-
- /* The following class and static object call cond_break exactly once at
- * program start, before any debuggable object is created, to allow the
- * user to set up tracing and breakpoints, and once at the end of execution
- * to allow for any needed cleanup.
- */
- #ifdef DEBUGGER_ON
- class init_ctl {
- public:
- init_ctl( ) { if (_count++ == 0) cond_break(PROG_START); }
- ~init_ctl( ) { if (--_count == 0) cond_break(PROG_END); }
- private:
- static int _count;
- };
-
- static init_ctl dbg_init;
- #endif
- #endif
-
-
- [LISTING TWO]
-
- // tdbg.cxx by William M. Miller, 8/3/91. This is a sample
- // program to be debugged with MOOD. A transcript of the debugging
- // session is shown in Example 3, accompanying this article.
-
- extern "C" {
- #include <stdio.h>
- }
- #include "MOOD.hxx"
-
- struct foo: virtual monitored {
- foo( const char* nm ): monitored(nm), my_name(nm) { }
- void display( ) { fprintf(stderr, "%s\n", my_name); }
- const char* my_name;
- };
- void x();
- void y();
- void z();
-
- int main() {
- trace tt("main");
- foo* p = new foo("*p");
- x();
- z();
- delete p;
- return 0;
- }
-
- void x() {
- trace tt("x");
- foo xf("xf");
- y();
- }
-
- void y() {
- trace tt("y");
- foo yf("yf");
- }
-
- void z() {
- trace tt("z");
- foo zf("zf");
- }
-
-
- [LISTING THREE]
-
- // MOOD.cxx, by William M. Miller, 8/3/91. MOOD kernel definitions.
-
- /* This routine implements the user interface of MOOD, the Minimal Object
- * Oriented Debugger. Example 2 in the accompanying article describes
- * currently available commands: s, g, d, v, and q.
- */
- extern "C" {
- #include <stdio.h>
- #include <string.h>
- }
- #define DEBUGGER_ON 1
- #include "MOOD.hxx"
-
- /* The objp() function does a system-dependent conversion of an ASCII pointer
- * specification into a pointer to a monitored object.
- */
- monitored* objp(const char* str);
-
- /* The cond_break() function is called under the various circumstances
- * described by the enumeration break_condition. It prints a message, if
- * required, describing the reason for its call, and optionally enters
- * interactive mode to take commands.
- */
- void cond_break(break_condition cond, const char* name, void* addr) {
-
- static int tracing = 0; // => verbose mode
- static char brk_name[128] = ""; // name on which to break
- static int was_step = 1; // last cmd was "step" => go to
- // interactive mode
- char buff[128]; // command line buffer
-
- /* We enter the display and possible interactive mode code under the following
- * conditions:
- * 1) We are tracing (verbose mode).
- * 2) We are stepping. (Note: this is initially TRUE, which takes care of
- * getting into interactive mode on the PROG_START call.)
- * 3) The breakpoint name was set and the current name matches it, or this
- * is a user breakpoint call with no name
- * 4) The breakpoint name was not set and this is a user breakpoint call.
- */
- if (tracing || was_step ||
- (brk_name[0] && ((strcmp(brk_name, name) == 0) ||
- (cond == USER_BP && !name))) || (!brk_name[0] && cond == USER_BP)) {
-
- switch(cond) { // Print an appropriate message:
-
- case PROG_START:
- fprintf(stderr,"MOOD: Minimal Object Oriented Debugger, V. 0.0\n");
- break;
- case PROG_END: fprintf(stderr, "End of execution.\n"); break;
-
- case FCN_ENTRY: fprintf(stderr, "Enter %s\n", name); break;
-
- case FCN_EXIT: fprintf(stderr, "Exit %s\n", name); break;
-
- case OBJ_CTOR: fprintf(stderr, "Construct %s @ %p\n", name, addr);
- break;
- case OBJ_DTOR: fprintf(stderr, "Destruct %s @ %p\n", name, addr);
- break;
- case USER_BP: fprintf(stderr, "Breakpoint %s (%p)\n", name, addr);
- break;
- } // switch
-
- /* We enter interactive mode if any of the above conditions other than
- * tracing is met. (This implies that named user breakpoints are skipped
- * if the user uses a g <name> command in which the name does not match
- * the breakpoint name, but that unnamed user breakpoints are always
- * effective, as are named user breakpoints after a g command with no name.)
- */
- if (was_step || (brk_name[0] && ((strcmp(brk_name, name) == 0) ||
- (cond == USER_BP && !name))) ||
- (!brk_name[0] && cond == USER_BP)) {
-
- // Reset breakpoint conditions
- was_step = 0;
- brk_name[0] = 0;
-
- // Main command loop
- do {
- fprintf(stderr, "cmd> ");
- gets(buff);
- switch(buff[0]) {
-
- case 'd': objp(buff + 2)->display(); break;
- case 'g': if (buff[1]) strcpy(brk_name, buff + 2); break;
- case 'q': tracing = 0; break;
- case 's': was_step = 1; break;
- case 'v': tracing = 1; break;
- } // switch
-
- } while(buff[0] != 's' && buff[0] != 'g');
- } // if (interactive)
- } // if (message)
- } // cond_break()
-
- monitored* objp(const char* str) {
- monitored* p;
- sscanf(str, "%p", &p);
- return p;
- }
-
- int init_ctl::_count;
-
-
-