mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 18:36:12 +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
 | 
