summaryrefslogtreecommitdiffstats
path: root/dbug/user.r
diff options
context:
space:
mode:
Diffstat (limited to 'dbug/user.r')
-rw-r--r--dbug/user.r1121
1 files changed, 1121 insertions, 0 deletions
diff --git a/dbug/user.r b/dbug/user.r
new file mode 100644
index 00000000..8d8a9ce6
--- /dev/null
+++ b/dbug/user.r
@@ -0,0 +1,1121 @@
+.\" @(#)user.r 1.13 10/29/86
+.\"
+.\" 2004-10-29: documented features implemented since 10/29/86
+.\" formatting cleanup
+.\" - Sergei Golubchik
+.\"
+.\" DBUG (Macro Debugger Package) nroff source
+.\"
+.\" nroff -mm user.r >user.t
+.\" groff -mm user.r >user.ps
+.\"
+.\" ===================================================
+.\"
+.\" === Some sort of black magic, but I forget...
+.tr ~
+.\" === Hyphenation control (1 = on)
+.\".nr Hy 1
+.\" === Force all first level headings to start on new page
+.nr Ej 1
+.\" === Set for breaks after headings for levels 1-3
+.nr Hb 3
+.\" === Set for space after headings for levels 1-3
+.nr Hs 3
+.\" === Set standard indent for one/half inch
+.nr Si 10
+.\" === Set page header
+.PH "/DBUG User Manual//\*(DT/"
+.\" === Set page footer
+.PF "// - % - //"
+.\" === Set page offset
+.\".po 0.60i
+.\" === Set line length
+.\".ll 6.5i
+.TL
+.warn 0
+D B U G
+.P 0
+C Program Debugging Package
+.P 0
+by
+.AU "Fred Fish"
+.AF ""
+.SA 1
+.\" === All paragraphs indented.
+.nr Pt 1
+.AS 1
+This document introduces
+.I dbug ,
+a macro based C debugging
+package which has proven to be a very flexible and useful tool
+for debugging, testing, and porting C programs.
+
+.P
+All of the features of the
+.I dbug
+package can be enabled or disabled dynamically at execution time.
+This means that production programs will run normally when
+debugging is not enabled, and eliminates the need to maintain two
+separate versions of a program.
+
+.P
+Many of the things easily accomplished with conventional debugging
+tools, such as symbolic debuggers, are difficult or impossible with this
+package, and vice versa.
+Thus the
+.I dbug
+package should
+.I not
+be thought of as a replacement or substitute for
+other debugging tools, but simply as a useful
+.I addition
+to the
+program development and maintenance environment.
+
+.AE
+.MT 4
+.SK
+.B
+INTRODUCTION
+.R
+
+.P
+Almost every program development environment worthy of the name
+provides some sort of debugging facility.
+Usually this takes the form of a program which is capable of
+controlling execution of other programs and examining the internal
+state of other executing programs.
+These types of programs will be referred to as external debuggers
+since the debugger is not part of the executing program.
+Examples of this type of debugger include the
+.B adb
+and
+.B sdb
+debuggers provided with the
+.B UNIX\*F
+.FS
+UNIX is a trademark of AT&T Bell Laboratories.
+.FE
+operating system.
+
+.P
+One of the problems associated with developing programs in an environment
+with good external debuggers is that developed programs tend to have
+little or no internal instrumentation.
+This is usually not a problem for the developer since he is,
+or at least should be, intimately familiar with the internal organization,
+data structures, and control flow of the program being debugged.
+It is a serious problem for maintenance programmers, who
+are unlikely to have such familiarity with the program being
+maintained, modified, or ported to another environment.
+It is also a problem, even for the developer, when the program is
+moved to an environment with a primitive or unfamiliar debugger,
+or even no debugger.
+
+.P
+On the other hand,
+.I dbug
+is an example of an internal debugger.
+Because it requires internal instrumentation of a program,
+and its usage does not depend on any special capabilities of
+the execution environment, it is always available and will
+execute in any environment that the program itself will
+execute in.
+In addition, since it is a complete package with a specific
+user interface, all programs which use it will be provided
+with similar debugging capabilities.
+This is in sharp contrast to other forms of internal instrumentation
+where each developer has their own, usually less capable, form
+of internal debugger.
+In summary,
+because
+.I dbug
+is an internal debugger it provides consistency across operating
+environments,
+and because it is available to all developers it provides
+consistency across all programs in the same environment.
+
+.P
+The
+.I dbug
+package imposes only a slight speed penalty on executing
+programs, typically much less than 10 percent, and a modest size
+penalty, typically 10 to 20 percent.
+By defining a specific C preprocessor symbol both of these
+can be reduced to zero with no changes required to the
+source code.
+
+.P
+The following list is a quick summary of the capabilities
+of the
+.I dbug
+package.
+Each capability can be individually enabled or disabled
+at the time a program is invoked by specifying the appropriate
+command line arguments.
+.SP 1
+.ML o 1i
+.LI
+Execution trace showing function level control flow in a
+semi-graphically manner using indentation to indicate nesting
+depth.
+.LI
+Output the values of all, or any subset of, key internal variables.
+.LI
+Limit actions to a specific set of named functions.
+.LI
+Limit function trace to a specified nesting depth.
+.LI
+Label each output line with source file name and line number.
+.LI
+Label each output line with name of current process.
+.LI
+Push or pop internal debugging state to allow execution with
+built in debugging defaults.
+.LI
+Redirect the debug output stream to standard output (stdout)
+or a named file.
+The default output stream is standard error (stderr).
+The redirection mechanism is completely independent of
+normal command line redirection to avoid output conflicts.
+.LE
+
+.SK
+.B
+PRIMITIVE DEBUGGING TECHNIQUES
+.R
+
+.P
+Internal instrumentation is already a familiar concept
+to most programmers, since it is usually the first debugging
+technique learned.
+Typically, "print\ statements" are inserted in the source
+code at interesting points, the code is recompiled and executed,
+and the resulting output is examined in an attempt to determine
+where the problem is.
+
+The procedure is iterative, with each iteration yielding more
+and more output, and hopefully the source of the problem is
+discovered before the output becomes too large to deal with
+or previously inserted statements need to be removed.
+Figure 1 is an example of this type of primitive debugging
+technique.
+.DS I N
+.SP 2
+\fC
+.so example1.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 1
+.ce
+Primitive Debugging Technique
+.ll +5
+.SP 2
+.DE
+
+.P
+Eventually, and usually after at least several iterations, the
+problem will be found and corrected.
+At this point, the newly inserted print statements must be
+dealt with.
+One obvious solution is to simply delete them all.
+Beginners usually do this a few times until they have to
+repeat the entire process every time a new bug pops up.
+The second most obvious solution is to somehow disable
+the output, either through the source code comment facility,
+creation of a debug variable to be switched on or off, or by using the
+C preprocessor.
+Figure 2 is an example of all three techniques.
+.DS I N
+.SP 2
+\fC
+.so example2.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 2
+.ce
+Debug Disable Techniques
+.ll +5
+.SP 2
+.DE
+
+.P
+Each technique has its advantages and disadvantages with respect
+to dynamic vs static activation, source code overhead, recompilation
+requirements, ease of use, program readability, etc.
+Overuse of the preprocessor solution quickly leads to problems with
+source code readability and maintainability when multiple
+.B #ifdef
+symbols are to be defined or undefined based on specific types
+of debug desired.
+The source code can be made slightly more readable by suitable indentation
+of the
+.B #ifdef
+arguments to match the indentation of the code, but
+not all C preprocessors allow this.
+The only requirement for the standard
+.B UNIX
+C preprocessor is for the '#' character to appear
+in the first column, but even this seems
+like an arbitrary and unreasonable restriction.
+Figure 3 is an example of this usage.
+.DS I N
+.SP 2
+\fC
+.so example3.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 3
+.ce
+More Readable Preprocessor Usage
+.ll +5
+.SP 2
+.DE
+
+.SK
+.B
+FUNCTION TRACE EXAMPLE
+.R
+
+.P
+We will start off learning about the capabilities of the
+.I dbug
+package by using a simple minded program which computes the
+factorial of a number.
+In order to better demonstrate the function trace mechanism, this
+program is implemented recursively.
+Figure 4 is the main function for this factorial program.
+.DS I N
+.SP 2
+\fC
+.so main.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 4
+.ce
+Factorial Program Mainline
+.ll +5
+.SP 2
+.DE
+
+.P
+The
+.B main
+function is responsible for processing any command line
+option arguments and then computing and printing the factorial of
+each non-option argument.
+.P
+First of all, notice that all of the debugger functions are implemented
+via preprocessor macros.
+This does not detract from the readability of the code and makes disabling
+all debug compilation trivial (a single preprocessor symbol,
+.B DBUG_OFF ,
+forces the macro expansions to be null).
+.P
+Also notice the inclusion of the header file
+.B dbug.h
+from the local header file directory.
+(The version included here is the test version in the dbug source
+distribution directory).
+This file contains all the definitions for the debugger macros, which
+all have the form
+.B DBUG_XX...XX .
+
+.P
+The
+.B DBUG_ENTER
+macro informs that debugger that we have entered the
+function named
+.B main .
+It must be the very first "executable" line in a function, after
+all declarations and before any other executable line.
+The
+.B DBUG_PROCESS
+macro is generally used only once per program to
+inform the debugger what name the program was invoked with.
+The
+.B DBUG_PUSH
+macro modifies the current debugger state by
+saving the previous state and setting a new state based on the
+control string passed as its argument.
+The
+.B DBUG_PRINT
+macro is used to print the values of each argument
+for which a factorial is to be computed.
+The
+.B DBUG_RETURN
+macro tells the debugger that the end of the current
+function has been reached and returns a value to the calling
+function.
+All of these macros will be fully explained in subsequent sections.
+.P
+To use the debugger, the factorial program is invoked with a command
+line of the form:
+.DS CB N
+\fCfactorial -#d:t 1 2 3
+.DE
+The
+.B main
+function recognizes the "-#d:t" string as a debugger control
+string, and passes the debugger arguments ("d:t") to the
+.I dbug
+runtime support routines via the
+.B DBUG_PUSH
+macro.
+This particular string enables output from the
+.B DBUG_PRINT
+macro with the 'd' flag and enables function tracing with the 't' flag.
+The factorial function is then called three times, with the arguments
+"1", "2", and "3".
+Note that the DBUG_PRINT takes exactly
+.B two
+arguments, with the second argument (a format string and list
+of printable values) enclosed in parentheses.
+.P
+Debug control strings consist of a header, the "-#", followed
+by a colon separated list of debugger arguments.
+Each debugger argument is a single character flag followed
+by an optional comma separated list of arguments specific
+to the given flag.
+Some examples are:
+.DS CB N
+\fC
+-#d:t:o
+-#d,in,out:f,main:F:L
+.DE
+Note that previously enabled debugger actions can be disabled by the
+control string "-#".
+
+.P
+The definition of the factorial function, symbolized as "N!", is
+given by:
+.DS CB N
+N! = N * N-1 * ... 2 * 1
+.DE
+Figure 5 is the factorial function which implements this algorithm
+recursively.
+Note that this is not necessarily the best way to do factorials
+and error conditions are ignored completely.
+.DS I N
+.SP 2
+\fC
+.so factorial.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 5
+.ce
+Factorial Function
+.ll +5
+.SP 2
+.DE
+
+.P
+One advantage (some may not consider it so) to using the
+.I dbug
+package is that it strongly encourages fully structured coding
+with only one entry and one exit point in each function.
+Multiple exit points, such as early returns to escape a loop,
+may be used, but each such point requires the use of an
+appropriate
+.B DBUG_RETURN
+or
+.B DBUG_VOID_RETURN
+macro.
+
+.P
+To build the factorial program on a
+.B UNIX
+system, compile and
+link with the command:
+.DS CB N
+\fCcc -o factorial main.c factorial.c -ldbug
+.DE
+The "-ldbug" argument tells the loader to link in the
+runtime support modules for the
+.I dbug
+package.
+Executing the factorial program with a command of the form:
+.DS CB N
+\fCfactorial 1 2 3 4 5
+.DE
+generates the output shown in figure 6.
+.DS I N
+.SP 2
+\fC
+.so output1.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 6
+.ce
+\fCfactorial 1 2 3 4 5
+.ll +5
+.SP 2
+.DE
+
+.P
+Function level tracing is enabled by passing the debugger
+the 't' flag in the debug control string.
+Figure 7 is the output resulting from the command
+"factorial\ -#t:o\ 2\ 3".
+.DS I N
+.SP 2
+\fC
+.so output2.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 7
+.ce
+\fCfactorial -#t:o 2 3
+.ll +5
+.SP 2
+.DE
+
+.P
+Each entry to or return from a function is indicated by '>' for the
+entry point and '<' for the exit point, connected by
+vertical bars to allow matching points to be easily found
+when separated by large distances.
+
+.P
+This trace output indicates that there was an initial call
+to factorial from main (to compute 2!), followed by
+a single recursive call to factorial to compute 1!.
+The main program then output the result for 2! and called the
+factorial function again with the second argument, 3.
+Factorial called itself recursively to compute 2! and 1!, then
+returned control to main, which output the value for 3! and exited.
+
+.P
+Note that there is no matching entry point "main>" for the
+return point "<main" because at the time the
+.B DBUG_ENTER
+macro was reached in main, tracing was not enabled yet.
+It was only after the macro
+.B DBUG_PUSH
+was executing that tracing became enabled.
+This implies that the argument list should be processed as early as
+possible since all code preceding the first call to
+.B DBUG_PUSH
+is
+essentially invisible to
+.I dbug
+(this can be worked around by
+inserting a temporary
+.B DBUG_PUSH(argv[1])
+immediately after the
+.B DBUG_ENTER("main")
+macro.
+
+.P
+One last note,
+the trace output normally comes out on the standard error.
+Since the factorial program prints its result on the standard
+output, there is the possibility of the output on the terminal
+being scrambled if the two streams are not synchronized.
+Thus the debugger is told to write its output on the standard
+output instead, via the 'o' flag character.
+Note that no 'o' implies the default (standard error), a 'o'
+with no arguments means standard output, and a 'o'
+with an argument means used the named file.
+i.e, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
+output in "logfile".
+Because of
+.B UNIX
+implementation details, programs usually run
+faster when writing to stdout rather than stderr, though this
+is not a prime consideration in this example.
+
+.SK
+.B
+USE OF DBUG_PRINT MACRO
+.R
+
+.P
+The mechanism used to produce "printf" style output is the
+.B DBUG_PRINT
+macro.
+
+.P
+To allow selection of output from specific macros, the first argument
+to every
+.B DBUG_PRINT
+macro is a
+.I dbug
+keyword.
+When this keyword appears in the argument list of the 'd' flag in
+a debug control string, as in "-#d,keyword1,keyword2,...:t",
+output from the corresponding macro is enabled.
+The default when there is no 'd' flag in the control string is to
+enable output from all
+.B DBUG_PRINT
+macros.
+
+.P
+Typically, a program will be run once, with no keywords specified,
+to determine what keywords are significant for the current problem
+(the keywords are printed in the macro output line).
+Then the program will be run again, with the desired keywords,
+to examine only specific areas of interest.
+
+.P
+The second argument to a
+.B DBUG_PRINT
+macro is a standard printf style
+format string and one or more arguments to print, all
+enclosed in parentheses so that they collectively become a single macro
+argument.
+This is how variable numbers of printf arguments are supported.
+Also note that no explicit newline is required at the end of the format string.
+As a matter of style, two or three small
+.B DBUG_PRINT
+macros are preferable
+to a single macro with a huge format string.
+Figure 8 shows the output for default tracing and debug.
+.DS I N
+.SP 2
+\fC
+.so output3.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 8
+.ce
+\fCfactorial -#d:t:o 3
+.ll +5
+.SP 2
+.DE
+
+.P
+The output from the
+.B DBUG_PRINT
+macro is indented to match the trace output
+for the function in which the macro occurs.
+When debugging is enabled, but not trace, the output starts at the left
+margin, without indentation.
+
+.P
+To demonstrate selection of specific macros for output, figure
+9 shows the result when the factorial program is invoked with
+the debug control string "-#d,result:o".
+.DS I N
+.SP 2
+\fC
+.so output4.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 9
+.ce
+\fCfactorial -#d,result:o 4
+.ll +5
+.SP 2
+.DE
+
+.P
+It is sometimes desirable to restrict debugging and trace actions
+to a specific function or list of functions.
+This is accomplished with the 'f' flag character in the debug
+control string.
+Figure 10 is the output of the factorial program when run with the
+control string "-#d:f,factorial:F:L:o".
+The 'F' flag enables printing of the source file name and the 'L'
+flag enables printing of the source file line number.
+.DS I N
+.SP 2
+\fC
+.so output5.r
+\fR
+.SP 2
+.ll -5
+.ce
+Figure 10
+.ce
+\fCfactorial -#d:f,factorial:F:L:o 3
+.ll +5
+.SP 2
+.DE
+
+.P
+The output in figure 10 shows that the "find" macro is in file
+"factorial.c" at source line 8 and the "result" macro is in the same
+file at source line 12.
+
+.SK
+.B
+SUMMARY OF MACROS
+.R
+
+.P
+This section summarizes the usage of all currently defined macros
+in the
+.I dbug
+package.
+The macros definitions are found in the user include file
+.B dbug.h
+from the standard include directory.
+
+.SP 2
+.BL 20
+.LI DBUG_ENTER\
+Used to tell the runtime support module the name of the function being
+entered. The argument must be of type "pointer to character". The
+DBUG_ENTER macro must precede all executable lines in the function
+just entered, and must come after all local declarations. Each
+DBUG_ENTER macro must have a matching DBUG_RETURN or DBUG_VOID_RETURN
+macro at the function exit points. DBUG_ENTER macros used without a
+matching DBUG_RETURN or DBUG_VOID_RETURN macro will cause warning
+messages from the
+.I dbug
+package runtime support module.
+.SP 1
+EX:\ \fCDBUG_ENTER\ ("main");\fR
+.SP 1
+.LI DBUG_RETURN\
+Used at each exit point of a function containing a DBUG_ENTER macro at
+the entry point. The argument is the value to return. Functions
+which return no value (void) should use the DBUG_VOID_RETURN macro.
+It is an error to have a DBUG_RETURN or DBUG_VOID_RETURN macro in a
+function which has no matching DBUG_ENTER macro, and the compiler will
+complain if the macros are actually used (expanded).
+.SP 1
+EX:\ \fCDBUG_RETURN\ (value);\fR
+.br
+EX:\ \fCDBUG_VOID_RETURN;\fR
+.SP 1
+.LI DBUG_PROCESS\
+Used to name the current process being executed.
+A typical argument for this macro is "argv[0]", though
+it will be perfectly happy with any other string.
+Im multi-threaded environment threads may have different names.
+.SP 1
+EX:\ \fCDBUG_PROCESS\ (argv[0]);\fR
+.SP 1
+.LI DBUG_PUSH\
+Sets a new debugger state by pushing the current
+.I dbug
+state onto an internal stack and setting up the new state using the
+debug control string passed as the macro argument. The most common
+usage is to set the state specified by a debug control string
+retrieved from the argument list. If the control string is
+.I incremental,
+the new state is a copy of the old state, modified by the control
+string.
+.SP 1
+EX:\ \fCDBUG_PUSH\ (\&(argv[i][2]));\fR
+.br
+EX:\ \fCDBUG_PUSH\ ("d:t");\fR
+.br
+EX:\ \fCDBUG_PUSH\ ("");\fR
+.SP 1
+.LI DBUG_POP\
+Restores the previous debugger state by popping the state stack.
+Attempting to pop more states than pushed will be ignored and no
+warning will be given. The DBUG_POP macro has no arguments.
+.SP 1
+EX:\ \fCDBUG_POP\ ();\fR
+.SP 1
+.LI DBUG_SET\
+Modifies the current debugger state on top of the stack or pushes
+a new state if the current is set to the initial settings, using
+the debug control string passed as the macro argument. Unless
+.I incremental
+control string is used (see below), it's equivalent to a combination of
+DBUG_POP and DBUG_PUSH.
+.SP 1
+EX:\ \fCDBUG_SET\ ("d:t");\fR
+.br
+EX:\ \fCDBUG_SET\ ("+d,info");\fR
+.br
+EX:\ \fCDBUG_SET\ ("+t:-d");\fR
+.SP 1
+.LI DBUG_FILE\
+The DBUG_FILE macro is used to do explicit I/O on the debug output
+stream. It is used in the same manner as the symbols "stdout" and
+"stderr" in the standard I/O package.
+.SP 1
+EX:\ \fCfprintf\ (DBUG_FILE,\ "Doing\ my\ own\ I/O!\\n");\fR
+.SP 1
+.LI DBUG_EXECUTE\
+The DBUG_EXECUTE macro is used to execute any arbitrary C code. The
+first argument is the debug keyword, used to trigger execution of the
+code specified as the second argument. This macro must be used
+cautiously because, like the DBUG_PRINT macro, it is automatically
+selected by default whenever the 'd' flag has no argument list (i.e.,
+a "-#d:t" control string).
+.SP 1
+EX:\ \fCDBUG_EXECUTE\ ("status",\ print_status\ ());\fR
+.SP 1
+.LI DBUG_EXECUTE_IF\
+Works like DBUG_EXECUTE macro, but the code is
+.B not
+executed "by default", if the keyword is not explicitly listed in
+the 'd' flag. Used to conditionally execute "dangerous" actions, e.g
+to crash the program testing how recovery works, or to introduce an
+artificial delay checking for race conditions.
+.SP 1
+EX:\ \fCDBUG_EXECUTE_IF\ ("crashme",\ DBUG_ABORT()\ ());\fR
+.SP 1
+.LI DBUG_EVALUATE\
+The DBUG_EVALUATE macro is similar to DBUG_EXECUTE, but it can be used in
+the expression context. The first argument is the debug keyword that is used to
+choose whether the second (keyword is enabled) or the third (keyword is not
+enabled) argument is evaluated. When
+.I dbug
+is compiled off, the third argument is evaluated.
+.SP 1
+EX:\fC
+.br
+ printf("Info-debug is %s",
+.br
+ DBUG_EVALUATE\ ("info", "ON", "OFF"));\fR
+.SP 1
+.LI DBUG_EVALUATE_IF\
+Works like DBUG_EVALUATE macro, but the second argument is
+.B not
+evaluated, if the keyword is not explicitly listed in
+the 'd' flag. Like DBUG_EXECUTE_IF this could be used to conditionally execute
+"dangerous" actions.
+.SP 1
+EX:\fC
+.br
+ if (prepare_transaction () ||
+.br
+ DBUG_EVALUATE ("crashme", (DBUG_ABORT(), 0), 0) ||
+.br
+ commit_transaction () )\fR
+.SP 1
+.LI DBUG_PRINT\
+Used to do printing via the "fprintf" library function on the current
+debug stream, DBUG_FILE. The first argument is a debug keyword, the
+second is a format string and the corresponding argument list. Note
+that the format string and argument list are all one macro argument
+and
+.B must
+be enclosed in parentheses.
+.SP 1
+EX:\ \fCDBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));\fR
+.br
+EX:\ \fCDBUG_PRINT\ ("type",\ ("type\ is\ %x", type));\fR
+.br
+EX:\ \fCDBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));\fR
+.SP 1
+.LI DBUG_DUMP\
+Used to dump a memory block in hex via the "fprintf" library function
+on the current debug stream, DBUG_FILE. The first argument is a debug
+keyword, the second is a pointer to a memory to dump, the third is a
+number of bytes to dump.
+.SP 1
+EX: \fCDBUG_DBUG\ ("net",\ packet,\ len);\fR
+.SP 1
+.LI DBUG_LOCK_FILE\
+Used in multi-threaded environment to lock DBUG_FILE stream.
+It can be used, for example, in functions that need to write something to a
+debug stream more than in one fprintf() call and want to ensure that no other
+thread will write something in between.
+.SP 1
+EX:\fC
+.br
+ DBUG_LOCK_FILE;
+.br
+ fprintf (DBUG_FILE, "a=[");
+.br
+ for (int i=0; i < a_length; i++)
+.br
+ fprintf (DBUG_FILE, "0x%03x ", a[i]);
+.br
+ fprintf (DBUG_FILE, "]");
+.br
+ DBUG_UNLOCK_FILE;\fR
+.SP 1
+.LI DBUG_UNLOCK_FILE\
+Unlocks DBUG_FILE stream, that was locked with a DBUG_LOCK_FILE.
+.LI DBUG_ASSERT\
+This macro just does a regular assert(). The difference is that it will be
+disabled by DBUG_OFF togeher with the
+.I dbug
+library. So there will be no need to disable asserts separately with NDEBUG.
+.SP 1
+EX:\ \fCDBUG_ASSERT(\ a\ >\ 0\ );\fR
+.SP 1
+.LI DBUG_ABORT\
+This macro could be used instead of abort(). It flushes DBUG_FILE stream
+to ensure that no
+.I dbug
+output is lost and then calls abort().
+.SP 1
+.LI DBUG_EXPLAIN\
+Generates control string corresponding to the current debug state.
+The macro takes two arguments - a buffer to store the result string
+into and its length. The macro (which could be used as a function)
+returns 1 if the control string didn't fit into the buffer and was
+truncated and 0 otherwise.
+.SP 1
+EX:\fC
+.br
+ char buf[256];
+.br
+ DBUG_EXPLAIN( buf, sizeof(buf) );\fR
+.SP 1
+.LI DBUG_SET_INITIAL\
+.LI DBUG_EXPLAIN_INITIAL\
+.br
+These two macros are identical to DBUG_SET and DBUG_EXPLAIN, but they
+operate on the debug state that any new thread starts from.
+Modifying
+.I initial
+value does not affect threads that are already running. Obviously,
+these macros are only useful in the multi-threaded environment.
+.LE
+
+.SK
+.B
+DEBUG CONTROL STRING
+.R
+
+.P
+The debug control string is used to set the state of the debugger
+via the
+.B DBUG_PUSH
+or
+.B DBUG_SET
+macros. Control string consists of colon separated flags. Colons
+that are part of ':\\', ':/', or '::' are not considered flag
+separators. A flag may take an argument or a list of arguments.
+If a control string starts from a '+' sign it works
+.I incrementally,
+that is, it can modify existing state without overriding it. Every
+flag may be preceded by a '+' or '-' to enable or disable a
+corresponding option in the debugger state or to add or remove
+arguments to the list. This section summarizes the currently available
+debugger options and the flag characters which enable or disable them.
+Argument lists enclosed in '[' and ']' are optional.
+.SP 2
+.BL 22
+.LI a[,file]
+Redirect the debugger output stream and append it to the specified
+file. The default output stream is stderr. A null argument list
+causes output to be redirected to stdout.
+.SP 1
+EX: \fCa,C:\\tmp\\log\fR
+.LI A[,file]
+Like 'a[,file]' but ensure that data are written after each write
+(this typically implies flush or close/reopen). It helps to get
+a complete log file in case of crashes. This mode is implicit in
+multi-threaded environment.
+.LI d[,keywords]
+Enable output from macros with specified keywords.
+Every keyword can be a
+.I glob(7)
+pattern.
+An empty list of keywords implies that all keywords are selected.
+.LI D[,time]
+Delay for specified time after each output line, to let output drain.
+Time is given in tenths of a second (value of 10 is one second).
+Default is zero.
+.LI f[,functions]
+Limit debugger actions to the specified list of functions.
+Every function can be a
+.I glob(7)
+pattern.
+An empty list of functions implies that all functions are selected.
+Every function in the list may optionally be followed by a '/' -
+this will implicitly select all the functions down the call stack.
+.SP 1
+EX: \fCf,func1,func2/:-f,func3,func4/\fR
+.SP 1
+This would enable debugger in functions 'func1()', 'func2()' and all
+functions called from it (directly or indirectly). But not in
+functions 'func3()' or 'func4()' and all functions called from
+it.
+.LI F
+Mark each debugger output line with the name of the source file
+containing the macro causing the output.
+.LI i
+Mark each debugger output line with the PID (or thread ID) of the
+current process.
+.LI L
+Mark each debugger output line with the source file line number of
+the macro causing the output.
+.LI n
+Mark each debugger output line with the current function nesting depth.
+.LI N
+Sequentially number each debugger output line starting at 1.
+This is useful for reference purposes when debugger output is
+interspersed with program output.
+.LI o[,file]
+Like 'a[,file]' but overwrite old file, do not append.
+.LI O[,file]
+Like 'A[,file]' but overwrite old file, do not append.
+.LI p[,processes]
+Limit debugger actions to the specified processes.
+Every name can be a
+.I glob(7)
+pattern.
+An empty list
+implies all processes. This is useful for processes which run child
+processes. Note that each debugger output line can be marked with the
+name of the current process via the 'P' flag. The process name must
+match the argument passed to the
+.B DBUG_PROCESS
+macro.
+.LI P
+Mark each debugger output line with the name of the current process.
+Most useful when used with a process which runs child processes that
+are also being debugged. Note that the parent process must arrange
+for the debugger control string to be passed to the child processes.
+.LI r
+Used in conjunction with the
+.B DBUG_PUSH
+macro to reset the current
+indentation level back to zero.
+Most useful with
+.B DBUG_PUSH
+macros used to temporarily alter the
+debugger state.
+.LI S
+When compiled with
+.I safemalloc
+this flag invokes "sanity" memory checks (for overwrites/underwrites)
+on each
+.B DBUG_ENTER
+and
+.B DBUG_RETURN.
+.LI t[,N]
+Enable function control flow tracing.
+The maximum nesting depth is specified by N, and defaults to
+200.
+.LI T
+Mark each debugger output line with the current timestamp.
+The value is printed with microsecond resolution, as returned by
+.I gettimeofday()
+system call. The actual resolution is OS- and hardware-dependent.
+.LE
+
+.SK
+.B
+MULTI-THREADED DEBUGGING
+.R
+
+.P
+When
+.I dbug
+is used in a multi-threaded environment there are few differences from a single-threaded
+case to keep in mind. This section tries to summarize them.
+.SP 2
+.BL 5
+.LI
+Every thread has its own stack of debugger states.
+.B DBUG_PUSH
+and
+.B DBUG_POP
+affect only the thread that executed them.
+.LI
+At the bottom of the stack for all threads there is the common
+.I initial
+state. Changes to this state (for example, with
+.B DBUG_SET_INITIAL
+macro) affect all new threads and all running threads that didn't
+.B DBUG_PUSH
+yet.
+.LI
+Every thread can have its own name, that can be set with
+.B DBUG_PROCESS
+macro. Thus, "-#p,name1,name2" can be used to limit the output to specific threads.
+.LI
+When printing directly to
+.B DBUG_FILE
+it may be necessary to prevent other threads from writing something between two parts
+of logically indivisible output. It is done with
+.B DBUG_LOCK_FILE
+and
+.B DBUG_UNLOCK_FILE
+macors. See the appropriate section for examples.
+.LI
+"-#o,file" and "-#O,file" are treated as "-#a,file" and "-#A,file" respectively. That is
+all writes to a file are always followed by a flush.
+.LI
+"-#i" prints not a PID but a thread id in the form of "T@nnn"
+.LE
+
+.SK
+.B
+
+HINTS AND MISCELLANEOUS
+.R
+
+.P
+One of the most useful capabilities of the
+.I dbug
+package is to compare the executions of a given program in two
+different environments.
+This is typically done by executing the program in the environment
+where it behaves properly and saving the debugger output in a
+reference file.
+The program is then run with identical inputs in the environment where
+it misbehaves and the output is again captured in a reference file.
+The two reference files can then be differentially compared to
+determine exactly where execution of the two processes diverges.
+
+.P
+A related usage is regression testing where the execution of a current
+version is compared against executions of previous versions.
+This is most useful when there are only minor changes.
+
+.P
+It is not difficult to modify an existing compiler to implement
+some of the functionality of the
+.I dbug
+package automatically, without source code changes to the
+program being debugged.
+In fact, such changes were implemented in a version of the
+Portable C Compiler by the author in less than a day.
+However, it is strongly encouraged that all newly
+developed code continue to use the debugger macros
+for the portability reasons noted earlier.
+The modified compiler should be used only for testing existing
+programs.
+
+.SK
+.B
+CAVEATS
+.R
+
+.P
+The
+.I dbug
+package works best with programs which have "line\ oriented"
+output, such as text processors, general purpose utilities, etc.
+It can be interfaced with screen oriented programs such as
+visual editors by redefining the appropriate macros to call
+special functions for displaying the debugger results.
+Of course, this caveat is not applicable if the debugger output
+is simply dumped into a file for post-execution examination.
+
+.P
+Programs which use memory allocation functions other than
+.B malloc
+will usually have problems using the standard
+.I dbug
+package.
+The most common problem is multiply allocated memory.
+.SP 2
+.\" .DE nroff dident like this. davida 900108
+.CS
+
+.\" vim:filetype=nroff