debug.html revision 90792
1<html>
2<head>
3    <title>libsm : Debugging and Tracing</title>
4</head>
5<body>
6
7<a href="index.html">Back to libsm overview</a>
8
9<center>
10    <h1> libsm : Debugging and Tracing </h1>
11    <br> $Id: debug.html,v 1.8 2000/12/08 21:41:41 ca Exp $
12</center>
13
14<h2> Introduction </h2>
15
16The debug and trace package provides abstractions for writing trace
17messages, and abstractions for enabling and disabling debug and
18trace code at run time.
19
20<p>
21Sendmail 8.11 and earlier has a <tt>-d</tt> option which 
22lets you turn on debug and trace code.
23Debug categories are integers from 0 to 99, with the sole exception
24of "ANSI", which is a named debug category.
25
26<p>
27The libsm debug package supports named debug categories.
28Debug category names have the form of C identifiers.
29For example, <tt>sm_trace_heap</tt> controls the output of trace
30messages from the sm heap package, while <tt>sm_check_heap</tt>
31controls the argument validity checking and memory leak detection
32features of the sm heap package.
33
34<p>
35In sendmail 8.12, the <tt>-d</tt> flag is generalized
36to support both the original style numeric categories, for backwards
37compatibility, and the new style named categories implemented by libsm.
38With this change,
39"-dANSI" is implemented using a libsm named debug category.
40You will be able to set a collection of named debug categories to
41the same activation level by specifying a glob pattern.
42For example,
43<dl>
44<dt>
45    <tt> -dANSI </tt>
46<dd>
47    sets the named category "ANSI" to level 1,
48<dt>
49    <tt> -dfoo_*.3 </tt>
50<dd>
51    sets all named categories matching the glob pattern "foo_*" to level 3,
52<dt>
53    <tt> -d0-99.1 </tt>
54<dd>
55    sets the numeric categories 0 through 99 to level 1, and
56<dt>
57    <tt> -dANSI,foo_*.3,0-99.1 </tt>
58<dd>
59    does all of the above.
60</dl>
61
62<p>
63For sendmail 9.x, I propose to drop support for numeric debug categories,
64and just use named debug categories.
65
66<h2> Synopsis </h2>
67
68<pre>
69#include &lt;sm/debug.h&gt;
70
71/*
72**  abstractions for printing trace messages
73*/
74void sm_dprintf(char *fmt, ...)
75void sm_dflush()
76void sm_debug_setfile(SM_FILE_T *)
77
78/*
79**  abstractions for setting and testing debug activation levels
80*/
81void sm_debug_addsettings(char *settings)
82void sm_debug_addsetting(char *pattern, int level)
83
84typedef struct sm_debug SM_DEBUG_T;
85SM_DEBUG_T dbg = SM_DEBUG_INITIALIZER("name", "@(#)$Debug: name - description $");
86
87bool sm_debug_active(SM_DEBUG_T *debug, int level)
88int  sm_debug_level(SM_DEBUG_T *debug)
89bool sm_debug_unknown(SM_DEBUG_T *debug)
90</pre>
91
92<h2> Naming Conventions </h2>
93
94All debug categories defined by libsm have names of the form <tt>sm_*</tt>.
95Debug categories that turn on trace output have names of the form
96<tt>*_trace_*</tt>.
97Debug categories that turn on run time checks have names of the form
98<tt>*_check_*</tt>.
99Here are all of the libsm debug categories as of March 2000:
100
101<table>
102  <tr>
103    <td>Variable name</td>
104    <td>Category name</td>
105    <td>Meaning</td>
106  </tr>
107  <tr>
108    <td>SmExpensiveAssert</td>
109    <td>sm_check_assert</td>
110    <td>enable expensive SM_ASSERT checking</td>
111  </tr>
112  <tr>
113    <td>SmExpensiveRequire</td>
114    <td>sm_check_require</td>
115    <td>enable expensive SM_REQUIRE checking</td>
116  </tr>
117  <tr>
118    <td>SmExpensiveEnsure</td>
119    <td>sm_check_ensure</td>
120    <td>enable expensive SM_ENSURE checking</td>
121  </tr>
122  <tr>
123    <td>SmHeapTrace</td>
124    <td>sm_trace_heap</td>
125    <td>trace sm_{malloc,realloc,free} calls</td>
126  </tr>
127  <tr>
128    <td>SmHeapCheck</td>
129    <td>sm_check_heap</td>
130    <td>enable checking and memory leak detection in sm_{malloc,realloc,free}</td>
131  </tr>
132</table>
133
134<h2> Function Reference </h2>
135
136<dl>
137<dt>
138<tt> SM_DEBUG_INITIALIZER </tt>
139<dd>
140    To create a new debug category, use the SM_DEBUG_INITIALIZER macro
141    to initialize a static variable of type SM_DEBUG_T.  For example,
142<blockquote><pre>
143SM_DEBUG_T ANSI_debug = SM_DEBUG_INITIALIZER("ANSI",
144	    "@(#)$Debug: ANSI - enable reverse video in debug output $");
145</pre></blockquote>
146    There is no centralized table of category names that needs to
147    be edited in order to add a new debug category.
148    The sole purpose of the second argument to SM_DEBUG_INITIALIZER
149    is to provide an easy way to find out what named debug categories
150    are present in a sendmail binary.  You can use:
151<blockquote><pre>
152ident /usr/sbin/sendmail | grep Debug
153</pre></blockquote>
154    or:
155<blockquote><pre>
156what /usr/sbin/sendmail | grep Debug
157</pre></blockquote>
158
159
160<dt>
161<tt> void sm_debug_addsetting(char *pattern, int level) </tt>
162<dd>
163    All debug categories default to activation level 0, which means
164    no activity.
165    This function updates an internal database of debug settings,
166    setting all categories whose name matches the specified glob
167    pattern to the specified activation level.  The level argument
168    must be &gt;= 0.
169    <p>
170
171
172<dt>
173<tt> void sm_debug_addsettings(char *settings) </tt>
174<dd>
175    This function is used to process the <tt>-d</tt> command line
176    option of Sendmail 9.x, and of other programs that support the
177    setting of named debug categories.  The settings argument is a
178    comma-separated list of settings; each setting is a glob pattern,
179    optionally followed by a '.' and a decimal numeral.
180    <p>
181
182
183<dt>
184<tt> bool sm_debug_active(SM_DEBUG_T *debug, int level) </tt>
185<dd>
186    This macro returns <tt>true</tt> if the activation level of
187    the statically initialized debug structure <tt>debug</tt>
188    is &gt;= the specified level.
189    The test is performed very efficiently: in the most common case,
190    when the result is <tt>false</tt>, only a single comparison
191    operation is performed.
192    <p>
193    This macro performs a function call only if the debug structure has
194    an unknown activation level.  All debug structures are in this state
195    at the beginning of program execution, and after a call to
196    <tt>sm_debug_addsetting</tt>.
197    <p>
198
199
200<dt>
201<tt> int sm_debug_level(SM_DEBUG_T *debug) </tt>
202<dd>
203    This macro returns the activation level of the specified debug structure.
204    The comparison
205<blockquote><pre>
206sm_debug_level(debug) &gt;= level
207</pre></blockquote>
208    is slightly less efficient than, but otherwise semantically
209    equivalent to
210<blockquote><pre>
211sm_debug_active(debug, level)
212</pre></blockquote>
213    <p>
214
215
216<dt>
217<tt> bool sm_debug_unknown(SM_DEBUG_T *debug) </tt>
218<dd>
219    This macro returns true if the activation level of the specified
220    debug structure is unknown.
221    Here is an example of how the macro might be used:
222<blockquote><pre>
223if (sm_debug_unknown(&FooDebug))
224{
225	if (sm_debug_active(&FooDebug, 1))
226	{
227		... perform some expensive data structure initializations
228		... in order to enable the "foo" debugging mechanism
229	}
230	else
231	{
232		... disable the "foo" debugging mechanism
233	}
234}
235</pre></blockquote>
236    The purpose of using <tt>sm_debug_unknown</tt> in the above example
237    is to avoid performing the expensive initializations each time through
238    the code.  So it's a performance hack.
239    A debug structure is in the "unknown" state at the beginning of
240    program execution, and after a call to <tt>sm_debug_addsetting</tt>.
241    A side effect of calling <tt>sm_debug_active</tt> is that the
242    activation level becomes known.
243    <p>
244
245
246<dt>
247<tt> void sm_dprintf(char *fmt, ...) </tt>
248<dd>
249    This function is used to print a debug message.
250    The standard idiom is
251<blockquote><pre>
252if (sm_debug_active(&BarDebug, 1))
253	sm_dprintf("bar: about to test tensile strength of bar %d\n", i);
254</pre></blockquote>
255    <p>
256
257<dt>
258<tt> void sm_dflush() </tt>
259<dd>
260    Flush the debug output stream.
261    <p>
262
263<dt>
264<tt> void sm_debug_setfile(SM_FILE_T *file) </tt>
265<dd>
266    This function lets you specify where debug output is printed.
267    By default, debug output is written to standard output.
268    <p>
269    We want to allow you to direct debug output to syslog.
270    The current plan is to provide a standard interface for
271    creating an SM_FILE_T object that writes to syslog.
272
273</dl>
274
275</body>
276</html>
277