DrC's Inline Debugger facilitates debugging C and C++ code. The programmer
instruments his or her code with "disappearing macros" which give the
programmer flexibility:
the debugger calls are compiled in if -DDEBUG is in the compile command, or
the debugger calls are compiled in if #define DEBUG is at the top of the file,
otherwise the code is compiled as if the debugger's calls are not present!
Your source code should have
#include "dbg.h"in every file using DrChip's debugging calls.
The debugger, even if compiled in, doesn't activate unless a -@ command is given on the command line. Then the programmer may issue commands to turn debugging on selectively by function and detail level, directing debugging output to one or more files.
DrC's internal inline debugger allows programmers to install debugging-smarts into their code without impacting the final production executables. As a result debugging output can be formatted to improve usability to the programmer. Often a problem's effect is found thousands of executed lines after the cause, and external debuggers don't allow easy backtracking. By redirecting debugging output to a file with DrC's internal debugger, one may have a history of helpful comments and important variable states recorded while suppressing unwanted debugger output.
You may get the source by clicking on DrC's Inline Debugger Source.
The Makefile included with the debugger's source code distribution makes the "xtdio.a" library and compiles an example using DrC's Inline Debugger. If you run this example as shown (by selectively turning on debugging for function f3), you'll see:
example -@ "on f3 1" f3(j=3){ |[res=1]*=[j=3]=3 |[res=3]*=[j=2]=6 |[res=6]*=[j=1]=6 |return f3 6 }
I also have a Vim-based syntax highlighting file for DrC's Inline Debugger; you may get it by clicking on dbg.vim.gz. The following shows what the output of the debugger looks like in Vim:
f3(j=3){ |[res=1]*=[j=3]=3 |[res=3]*=[j=2]=6 |[res=6]*=[j=1]=6 |return f3 6 }
Typically one instruments the source code with calls like
Edbg(("funcname(arg=%d)",arg));
at the beginning of every function and
Rdbg(("funcname %d",retval));
just before every return point in each function.
Note that the string and arguments style is patterned off
of C-style printf(). In addition, where one thinks it
appropriate, put in additional debugging statements like
Dprintf((1,"whatever=%d",iwhatever));
The 1 is a debugging level; at runtime, you will be able to control the level of debugging detail coming out of the debugger (see edbg, rdbg, and dprintf).
The debugging system is internally energized by calling
initdbg(&argc,argv);
early on in the main program. Externally, when you run the program,
-@ dbgfile [dbgfile2 ...] [# [#]]
or
-@ "{on|ondis|keep|off} funcname [*] [detail-level] [:dtst1 [:dtst2]] [preq list]"
will enable the debugger. The initdbg() looks for that -@
and processes a dbgfile in the first case and actual debugger
commands in the second case. A dbgfile merely consists of one or more
debugger command lines and simplifies keeping specialized groups of
debugging commands.
The two optional numbers :dtst1
and :dtst2
are
also read into the global variables dtst1 and dtst2. If the optional numbers are
not present on the command line, then both will be set to DBG_DTSTOFF, which
currently is -2. Note: debug files may not begin with an integer or minus sign.
The presence of a debugger command as opposed to the name of a dbgfile
is detected by determining if the dbgfile-name/debugger-command string began
with "on" or "off"; if so, the string is treated as a debugger command
and passed on to initdbg3()
.
The debugging system exhibits function-level control over printing of debugging information. The dbgmode contains three pieces of information: a detail level (between 0 to 15), whether or not debugging is currently active (ie. on), and whether debugging is to be inherited by deeper functions. Debugging output is preceded by a number of bars indicating the current debugging function depth.
The debug file contains lines following one of the following forms:
{on|ondis|off} funcname [*] [detail-level] [:dtst1 [:dtst2]] [preq list] [> file]
keep funcname [:dtst1 [:dtst2]]
del [funcname | *]
[proc | thrd]
Debugging Command | : | Description | |
on|off | : | during program flow, debugging will be turned on/off | |
if the associated function name (funcname) is encountered. | |||
keep | : | don't modify debugging status, but allow changes to dtst1,2 | |
ondis | : | debugging for the given function is unchanged, but | |
dbgswitch() can be used to turn it on (on but disabled) | |||
funcname | : | debugging information concerns this function name | |
* | : | debugging mode will not be inherited by deeper | |
routines (default: debug mode will be inherited) | |||
detail-level | : | debugging detail levels are in the interval [0,15], | |
with 0 as default (and least detail). | |||
:dtst1 | : | a colon-number signifies a dtst1 value | |
:dtst2 | : | a colon-number signifies a dtst2 value | |
preq-list | : | a list of function names, optionally preceded with no | |
intervening white space by a "!". These functions must | |||
be present in the current routine stack (or not present | |||
if preceded by a "!") for the debugging command to be fire. | |||
> filename | : | debugging output will be directed to this file. It | |
will be opened once, and debugging output appended to, | |||
the given file. | |||
del funcname | : | delete debugging info on funcname from debugging system | |
del * | : | delete all debugging info from debugging system | |
proc | : | precede every debugging line with the process pid | |
thrd | : | precede every debugging line with the thread id |
There's more than edbg(), rdbg(), and dprintf()! Each of these functions have "macro((...))" variants which are "disappearing" versions controlled via the C/C++ preprocessor (in particular, Edbg(()), Rdbg(()), and Dprintf(()) ).
That is, if -DDEBUG is on the command line (or #define DEBUG is in the code), the inline debugger's "disappearing macros" are available, otherwise the preprocessor will eliminate them. Makes it easy to get that production version but keep the inline debugger instrumentation available for when you really need it!
Dbgswitch((...))
int dbgswitch(int on)
If dtst1 and optionally dtst2 were entered on the command line, then dbgswitch can be used to further delineate debugging selection. Basically, dbgswitch takes a true/false (0=false, other=true) and will turn dbgmode on/off as indicated. dtst1 and dtst2 may, of course, be used in the test.
Dbgtst((...))
int dbgtst(int detail)
This function tests to see if a dprintf() at the specified detail level would print or not.
Dprintf((...))
int dprintf(int detail,char *fmt,...)
dprintf(detail-level,"...",...): except for the first integer argument, this function appears like a member of the printf() family. The detail-level is an integer between 0 to 15. The data will be printed with the usual leading dots indicating routine depth. This function returns a 1 if debugging is enabled, 0 else.
Edbg((...))
void edbg(char *fmt,...)
edbg("funcname(...)",...): the function appears like a member of the printf() family, except that the string must begin with a funcname. The funcname is checked against the debug file info and, if the funcname appears in the debugging database, the dbgmode is modified appropriately. This call is to be placed at the beginning of every function (to be debugged); it signifies that the function has been entered. The string will be printed if the dbgmode so indicates at a detail-level of zero.
Initdbg((...))
void initdbg(int *argc,char **argv)
Call initdbg("argc,argv) at the beginning of the main program.
Initdbg2((...))
void initdbg2(char *dbgfile)
The function processes all the lines in the dbgfile using initdbg3. It is called by initdbg().
Initdbg3((...))
void initdbg3(char *buf)
The function processes a single line, usually provided by initdbg2(), and modifies the debugging database.
Prt_dbgstr((...))
void prt_dbgstr()
Prints out the entire debugging database. This function is useful for documenting a particular debugging run with what debugging information was used.
Prt_traceback((...))
void prt_traceback()
prints the current routine stack (quaintly known as a traceback)
Rdbg((...))
void rdbg(char *fmt,...)
rdbg("funcname ...",...): the function appears like a member of the printf() family, except that the format string must begin with the current funcname. This call is to be placed just before every return point; it signifies that the function is returning. The string will be printed if the dbgmode so indicates at a detail-level of zero.
proc
thrd
A "proc" command tells the debugger to precede debugging output with the process id
of the process generating the information.
Likewise, a "thrd" command does the same sort of thing but using the thread id.
After the debugging output file has been generated, one can separate the output
that each process/thread generated.
Last Modified May 20, 2023 01:52:33 AM | © 2012, Charles E Campbell |