1
by brian
clean slate |
1 |
.\" @(#)user.r 1.13 10/29/86
|
2 |
.\"
|
|
3 |
.\" 2004-10-29: documented features implemented since 10/29/86
|
|
4 |
.\" formatting cleanup
|
|
5 |
.\" - Sergei Golubchik
|
|
6 |
.\"
|
|
7 |
.\" DBUG (Macro Debugger Package) nroff source
|
|
8 |
.\"
|
|
9 |
.\" nroff -mm user.r >user.t
|
|
10 |
.\" groff -mm user.r >user.ps
|
|
11 |
.\"
|
|
12 |
.\" ===================================================
|
|
13 |
.\"
|
|
14 |
.\" === Some sort of black magic, but I forget...
|
|
15 |
.tr ~
|
|
16 |
.\" === Hyphenation control (1 = on)
|
|
17 |
.\".nr Hy 1
|
|
18 |
.\" === Force all first level headings to start on new page
|
|
19 |
.nr Ej 1
|
|
20 |
.\" === Set for breaks after headings for levels 1-3
|
|
21 |
.nr Hb 3
|
|
22 |
.\" === Set for space after headings for levels 1-3
|
|
23 |
.nr Hs 3
|
|
24 |
.\" === Set standard indent for one/half inch
|
|
25 |
.nr Si 10
|
|
26 |
.\" === Set page header
|
|
27 |
.PH "/DBUG User Manual//\*(DT/"
|
|
28 |
.\" === Set page footer
|
|
29 |
.PF "// - % - //"
|
|
30 |
.\" === Set page offset
|
|
31 |
.\".po 0.60i
|
|
32 |
.\" === Set line length
|
|
33 |
.\".ll 6.5i
|
|
34 |
.TL
|
|
35 |
D B U G
|
|
36 |
.P 0
|
|
37 |
C Program Debugging Package
|
|
38 |
.P 0
|
|
39 |
by
|
|
40 |
.AU "Fred Fish"
|
|
41 |
.AF ""
|
|
42 |
.SA 1
|
|
43 |
.\" === All paragraphs indented.
|
|
44 |
.nr Pt 1
|
|
45 |
.AS 1
|
|
46 |
This document introduces
|
|
47 |
.I dbug ,
|
|
48 |
a macro based C debugging
|
|
49 |
package which has proven to be a very flexible and useful tool
|
|
50 |
for debugging, testing, and porting C programs.
|
|
51 |
||
52 |
.P
|
|
53 |
All of the features of the
|
|
54 |
.I dbug
|
|
55 |
package can be enabled or disabled dynamically at execution time.
|
|
56 |
This means that production programs will run normally when
|
|
57 |
debugging is not enabled, and eliminates the need to maintain two
|
|
58 |
separate versions of a program.
|
|
59 |
||
60 |
.P
|
|
61 |
Many of the things easily accomplished with conventional debugging
|
|
62 |
tools, such as symbolic debuggers, are difficult or impossible with this
|
|
63 |
package, and vice versa.
|
|
64 |
Thus the
|
|
65 |
.I dbug
|
|
66 |
package should
|
|
67 |
.I not
|
|
68 |
be thought of as a replacement or substitute for
|
|
69 |
other debugging tools, but simply as a useful
|
|
70 |
.I addition
|
|
71 |
to the
|
|
72 |
program development and maintenance environment.
|
|
73 |
||
74 |
.AE
|
|
75 |
.MT 4
|
|
76 |
.SK
|
|
77 |
.B
|
|
78 |
INTRODUCTION
|
|
79 |
.R
|
|
80 |
||
81 |
.P
|
|
82 |
Almost every program development environment worthy of the name
|
|
83 |
provides some sort of debugging facility.
|
|
84 |
Usually this takes the form of a program which is capable of
|
|
85 |
controlling execution of other programs and examining the internal
|
|
86 |
state of other executing programs.
|
|
87 |
These types of programs will be referred to as external debuggers
|
|
88 |
since the debugger is not part of the executing program.
|
|
89 |
Examples of this type of debugger include the
|
|
90 |
.B adb
|
|
91 |
and
|
|
92 |
.B sdb
|
|
93 |
debuggers provided with the
|
|
94 |
.B UNIX\*F
|
|
95 |
.FS
|
|
96 |
UNIX is a trademark of AT&T Bell Laboratories.
|
|
97 |
.FE
|
|
98 |
operating system.
|
|
99 |
||
100 |
.P
|
|
101 |
One of the problems associated with developing programs in an environment
|
|
102 |
with good external debuggers is that developed programs tend to have
|
|
103 |
little or no internal instrumentation.
|
|
104 |
This is usually not a problem for the developer since he is,
|
|
105 |
or at least should be, intimately familiar with the internal organization,
|
|
106 |
data structures, and control flow of the program being debugged.
|
|
107 |
It is a serious problem for maintenance programmers, who
|
|
108 |
are unlikely to have such familiarity with the program being
|
|
109 |
maintained, modified, or ported to another environment.
|
|
110 |
It is also a problem, even for the developer, when the program is
|
|
111 |
moved to an environment with a primitive or unfamiliar debugger,
|
|
112 |
or even no debugger.
|
|
113 |
||
114 |
.P
|
|
115 |
On the other hand,
|
|
116 |
.I dbug
|
|
117 |
is an example of an internal debugger.
|
|
118 |
Because it requires internal instrumentation of a program,
|
|
119 |
and its usage does not depend on any special capabilities of
|
|
120 |
the execution environment, it is always available and will
|
|
121 |
execute in any environment that the program itself will
|
|
122 |
execute in.
|
|
123 |
In addition, since it is a complete package with a specific
|
|
124 |
user interface, all programs which use it will be provided
|
|
125 |
with similar debugging capabilities.
|
|
126 |
This is in sharp contrast to other forms of internal instrumentation
|
|
127 |
where each developer has their own, usually less capable, form
|
|
128 |
of internal debugger.
|
|
129 |
In summary,
|
|
130 |
because
|
|
131 |
.I dbug
|
|
132 |
is an internal debugger it provides consistency across operating
|
|
133 |
environments,
|
|
134 |
and because it is available to all developers it provides
|
|
135 |
consistency across all programs in the same environment.
|
|
136 |
||
137 |
.P
|
|
138 |
The
|
|
139 |
.I dbug
|
|
140 |
package imposes only a slight speed penalty on executing
|
|
141 |
programs, typically much less than 10 percent, and a modest size
|
|
142 |
penalty, typically 10 to 20 percent.
|
|
143 |
By defining a specific C preprocessor symbol both of these
|
|
144 |
can be reduced to zero with no changes required to the
|
|
145 |
source code.
|
|
146 |
||
147 |
.P
|
|
148 |
The following list is a quick summary of the capabilities
|
|
149 |
of the
|
|
150 |
.I dbug
|
|
151 |
package.
|
|
152 |
Each capability can be individually enabled or disabled
|
|
153 |
at the time a program is invoked by specifying the appropriate
|
|
154 |
command line arguments.
|
|
155 |
.SP 1
|
|
156 |
.ML o 1i
|
|
157 |
.LI
|
|
158 |
Execution trace showing function level control flow in a
|
|
159 |
semi-graphically manner using indentation to indicate nesting
|
|
160 |
depth.
|
|
161 |
.LI
|
|
162 |
Output the values of all, or any subset of, key internal variables.
|
|
163 |
.LI
|
|
164 |
Limit actions to a specific set of named functions.
|
|
165 |
.LI
|
|
166 |
Limit function trace to a specified nesting depth.
|
|
167 |
.LI
|
|
168 |
Label each output line with source file name and line number.
|
|
169 |
.LI
|
|
170 |
Label each output line with name of current process.
|
|
171 |
.LI
|
|
172 |
Push or pop internal debugging state to allow execution with
|
|
173 |
built in debugging defaults.
|
|
174 |
.LI
|
|
175 |
Redirect the debug output stream to standard output (stdout)
|
|
176 |
or a named file.
|
|
177 |
The default output stream is standard error (stderr).
|
|
178 |
The redirection mechanism is completely independent of
|
|
179 |
normal command line redirection to avoid output conflicts.
|
|
180 |
.LE
|
|
181 |
||
182 |
.SK
|
|
183 |
.B
|
|
184 |
PRIMITIVE DEBUGGING TECHNIQUES
|
|
185 |
.R
|
|
186 |
||
187 |
.P
|
|
188 |
Internal instrumentation is already a familiar concept
|
|
189 |
to most programmers, since it is usually the first debugging
|
|
190 |
technique learned.
|
|
191 |
Typically, "print\ statements" are inserted in the source
|
|
192 |
code at interesting points, the code is recompiled and executed,
|
|
193 |
and the resulting output is examined in an attempt to determine
|
|
194 |
where the problem is.
|
|
195 |
||
196 |
The procedure is iterative, with each iteration yielding more
|
|
197 |
and more output, and hopefully the source of the problem is
|
|
198 |
discovered before the output becomes too large to deal with
|
|
199 |
or previously inserted statements need to be removed.
|
|
200 |
Figure 1 is an example of this type of primitive debugging
|
|
201 |
technique.
|
|
202 |
.DS I N
|
|
203 |
.SP 2
|
|
204 |
\fC
|
|
205 |
.so example1.r
|
|
206 |
\fR
|
|
207 |
.SP 2
|
|
208 |
.ll -5
|
|
209 |
.ce
|
|
210 |
Figure 1
|
|
211 |
.ce
|
|
212 |
Primitive Debugging Technique
|
|
213 |
.ll +5
|
|
214 |
.SP 2
|
|
215 |
.DE
|
|
216 |
||
217 |
.P
|
|
218 |
Eventually, and usually after at least several iterations, the
|
|
219 |
problem will be found and corrected.
|
|
220 |
At this point, the newly inserted print statements must be
|
|
221 |
dealt with.
|
|
222 |
One obvious solution is to simply delete them all.
|
|
223 |
Beginners usually do this a few times until they have to
|
|
224 |
repeat the entire process every time a new bug pops up.
|
|
225 |
The second most obvious solution is to somehow disable
|
|
226 |
the output, either through the source code comment facility,
|
|
227 |
creation of a debug variable to be switched on or off, or by using the
|
|
228 |
C preprocessor.
|
|
229 |
Figure 2 is an example of all three techniques.
|
|
230 |
.DS I N
|
|
231 |
.SP 2
|
|
232 |
\fC
|
|
233 |
.so example2.r
|
|
234 |
\fR
|
|
235 |
.SP 2
|
|
236 |
.ll -5
|
|
237 |
.ce
|
|
238 |
Figure 2
|
|
239 |
.ce
|
|
240 |
Debug Disable Techniques
|
|
241 |
.ll +5
|
|
242 |
.SP 2
|
|
243 |
.DE
|
|
244 |
||
245 |
.P
|
|
246 |
Each technique has its advantages and disadvantages with respect
|
|
247 |
to dynamic vs static activation, source code overhead, recompilation
|
|
248 |
requirements, ease of use, program readability, etc.
|
|
249 |
Overuse of the preprocessor solution quickly leads to problems with
|
|
250 |
source code readability and maintainability when multiple
|
|
251 |
.B #ifdef
|
|
252 |
symbols are to be defined or undefined based on specific types
|
|
253 |
of debug desired.
|
|
254 |
The source code can be made slightly more readable by suitable indentation
|
|
255 |
of the
|
|
256 |
.B #ifdef
|
|
257 |
arguments to match the indentation of the code, but
|
|
258 |
not all C preprocessors allow this.
|
|
259 |
The only requirement for the standard
|
|
260 |
.B UNIX
|
|
261 |
C preprocessor is for the '#' character to appear
|
|
262 |
in the first column, but even this seems
|
|
263 |
like an arbitrary and unreasonable restriction.
|
|
264 |
Figure 3 is an example of this usage.
|
|
265 |
.DS I N
|
|
266 |
.SP 2
|
|
267 |
\fC
|
|
268 |
.so example3.r
|
|
269 |
\fR
|
|
270 |
.SP 2
|
|
271 |
.ll -5
|
|
272 |
.ce
|
|
273 |
Figure 3
|
|
274 |
.ce
|
|
275 |
More Readable Preprocessor Usage
|
|
276 |
.ll +5
|
|
277 |
.SP 2
|
|
278 |
.DE
|
|
279 |
||
280 |
.SK
|
|
281 |
.B
|
|
282 |
FUNCTION TRACE EXAMPLE
|
|
283 |
.R
|
|
284 |
||
285 |
.P
|
|
286 |
We will start off learning about the capabilities of the
|
|
287 |
.I dbug
|
|
288 |
package by using a simple minded program which computes the
|
|
289 |
factorial of a number.
|
|
290 |
In order to better demonstrate the function trace mechanism, this
|
|
291 |
program is implemented recursively.
|
|
292 |
Figure 4 is the main function for this factorial program.
|
|
293 |
.DS I N
|
|
294 |
.SP 2
|
|
295 |
\fC
|
|
296 |
.so main.r
|
|
297 |
\fR
|
|
298 |
.SP 2
|
|
299 |
.ll -5
|
|
300 |
.ce
|
|
301 |
Figure 4
|
|
302 |
.ce
|
|
303 |
Factorial Program Mainline
|
|
304 |
.ll +5
|
|
305 |
.SP 2
|
|
306 |
.DE
|
|
307 |
||
308 |
.P
|
|
309 |
The
|
|
310 |
.B main
|
|
311 |
function is responsible for processing any command line
|
|
312 |
option arguments and then computing and printing the factorial of
|
|
313 |
each non-option argument.
|
|
314 |
.P
|
|
315 |
First of all, notice that all of the debugger functions are implemented
|
|
316 |
via preprocessor macros.
|
|
317 |
This does not detract from the readability of the code and makes disabling
|
|
318 |
all debug compilation trivial (a single preprocessor symbol,
|
|
319 |
.B DBUG_OFF ,
|
|
320 |
forces the macro expansions to be null).
|
|
321 |
.P
|
|
322 |
Also notice the inclusion of the header file
|
|
323 |
.B dbug.h
|
|
324 |
from the local header file directory.
|
|
325 |
(The version included here is the test version in the dbug source
|
|
326 |
distribution directory).
|
|
327 |
This file contains all the definitions for the debugger macros, which
|
|
328 |
all have the form
|
|
329 |
.B DBUG_XX...XX .
|
|
330 |
||
331 |
.P
|
|
332 |
The
|
|
333 |
.B DBUG_ENTER
|
|
334 |
macro informs that debugger that we have entered the
|
|
335 |
function named
|
|
336 |
.B main .
|
|
337 |
It must be the very first "executable" line in a function, after
|
|
338 |
all declarations and before any other executable line.
|
|
339 |
The
|
|
340 |
.B DBUG_PROCESS
|
|
341 |
macro is generally used only once per program to
|
|
342 |
inform the debugger what name the program was invoked with.
|
|
343 |
The
|
|
344 |
.B DBUG_PUSH
|
|
345 |
macro modifies the current debugger state by
|
|
346 |
saving the previous state and setting a new state based on the
|
|
347 |
control string passed as its argument.
|
|
348 |
The
|
|
349 |
.B DBUG_PRINT
|
|
350 |
macro is used to print the values of each argument
|
|
351 |
for which a factorial is to be computed.
|
|
352 |
The
|
|
353 |
.B DBUG_RETURN
|
|
354 |
macro tells the debugger that the end of the current
|
|
355 |
function has been reached and returns a value to the calling
|
|
356 |
function.
|
|
357 |
All of these macros will be fully explained in subsequent sections.
|
|
358 |
.P
|
|
359 |
To use the debugger, the factorial program is invoked with a command
|
|
360 |
line of the form:
|
|
361 |
.DS CB N
|
|
362 |
\fCfactorial -#d:t 1 2 3
|
|
363 |
.DE
|
|
364 |
The
|
|
365 |
.B main
|
|
366 |
function recognizes the "-#d:t" string as a debugger control
|
|
367 |
string, and passes the debugger arguments ("d:t") to the
|
|
368 |
.I dbug
|
|
369 |
runtime support routines via the
|
|
370 |
.B DBUG_PUSH
|
|
371 |
macro.
|
|
372 |
This particular string enables output from the
|
|
373 |
.B DBUG_PRINT
|
|
374 |
macro with the 'd' flag and enables function tracing with the 't' flag.
|
|
375 |
The factorial function is then called three times, with the arguments
|
|
376 |
"1", "2", and "3".
|
|
377 |
Note that the DBUG_PRINT takes exactly
|
|
378 |
.B two
|
|
379 |
arguments, with the second argument (a format string and list
|
|
380 |
of printable values) enclosed in parentheses.
|
|
381 |
.P
|
|
382 |
Debug control strings consist of a header, the "-#", followed
|
|
383 |
by a colon separated list of debugger arguments.
|
|
384 |
Each debugger argument is a single character flag followed
|
|
385 |
by an optional comma separated list of arguments specific
|
|
386 |
to the given flag.
|
|
387 |
Some examples are:
|
|
388 |
.DS CB N
|
|
389 |
\fC
|
|
390 |
-#d:t:o
|
|
391 |
-#d,in,out:f,main:F:L
|
|
392 |
.DE
|
|
393 |
Note that previously enabled debugger actions can be disabled by the
|
|
394 |
control string "-#".
|
|
395 |
||
396 |
.P
|
|
397 |
The definition of the factorial function, symbolized as "N!", is
|
|
398 |
given by:
|
|
399 |
.DS CB N
|
|
400 |
N! = N * N-1 * ... 2 * 1
|
|
401 |
.DE
|
|
402 |
Figure 5 is the factorial function which implements this algorithm
|
|
403 |
recursively.
|
|
404 |
Note that this is not necessarily the best way to do factorials
|
|
405 |
and error conditions are ignored completely.
|
|
406 |
.DS I N
|
|
407 |
.SP 2
|
|
408 |
\fC
|
|
409 |
.so factorial.r
|
|
410 |
\fR
|
|
411 |
.SP 2
|
|
412 |
.ll -5
|
|
413 |
.ce
|
|
414 |
Figure 5
|
|
415 |
.ce
|
|
416 |
Factorial Function
|
|
417 |
.ll +5
|
|
418 |
.SP 2
|
|
419 |
.DE
|
|
420 |
||
421 |
.P
|
|
422 |
One advantage (some may not consider it so) to using the
|
|
423 |
.I dbug
|
|
424 |
package is that it strongly encourages fully structured coding
|
|
425 |
with only one entry and one exit point in each function.
|
|
426 |
Multiple exit points, such as early returns to escape a loop,
|
|
427 |
may be used, but each such point requires the use of an
|
|
428 |
appropriate
|
|
429 |
.B DBUG_RETURN
|
|
430 |
or
|
|
431 |
.B DBUG_VOID_RETURN
|
|
432 |
macro.
|
|
433 |
||
434 |
.P
|
|
435 |
To build the factorial program on a
|
|
436 |
.B UNIX
|
|
437 |
system, compile and
|
|
438 |
link with the command:
|
|
439 |
.DS CB N
|
|
440 |
\fCcc -o factorial main.c factorial.c -ldbug
|
|
441 |
.DE
|
|
442 |
The "-ldbug" argument tells the loader to link in the
|
|
443 |
runtime support modules for the
|
|
444 |
.I dbug
|
|
445 |
package.
|
|
446 |
Executing the factorial program with a command of the form:
|
|
447 |
.DS CB N
|
|
448 |
\fCfactorial 1 2 3 4 5
|
|
449 |
.DE
|
|
450 |
generates the output shown in figure 6.
|
|
451 |
.DS I N
|
|
452 |
.SP 2
|
|
453 |
\fC
|
|
454 |
.so output1.r
|
|
455 |
\fR
|
|
456 |
.SP 2
|
|
457 |
.ll -5
|
|
458 |
.ce
|
|
459 |
Figure 6
|
|
460 |
.ce
|
|
461 |
\fCfactorial 1 2 3 4 5
|
|
462 |
.ll +5
|
|
463 |
.SP 2
|
|
464 |
.DE
|
|
465 |
||
466 |
.P
|
|
467 |
Function level tracing is enabled by passing the debugger
|
|
468 |
the 't' flag in the debug control string.
|
|
469 |
Figure 7 is the output resulting from the command
|
|
470 |
"factorial\ -#t:o\ 2\ 3".
|
|
471 |
.DS I N
|
|
472 |
.SP 2
|
|
473 |
\fC
|
|
474 |
.so output2.r
|
|
475 |
\fR
|
|
476 |
.SP 2
|
|
477 |
.ll -5
|
|
478 |
.ce
|
|
479 |
Figure 7
|
|
480 |
.ce
|
|
481 |
\fCfactorial -#t:o 2 3
|
|
482 |
.ll +5
|
|
483 |
.SP 2
|
|
484 |
.DE
|
|
485 |
||
486 |
.P
|
|
487 |
Each entry to or return from a function is indicated by '>' for the
|
|
488 |
entry point and '<' for the exit point, connected by
|
|
489 |
vertical bars to allow matching points to be easily found
|
|
490 |
when separated by large distances.
|
|
491 |
||
492 |
.P
|
|
493 |
This trace output indicates that there was an initial call
|
|
494 |
to factorial from main (to compute 2!), followed by
|
|
495 |
a single recursive call to factorial to compute 1!.
|
|
496 |
The main program then output the result for 2! and called the
|
|
497 |
factorial function again with the second argument, 3.
|
|
498 |
Factorial called itself recursively to compute 2! and 1!, then
|
|
499 |
returned control to main, which output the value for 3! and exited.
|
|
500 |
||
501 |
.P
|
|
502 |
Note that there is no matching entry point "main>" for the
|
|
503 |
return point "<main" because at the time the
|
|
504 |
.B DBUG_ENTER
|
|
505 |
macro was reached in main, tracing was not enabled yet.
|
|
506 |
It was only after the macro
|
|
507 |
.B DBUG_PUSH
|
|
508 |
was executing that tracing became enabled.
|
|
509 |
This implies that the argument list should be processed as early as
|
|
510 |
possible since all code preceding the first call to
|
|
511 |
.B DBUG_PUSH
|
|
512 |
is
|
|
513 |
essentially invisible to
|
|
514 |
.B dbug
|
|
515 |
(this can be worked around by
|
|
516 |
inserting a temporary
|
|
517 |
.B DBUG_PUSH(argv[1])
|
|
518 |
immediately after the
|
|
519 |
.B DBUG_ENTER("main")
|
|
520 |
macro.
|
|
521 |
||
522 |
.P
|
|
523 |
One last note,
|
|
524 |
the trace output normally comes out on the standard error.
|
|
525 |
Since the factorial program prints its result on the standard
|
|
526 |
output, there is the possibility of the output on the terminal
|
|
527 |
being scrambled if the two streams are not synchronized.
|
|
528 |
Thus the debugger is told to write its output on the standard
|
|
529 |
output instead, via the 'o' flag character.
|
|
530 |
Note that no 'o' implies the default (standard error), a 'o'
|
|
531 |
with no arguments means standard output, and a 'o'
|
|
532 |
with an argument means used the named file.
|
|
533 |
i.e, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
|
|
534 |
output in "logfile".
|
|
535 |
Because of
|
|
536 |
.B UNIX
|
|
537 |
implementation details, programs usually run
|
|
538 |
faster when writing to stdout rather than stderr, though this
|
|
539 |
is not a prime consideration in this example.
|
|
540 |
||
541 |
.SK
|
|
542 |
.B
|
|
543 |
USE OF DBUG_PRINT MACRO
|
|
544 |
.R
|
|
545 |
||
546 |
.P
|
|
547 |
The mechanism used to produce "printf" style output is the
|
|
548 |
.B DBUG_PRINT
|
|
549 |
macro.
|
|
550 |
||
551 |
.P
|
|
552 |
To allow selection of output from specific macros, the first argument
|
|
553 |
to every
|
|
554 |
.B DBUG_PRINT
|
|
555 |
macro is a
|
|
556 |
.I dbug
|
|
557 |
keyword.
|
|
558 |
When this keyword appears in the argument list of the 'd' flag in
|
|
559 |
a debug control string, as in "-#d,keyword1,keyword2,...:t",
|
|
560 |
output from the corresponding macro is enabled.
|
|
561 |
The default when there is no 'd' flag in the control string is to
|
|
562 |
enable output from all
|
|
563 |
.B DBUG_PRINT
|
|
564 |
macros.
|
|
565 |
||
566 |
.P
|
|
567 |
Typically, a program will be run once, with no keywords specified,
|
|
568 |
to determine what keywords are significant for the current problem
|
|
569 |
(the keywords are printed in the macro output line).
|
|
570 |
Then the program will be run again, with the desired keywords,
|
|
571 |
to examine only specific areas of interest.
|
|
572 |
||
573 |
.P
|
|
574 |
The second argument to a
|
|
575 |
.B DBUG_PRINT
|
|
576 |
macro is a standard printf style
|
|
577 |
format string and one or more arguments to print, all
|
|
578 |
enclosed in parentheses so that they collectively become a single macro
|
|
579 |
argument.
|
|
580 |
This is how variable numbers of printf arguments are supported.
|
|
581 |
Also note that no explicit newline is required at the end of the format string.
|
|
582 |
As a matter of style, two or three small
|
|
583 |
.B DBUG_PRINT
|
|
584 |
macros are preferable
|
|
585 |
to a single macro with a huge format string.
|
|
586 |
Figure 8 shows the output for default tracing and debug.
|
|
587 |
.DS I N
|
|
588 |
.SP 2
|
|
589 |
\fC
|
|
590 |
.so output3.r
|
|
591 |
\fR
|
|
592 |
.SP 2
|
|
593 |
.ll -5
|
|
594 |
.ce
|
|
595 |
Figure 8
|
|
596 |
.ce
|
|
597 |
\fCfactorial -#d:t:o 3
|
|
598 |
.ll +5
|
|
599 |
.SP 2
|
|
600 |
.DE
|
|
601 |
||
602 |
.P
|
|
603 |
The output from the
|
|
604 |
.B DBUG_PRINT
|
|
605 |
macro is indented to match the trace output
|
|
606 |
for the function in which the macro occurs.
|
|
607 |
When debugging is enabled, but not trace, the output starts at the left
|
|
608 |
margin, without indentation.
|
|
609 |
||
610 |
.P
|
|
611 |
To demonstrate selection of specific macros for output, figure
|
|
612 |
9 shows the result when the factorial program is invoked with
|
|
613 |
the debug control string "-#d,result:o".
|
|
614 |
.DS I N
|
|
615 |
.SP 2
|
|
616 |
\fC
|
|
617 |
.so output4.r
|
|
618 |
\fR
|
|
619 |
.SP 2
|
|
620 |
.ll -5
|
|
621 |
.ce
|
|
622 |
Figure 9
|
|
623 |
.ce
|
|
624 |
\fCfactorial -#d,result:o 4
|
|
625 |
.ll +5
|
|
626 |
.SP 2
|
|
627 |
.DE
|
|
628 |
||
629 |
.P
|
|
630 |
It is sometimes desirable to restrict debugging and trace actions
|
|
631 |
to a specific function or list of functions.
|
|
632 |
This is accomplished with the 'f' flag character in the debug
|
|
633 |
control string.
|
|
634 |
Figure 10 is the output of the factorial program when run with the
|
|
635 |
control string "-#d:f,factorial:F:L:o".
|
|
636 |
The 'F' flag enables printing of the source file name and the 'L'
|
|
637 |
flag enables printing of the source file line number.
|
|
638 |
.DS I N
|
|
639 |
.SP 2
|
|
640 |
\fC
|
|
641 |
.so output5.r
|
|
642 |
\fR
|
|
643 |
.SP 2
|
|
644 |
.ll -5
|
|
645 |
.ce
|
|
646 |
Figure 10
|
|
647 |
.ce
|
|
648 |
\fCfactorial -#d:f,factorial:F:L:o 3
|
|
649 |
.ll +5
|
|
650 |
.SP 2
|
|
651 |
.DE
|
|
652 |
||
653 |
.P
|
|
654 |
The output in figure 10 shows that the "find" macro is in file
|
|
655 |
"factorial.c" at source line 8 and the "result" macro is in the same
|
|
656 |
file at source line 12.
|
|
657 |
||
658 |
.SK
|
|
659 |
.B
|
|
660 |
SUMMARY OF MACROS
|
|
661 |
.R
|
|
662 |
||
663 |
.P
|
|
664 |
This section summarizes the usage of all currently defined macros
|
|
665 |
in the
|
|
666 |
.I dbug
|
|
667 |
package.
|
|
668 |
The macros definitions are found in the user include file
|
|
669 |
.B dbug.h
|
|
670 |
from the standard include directory.
|
|
671 |
||
672 |
.SP 2
|
|
673 |
.BL 20
|
|
674 |
.LI DBUG_ENTER\
|
|
675 |
Used to tell the runtime support module the name of the function being
|
|
676 |
entered. The argument must be of type "pointer to character". The
|
|
677 |
DBUG_ENTER macro must precede all executable lines in the function
|
|
678 |
just entered, and must come after all local declarations. Each
|
|
679 |
DBUG_ENTER macro must have a matching DBUG_RETURN or DBUG_VOID_RETURN
|
|
680 |
macro at the function exit points. DBUG_ENTER macros used without a
|
|
681 |
matching DBUG_RETURN or DBUG_VOID_RETURN macro will cause warning
|
|
682 |
messages from the
|
|
683 |
.I dbug
|
|
684 |
package runtime support module.
|
|
685 |
.SP 1
|
|
686 |
EX:\ \fCDBUG_ENTER\ ("main");\fR
|
|
687 |
.SP 1
|
|
688 |
.LI DBUG_RETURN\
|
|
689 |
Used at each exit point of a function containing a DBUG_ENTER macro at
|
|
690 |
the entry point. The argument is the value to return. Functions
|
|
691 |
which return no value (void) should use the DBUG_VOID_RETURN macro.
|
|
692 |
It is an error to have a DBUG_RETURN or DBUG_VOID_RETURN macro in a
|
|
693 |
function which has no matching DBUG_ENTER macro, and the compiler will
|
|
694 |
complain if the macros are actually used (expanded).
|
|
695 |
.SP 1
|
|
696 |
EX:\ \fCDBUG_RETURN\ (value);\fR
|
|
697 |
.br
|
|
698 |
EX:\ \fCDBUG_VOID_RETURN;\fR
|
|
699 |
.SP 1
|
|
700 |
.LI DBUG_PROCESS\
|
|
701 |
Used to name the current process being executed.
|
|
702 |
A typical argument for this macro is "argv[0]", though
|
|
703 |
it will be perfectly happy with any other string.
|
|
704 |
Im multi-threaded environment threads may have different names.
|
|
705 |
.SP 1
|
|
706 |
EX:\ \fCDBUG_PROCESS\ (argv[0]);\fR
|
|
707 |
.SP 1
|
|
708 |
.LI DBUG_PUSH\
|
|
709 |
Sets a new debugger state by pushing the current
|
|
710 |
.B dbug
|
|
711 |
state onto an internal stack and setting up the new state using the
|
|
712 |
debug control string passed as the macro argument. The most common
|
|
713 |
usage is to set the state specified by a debug control string
|
|
714 |
retrieved from the argument list. If the control string is
|
|
715 |
.I incremental,
|
|
716 |
the new state is a copy of the old state, modified by the control
|
|
717 |
string.
|
|
718 |
.SP 1
|
|
719 |
EX:\ \fCDBUG_PUSH\ (\&(argv[i][2]));\fR
|
|
720 |
.br
|
|
721 |
EX:\ \fCDBUG_PUSH\ ("d:t");\fR
|
|
722 |
.br
|
|
723 |
EX:\ \fCDBUG_PUSH\ ("");\fR
|
|
724 |
.SP 1
|
|
725 |
.LI DBUG_POP\
|
|
726 |
Restores the previous debugger state by popping the state stack.
|
|
727 |
Attempting to pop more states than pushed will be ignored and no
|
|
728 |
warning will be given. The DBUG_POP macro has no arguments.
|
|
729 |
.SP 1
|
|
730 |
EX:\ \fCDBUG_POP\ ();\fR
|
|
731 |
.SP 1
|
|
732 |
.LI DBUG_SET\
|
|
733 |
Modifies the current debugger state on top of the stack or pushes
|
|
734 |
a new state if the current is set to the initial settings, using
|
|
735 |
the debug control string passed as the macro argument. Unless
|
|
736 |
.I incremental
|
|
737 |
control string is used (see below), it's equivalent to a combination of
|
|
738 |
DBUG_POP and DBUG_PUSH.
|
|
739 |
.SP 1
|
|
740 |
EX:\ \fCDBUG_SET\ ("d:t");\fR
|
|
741 |
.br
|
|
742 |
EX:\ \fCDBUG_SET\ ("+d,info");\fR
|
|
743 |
.br
|
|
744 |
EX:\ \fCDBUG_SET\ ("+t:-d");\fR
|
|
745 |
.SP 1
|
|
746 |
.LI DBUG_FILE\
|
|
747 |
The DBUG_FILE macro is used to do explicit I/O on the debug output
|
|
748 |
stream. It is used in the same manner as the symbols "stdout" and
|
|
749 |
"stderr" in the standard I/O package.
|
|
750 |
.SP 1
|
|
751 |
EX:\ \fCfprintf\ (DBUG_FILE,\ "Doing\ my\ own\ I/O!\\n");\fR
|
|
752 |
.SP 1
|
|
753 |
.LI DBUG_EXECUTE\
|
|
754 |
The DBUG_EXECUTE macro is used to execute any arbitrary C code. The
|
|
755 |
first argument is the debug keyword, used to trigger execution of the
|
|
756 |
code specified as the second argument. This macro must be used
|
|
757 |
cautiously because, like the DBUG_PRINT macro, it is automatically
|
|
758 |
selected by default whenever the 'd' flag has no argument list (i.e.,
|
|
759 |
a "-#d:t" control string).
|
|
760 |
.SP 1
|
|
761 |
EX:\ \fCDBUG_EXECUTE\ ("status",\ print_status\ ());\fR
|
|
762 |
.SP 1
|
|
763 |
.LI DBUG_EXECUTE_IF\
|
|
764 |
Works like DBUG_EXECUTE macro, but the code is
|
|
765 |
.B not
|
|
766 |
executed "by default", if the keyword is not explicitly listed in
|
|
767 |
the 'd' flag. Used to conditionally execute "dangerous" actions, e.g
|
|
768 |
to crash the program testing how recovery works, or to introduce an
|
|
769 |
artificial delay checking for race conditions.
|
|
770 |
.SP 1
|
|
771 |
EX:\ \fCDBUG_EXECUTE_IF\ ("crashme",\ abort\ ());\fR
|
|
772 |
.SP 1
|
|
773 |
.LI DBUG_EVALUATE\
|
|
774 |
The DBUG_EVALUATE macro is similar to DBUG_EXECUTE, but it can be used in
|
|
775 |
the expression context. The first argument is the debug keyword that is used to
|
|
776 |
choose whether the second (keyword is enabled) or the third (keyword is not
|
|
777 |
enabled) argument is evaluated. When
|
|
778 |
.B dbug
|
|
779 |
is compiled off, the third argument is evaluated.
|
|
780 |
.SP 1
|
|
781 |
EX:\fC
|
|
782 |
.br
|
|
783 |
printf("Info-debug is %s",
|
|
784 |
.br
|
|
785 |
DBUG_EVALUATE\ ("info", "ON", "OFF"));\fR
|
|
786 |
.SP 1
|
|
787 |
.LI DBUG_EVALUATE_IF\
|
|
788 |
Works like DBUG_EVALUATE macro, but the second argument is
|
|
789 |
.B not
|
|
790 |
evaluated, if the keyword is not explicitly listed in
|
|
791 |
the 'd' flag. Like DBUG_EXECUTE_IF this could be used to conditionally execute
|
|
792 |
"dangerous" actions.
|
|
793 |
.SP 1
|
|
794 |
EX:\fC
|
|
795 |
.br
|
|
796 |
if (prepare_transaction () ||
|
|
797 |
.br
|
|
798 |
DBUG_EVALUATE ("crashme", (abort (), 0), 0) ||
|
|
799 |
.br
|
|
800 |
commit_transaction () )\fR
|
|
801 |
.SP 1
|
|
802 |
.LI DBUG_PRINT\
|
|
803 |
Used to do printing via the "fprintf" library function on the current
|
|
804 |
debug stream, DBUG_FILE. The first argument is a debug keyword, the
|
|
805 |
second is a format string and the corresponding argument list. Note
|
|
806 |
that the format string and argument list are all one macro argument
|
|
807 |
and
|
|
808 |
.B must
|
|
809 |
be enclosed in parentheses.
|
|
810 |
.SP 1
|
|
811 |
EX:\ \fCDBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));\fR
|
|
812 |
.br
|
|
813 |
EX:\ \fCDBUG_PRINT\ ("type",\ ("type\ is\ %x", type));\fR
|
|
814 |
.br
|
|
815 |
EX:\ \fCDBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));\fR
|
|
816 |
.SP 1
|
|
817 |
.LI DBUG_DUMP\
|
|
818 |
Used to dump a memory block in hex via the "fprintf" library function
|
|
819 |
on the current debug stream, DBUG_FILE. The first argument is a debug
|
|
820 |
keyword, the second is a pointer to a memory to dump, the third is a
|
|
821 |
number of bytes to dump.
|
|
822 |
.SP 1
|
|
823 |
EX: \fCDBUG_DBUG\ ("net",\ packet,\ len);\fR
|
|
824 |
.SP 1
|
|
825 |
.LI DBUG_SETJMP\
|
|
826 |
Used in place of the setjmp() function to first save the current
|
|
827 |
debugger state and then execute the standard setjmp call.
|
|
828 |
This allows to the debugger to restore its state when the
|
|
829 |
DBUG_LONGJMP macro is used to invoke the standard longjmp() call.
|
|
830 |
Currently all instances of DBUG_SETJMP must occur within the
|
|
831 |
same function and at the same function nesting level.
|
|
832 |
.SP 1
|
|
833 |
EX: \fCDBUG_SETJMP\ (env);\fR
|
|
834 |
.SP 1
|
|
835 |
.LI DBUG_LONGJMP\
|
|
836 |
Used in place of the longjmp() function to first restore the
|
|
837 |
previous debugger state at the time of the last DBUG_SETJMP
|
|
838 |
and then execute the standard longjmp() call.
|
|
839 |
Note that currently all DBUG_LONGJMP macros restore the state
|
|
840 |
at the time of the last DBUG_SETJMP.
|
|
841 |
It would be possible to maintain separate DBUG_SETJMP and DBUG_LONGJMP
|
|
842 |
pairs by having the debugger runtime support module use the first
|
|
843 |
argument to differentiate the pairs.
|
|
844 |
.SP 1
|
|
845 |
EX: \fCDBUG_LONGJMP\ (env,val);\fR
|
|
846 |
.SP 1
|
|
847 |
.LI DBUG_LOCK_FILE\
|
|
848 |
Used in multi-threaded environment to lock DBUG_FILE stream.
|
|
849 |
It can be used, for example, in functions that need to write something to a
|
|
850 |
debug stream more than in one fprintf() call and want to ensure that no other
|
|
851 |
thread will write something in between.
|
|
852 |
.SP 1
|
|
853 |
EX:\fC
|
|
854 |
.br
|
|
855 |
DBUG_LOCK_FILE;
|
|
856 |
.br
|
|
857 |
fprintf (DBUG_FILE, "a=[");
|
|
858 |
.br
|
|
859 |
for (int i=0; i < a_length; i++)
|
|
860 |
.br
|
|
861 |
fprintf (DBUG_FILE, "0x%03x ", a[i]);
|
|
862 |
.br
|
|
863 |
fprintf (DBUG_FILE, "]");
|
|
864 |
.br
|
|
865 |
DBUG_UNLOCK_FILE;\fR
|
|
866 |
.SP 1
|
|
867 |
.LI DBUG_UNLOCK_FILE\
|
|
868 |
Unlocks DBUG_FILE stream, that was locked with a DBUG_LOCK_FILE.
|
|
869 |
.LI DBUG_ASSERT\
|
|
870 |
This macro just does a regular assert(). The difference is that it will be
|
|
871 |
disabled by DBUG_OFF togeher with the
|
|
872 |
.I dbug
|
|
873 |
library. So there will be no need to disable asserts separately with NDEBUG.
|
|
874 |
.SP 1
|
|
875 |
EX:\ \fCDBUG_ASSERT(\ a\ >\ 0\ );\fR
|
|
876 |
.SP 1
|
|
877 |
.LI DBUG_EXPLAIN\
|
|
878 |
Generates control string corresponding to the current debug state.
|
|
879 |
The macro takes two arguments - a buffer to store the result string
|
|
880 |
into and its length. The macro (which could be used as a function)
|
|
881 |
returns 1 if the control string didn't fit into the buffer and was
|
|
882 |
truncated and 0 otherwise.
|
|
883 |
.SP 1
|
|
884 |
EX:\fC
|
|
885 |
.br
|
|
886 |
char buf[256];
|
|
887 |
.br
|
|
888 |
DBUG_EXPLAIN( buf, sizeof(buf) );\fR
|
|
889 |
.SP 1
|
|
890 |
.LI DBUG_SET_INITIAL\
|
|
891 |
.LI DBUG_EXPLAIN_INITIAL\
|
|
892 |
.br
|
|
893 |
These two macros are identical to DBUG_SET and DBUG_EXPLAIN, but they
|
|
894 |
operate on the debug state that any new thread starts from.
|
|
895 |
Modifying
|
|
896 |
.I initial
|
|
897 |
value does not affect threads that are already running. Obviously,
|
|
898 |
these macros are only useful in the multi-threaded environment.
|
|
899 |
.LE
|
|
900 |
||
901 |
.SK
|
|
902 |
.B
|
|
903 |
DEBUG CONTROL STRING
|
|
904 |
.R
|
|
905 |
||
906 |
.P
|
|
907 |
The debug control string is used to set the state of the debugger
|
|
908 |
via the
|
|
909 |
.B DBUG_PUSH
|
|
910 |
or
|
|
911 |
.B DBUG_SET
|
|
912 |
macros. Control string consists of colon separate flags. Colons
|
|
913 |
that are part of ':\\', ':/', or '::' are not considered flag
|
|
914 |
separators. A flag may take an argument or a list of arguments.
|
|
915 |
If a control string starts from a '+' sign it works
|
|
916 |
.I incrementally,
|
|
917 |
that is, it can modify existing state without overriding it. In such a
|
|
918 |
string every flag may be preceded by a '+' or '-' to enable or disable
|
|
919 |
a corresponding option in the debugger state. This section summarizes
|
|
920 |
the currently available debugger options and the flag characters which
|
|
921 |
enable or disable them. Argument lists enclosed in '[' and ']' are
|
|
922 |
optional.
|
|
923 |
.SP 2
|
|
924 |
.BL 22
|
|
925 |
.LI a[,file]
|
|
926 |
Redirect the debugger output stream and append it to the specified
|
|
927 |
file. The default output stream is stderr. A null argument list
|
|
928 |
causes output to be redirected to stdout.
|
|
929 |
.SP 1
|
|
930 |
EX: \fCa,C:\\tmp\\log\fR
|
|
931 |
.LI A[,file]
|
|
932 |
Like 'a[,file]' but ensure that data are written after each write
|
|
933 |
(this typically implies flush or close/reopen). It helps to get
|
|
934 |
a complete log file in case of crashes. This mode is implicit in
|
|
935 |
multi-threaded environment.
|
|
936 |
.LI d[,keywords]
|
|
937 |
Enable output from macros with specified keywords.
|
|
938 |
An empty list of keywords implies that all keywords are selected.
|
|
939 |
.LI D[,time]
|
|
940 |
Delay for specified time after each output line, to let output drain.
|
|
941 |
Time is given in tenths of a second (value of 10 is one second).
|
|
942 |
Default is zero.
|
|
943 |
.LI f[,functions]
|
|
944 |
Limit debugger actions to the specified list of functions.
|
|
945 |
An empty list of functions implies that all functions are selected.
|
|
946 |
.LI F
|
|
947 |
Mark each debugger output line with the name of the source file
|
|
948 |
containing the macro causing the output.
|
|
949 |
.LI i
|
|
950 |
Mark each debugger output line with the PID (or thread ID) of the
|
|
951 |
current process.
|
|
952 |
.LI g,[functions]
|
|
953 |
Enable profiling for the specified list of functions.
|
|
954 |
An empty list of functions enables profiling for all functions.
|
|
955 |
See
|
|
956 |
.B PROFILING\ WITH\ DBUG
|
|
957 |
below.
|
|
958 |
.LI L
|
|
959 |
Mark each debugger output line with the source file line number of
|
|
960 |
the macro causing the output.
|
|
961 |
.LI n
|
|
962 |
Mark each debugger output line with the current function nesting depth.
|
|
963 |
.LI N
|
|
964 |
Sequentially number each debugger output line starting at 1.
|
|
965 |
This is useful for reference purposes when debugger output is
|
|
966 |
interspersed with program output.
|
|
967 |
.LI o[,file]
|
|
968 |
Like 'a[,file]' but overwrite old file, do not append.
|
|
969 |
.LI O[,file]
|
|
970 |
Like 'A[,file]' but overwrite old file, do not append.
|
|
971 |
.LI p[,processes]
|
|
972 |
Limit debugger actions to the specified processes. An empty list
|
|
973 |
implies all processes. This is useful for processes which run child
|
|
974 |
processes. Note that each debugger output line can be marked with the
|
|
975 |
name of the current process via the 'P' flag. The process name must
|
|
976 |
match the argument passed to the
|
|
977 |
.B DBUG_PROCESS
|
|
978 |
macro.
|
|
979 |
.LI P
|
|
980 |
Mark each debugger output line with the name of the current process.
|
|
981 |
Most useful when used with a process which runs child processes that
|
|
982 |
are also being debugged. Note that the parent process must arrange
|
|
983 |
for the debugger control string to be passed to the child processes.
|
|
984 |
.LI r
|
|
985 |
Used in conjunction with the
|
|
986 |
.B DBUG_PUSH
|
|
987 |
macro to reset the current
|
|
988 |
indentation level back to zero.
|
|
989 |
Most useful with
|
|
990 |
.B DBUG_PUSH
|
|
991 |
macros used to temporarily alter the
|
|
992 |
debugger state.
|
|
993 |
.LI S
|
|
994 |
When compiled with
|
|
995 |
.I safemalloc
|
|
996 |
this flag forces "sanity" memory checks (for overwrites/underwrites)
|
|
997 |
on each
|
|
998 |
.B DBUG_ENTER
|
|
999 |
and
|
|
1000 |
.B DBUG_RETURN.
|
|
1001 |
.LI t[,N]
|
|
1002 |
Enable function control flow tracing.
|
|
1003 |
The maximum nesting depth is specified by N, and defaults to
|
|
1004 |
200.
|
|
1005 |
.LI T
|
|
1006 |
Mark each debugger output line with the current timestamp.
|
|
1007 |
The value is printed with microsecond resolution, as returned by
|
|
1008 |
.I gettimeofday()
|
|
1009 |
system call. The actual resolution is OS- and hardware-dependent.
|
|
1010 |
.LE
|
|
1011 |
||
1012 |
.SK
|
|
1013 |
.B
|
|
1014 |
MULTI-THREADED DEBUGGING
|
|
1015 |
.R
|
|
1016 |
||
1017 |
.P
|
|
1018 |
When
|
|
1019 |
.I dbug
|
|
1020 |
is used in a multi-threaded environment there are few differences from a single-threaded
|
|
1021 |
case to keep in mind. This section tries to summarize them.
|
|
1022 |
.SP 2
|
|
1023 |
.BL 5
|
|
1024 |
.LI
|
|
1025 |
Every thread has its own stack of debugger states.
|
|
1026 |
.B DBUG_PUSH
|
|
1027 |
and
|
|
1028 |
.B DBUG_POP
|
|
1029 |
affect only the thread that executed them.
|
|
1030 |
.LI
|
|
1031 |
At the bottom of the stack for all threads there is the common
|
|
1032 |
.I initial
|
|
1033 |
state. Changes to this state (for example, with
|
|
1034 |
.B DBUG_SET_INITIAL
|
|
1035 |
macro) affect all new threads and all running threads that didn't
|
|
1036 |
.B DBUG_PUSH
|
|
1037 |
yet.
|
|
1038 |
.LI
|
|
1039 |
Every thread can have its own name, that can be set with
|
|
1040 |
.B DBUG_PROCESS
|
|
1041 |
macro. Thus, "-#p,name1,name2" can be used to limit the output to specific threads.
|
|
1042 |
.LI
|
|
1043 |
When printing directly to
|
|
1044 |
.B DBUG_FILE
|
|
1045 |
it may be necessary to prevent other threads from writing something between two parts
|
|
1046 |
of logically indivisible output. It is done with
|
|
1047 |
.B DBUG_LOCK_FILE
|
|
1048 |
and
|
|
1049 |
.B DBUG_UNLOCK_FILE
|
|
1050 |
macors. See the appropriate section for examples.
|
|
1051 |
.LI
|
|
1052 |
"-#o,file" and "-#O,file" are treated as "-#a,file" and "-#A,file" respectively. That is
|
|
1053 |
all writes to a file are always followed by a flush.
|
|
1054 |
.LI
|
|
1055 |
"-#i" prints not a PID but a thread id in the form of "T@nnn"
|
|
1056 |
.LE
|
|
1057 |
||
1058 |
.SK
|
|
1059 |
.B
|
|
1060 |
PROFILING WITH DBUG
|
|
1061 |
.R
|
|
1062 |
||
1063 |
.P
|
|
1064 |
With
|
|
1065 |
.I dbug
|
|
1066 |
one can do profiling in a machine independent fashion,
|
|
1067 |
without a need for profiled version of system libraries.
|
|
1068 |
For this,
|
|
1069 |
.I dbug
|
|
1070 |
can write out a file
|
|
1071 |
called
|
|
1072 |
.B dbugmon.out
|
|
1073 |
(by default). This is an ascii file containing lines of the form:
|
|
1074 |
.DS CB N
|
|
1075 |
\fC<function-name> E <time-entered>
|
|
1076 |
<function-name> X <time-exited>
|
|
1077 |
.DE
|
|
1078 |
||
1079 |
.P
|
|
1080 |
A second program (\fBanalyze\fR) reads this file, and produces a report on
|
|
1081 |
standard output.
|
|
1082 |
||
1083 |
.P
|
|
1084 |
Profiling is enabled through the
|
|
1085 |
.B g
|
|
1086 |
flag. It can take a list of
|
|
1087 |
function names for which profiling is enabled. By default, it
|
|
1088 |
profiles all functions.
|
|
1089 |
||
1090 |
.P
|
|
1091 |
The profile file is opened for appending. This
|
|
1092 |
is in order that one can run a program several times, and get the
|
|
1093 |
sum total of all the times, etc.
|
|
1094 |
||
1095 |
.P
|
|
1096 |
An example of the report generated follows:
|
|
1097 |
.DS CB N
|
|
1098 |
\fC
|
|
1099 |
Profile of Execution
|
|
1100 |
Execution times are in milliseconds
|
|
1101 |
||
1102 |
Calls Time
|
|
1103 |
----- ----
|
|
1104 |
Times Percentage Time Spent Percentage
|
|
1105 |
Function Called of total in Function of total Importance
|
|
1106 |
======== ====== ========== =========== ========== ==========
|
|
1107 |
factorial 5 83.33 30 100.00 8333
|
|
1108 |
main 1 16.67 0 0.00 0
|
|
1109 |
======== ====== ========== =========== ==========
|
|
1110 |
Totals 6 100.00 30 100.00
|
|
1111 |
.DE
|
|
1112 |
.P
|
|
1113 |
As you can see, it's quite self-evident. The
|
|
1114 |
.B Importance
|
|
1115 |
column is a
|
|
1116 |
metric obtained by multiplying the percentage of the calls and the percentage
|
|
1117 |
of the time. Functions with higher 'importance' benefit the most from
|
|
1118 |
being sped up.
|
|
1119 |
||
1120 |
.P
|
|
1121 |
As a limitation - setjmp/longjmp, or child processes, are ignored
|
|
1122 |
for the time being. Also, profiling does not work
|
|
1123 |
in a multi-threaded environment.
|
|
1124 |
||
1125 |
.P
|
|
1126 |
Profiling code is (c) Binayak Banerjee.
|
|
1127 |
||
1128 |
.SK
|
|
1129 |
.B
|
|
1130 |
HINTS AND MISCELLANEOUS
|
|
1131 |
.R
|
|
1132 |
||
1133 |
.P
|
|
1134 |
One of the most useful capabilities of the
|
|
1135 |
.I dbug
|
|
1136 |
package is to compare the executions of a given program in two
|
|
1137 |
different environments.
|
|
1138 |
This is typically done by executing the program in the environment
|
|
1139 |
where it behaves properly and saving the debugger output in a
|
|
1140 |
reference file.
|
|
1141 |
The program is then run with identical inputs in the environment where
|
|
1142 |
it misbehaves and the output is again captured in a reference file.
|
|
1143 |
The two reference files can then be differentially compared to
|
|
1144 |
determine exactly where execution of the two processes diverges.
|
|
1145 |
||
1146 |
.P
|
|
1147 |
A related usage is regression testing where the execution of a current
|
|
1148 |
version is compared against executions of previous versions.
|
|
1149 |
This is most useful when there are only minor changes.
|
|
1150 |
||
1151 |
.P
|
|
1152 |
It is not difficult to modify an existing compiler to implement
|
|
1153 |
some of the functionality of the
|
|
1154 |
.I dbug
|
|
1155 |
package automatically, without source code changes to the
|
|
1156 |
program being debugged.
|
|
1157 |
In fact, such changes were implemented in a version of the
|
|
1158 |
Portable C Compiler by the author in less than a day.
|
|
1159 |
However, it is strongly encouraged that all newly
|
|
1160 |
developed code continue to use the debugger macros
|
|
1161 |
for the portability reasons noted earlier.
|
|
1162 |
The modified compiler should be used only for testing existing
|
|
1163 |
programs.
|
|
1164 |
||
1165 |
.SK
|
|
1166 |
.B
|
|
1167 |
CAVEATS
|
|
1168 |
.R
|
|
1169 |
||
1170 |
.P
|
|
1171 |
The
|
|
1172 |
.I dbug
|
|
1173 |
package works best with programs which have "line\ oriented"
|
|
1174 |
output, such as text processors, general purpose utilities, etc.
|
|
1175 |
It can be interfaced with screen oriented programs such as
|
|
1176 |
visual editors by redefining the appropriate macros to call
|
|
1177 |
special functions for displaying the debugger results.
|
|
1178 |
Of course, this caveat is not applicable if the debugger output
|
|
1179 |
is simply dumped into a file for post-execution examination.
|
|
1180 |
||
1181 |
.P
|
|
1182 |
Programs which use memory allocation functions other than
|
|
1183 |
.B malloc
|
|
1184 |
will usually have problems using the standard
|
|
1185 |
.I dbug
|
|
1186 |
package.
|
|
1187 |
The most common problem is multiply allocated memory.
|
|
1188 |
.SP 2
|
|
1189 |
.\" .DE nroff dident like this. davida 900108
|
|
1190 |
.CS
|
|
1191 |
||
1192 |
.\" vim:filetype=nroff
|