mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
1109 lines
31 KiB
R
1109 lines
31 KiB
R
.\" @(#)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_IF\
|
|
Returns
|
|
.B 1
|
|
if the keyword is explicitly listed in
|
|
the 'd' flag. Otherwise returns
|
|
.B 0
|
|
Like DBUG_EXECUTE_IF this could be used to conditionally execute
|
|
"dangerous" actions.
|
|
.SP 1
|
|
EX:\fC
|
|
.br
|
|
if (prepare_transaction () ||
|
|
.br
|
|
(DBUG_IF("crashme") && (DBUG_ABORT(), 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 together 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 didn't like this. davida 900108
|
|
.CS
|
|
|
|
.\" vim:filetype=nroff
|