diff options
Diffstat (limited to 'dbug/user.r')
-rw-r--r-- | dbug/user.r | 1121 |
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 |