| 263 |
dpurdie |
1 |
SHERLOCK
|
|
|
2 |
C Programming Tool
|
|
|
3 |
|
|
|
4 |
|
|
|
5 |
February 1, 1990
|
|
|
6 |
Version 1.5
|
|
|
7 |
|
|
|
8 |
|
|
|
9 |
Edward K. Ream
|
|
|
10 |
1617 Monroe Street.
|
|
|
11 |
Madison, WI 53711
|
|
|
12 |
|
|
|
13 |
|
|
|
14 |
|
|
|
15 |
CHAPTER 1 INTRODUCING SHERLOCK
|
|
|
16 |
|
|
|
17 |
|
|
|
18 |
Welcome to Sherlock! Sherlock is not an ordinary programming tool and
|
|
|
19 |
you may have some questions about it: what is it, what features does it
|
|
|
20 |
have, how does it operate, how will it benefit you, how do you use it, how
|
|
|
21 |
does it compare with other tools and techniques, how easy will it be to use,
|
|
|
22 |
how can you customize it? This chapter poses and answers these kinds of
|
|
|
23 |
questions and along the way provides examples showing how to use
|
|
|
24 |
Sherlock.
|
|
|
25 |
|
|
|
26 |
|
|
|
27 |
What is Sherlock, anyway?
|
|
|
28 |
|
|
|
29 |
Sherlock is a debugging, tracing and profiling tool for the C programming
|
|
|
30 |
language. That is, Sherlock allows you to test and debug C programs by
|
|
|
31 |
examining various traces. As an added benefit, Sherlock offers detailed
|
|
|
32 |
statistics about your program. Sherlock consists of C language macros
|
|
|
33 |
and support routines called by those macros.
|
|
|
34 |
|
|
|
35 |
|
|
|
36 |
Why should I use Sherlock?
|
|
|
37 |
|
|
|
38 |
Sherlock allows you to build, study, enhance and maintain more complex
|
|
|
39 |
programs in less time. It gives you a better view of your program than
|
|
|
40 |
other kinds of debuggersDyou get more useful information and less
|
|
|
41 |
useless data. Sherlock reveals your program at any level you wish, from a
|
|
|
42 |
global, overall, landscape view to a very detailed view. And you get to choose the exact format in which the information is presented. Sherlock
|
|
|
43 |
is very flexible and can be used with very large and complex programs,
|
|
|
44 |
including programs that use overlays and re-entrant programs.
|
|
|
45 |
|
|
|
46 |
|
|
|
47 |
How does Sherlock work?
|
|
|
48 |
|
|
|
49 |
The basic idea behind Sherlock is simple: you can create individual tracing
|
|
|
50 |
instructions, written in the C language, which lie dormant in your program
|
|
|
51 |
until enabled while your program is executing.
|
|
|
52 |
|
|
|
53 |
|
|
|
54 |
That sounds very simple. What's the big deal?
|
|
|
55 |
|
|
|
56 |
The ability to add hide latent instructions inside a program and to enable
|
|
|
57 |
them while the program is running turns out to be very powerful.
|
|
|
58 |
Typically these dormant instructions are tracing statements such as print
|
|
|
59 |
statements. By enabling various sets of these tracing instructions you can
|
|
|
60 |
produce literally thousands of different traces from your program without
|
|
|
61 |
changing it or recompiling it. This is a very fast and handy way of
|
|
|
62 |
pinpointing the location of bugs, especially pointer bugs.
|
|
|
63 |
|
|
|
64 |
|
|
|
65 |
Isn't using Sherlock like putting print statements throughout a program?
|
|
|
66 |
|
|
|
67 |
Not really. If you just insert print statements throughout your program
|
|
|
68 |
you are buried in useless output. The sheer volume of the output hides the
|
|
|
69 |
information that would make a difference to you. The only way to make
|
|
|
70 |
sense of the output is to get rid of most of it. Alas, removing the print
|
|
|
71 |
statements and recompiling takes a lot of time. Also, once print statements
|
|
|
72 |
have been removed they are not available later until they have been re-
|
|
|
73 |
inserted and and the program recompiled and relinked. You just can't be
|
|
|
74 |
very flexible this way.
|
|
|
75 |
|
|
|
76 |
With Sherlock, you enable tracing statements without changing your
|
|
|
77 |
program in any way. Generating different traces is done in a matter of
|
|
|
78 |
seconds, not minutes. And since your program remains unchanged, bugs
|
|
|
79 |
remain stable; their symptoms do not change as they would if you added
|
|
|
80 |
or deleted print statements.
|
|
|
81 |
|
|
|
82 |
|
|
|
83 |
How is it possible to enable or disable a single C instruction?
|
|
|
84 |
|
|
|
85 |
It's done with macros. The instruction or instructions are entered as the
|
|
|
86 |
arguments to special tracing macros. For instance, suppose you want to
|
|
|
87 |
disable the following print statement:
|
|
|
88 |
|
|
|
89 |
printf("The value of i is %d\n", i);
|
|
|
90 |
|
|
|
91 |
The TRACE macro is one of several that you might use. It takes two
|
|
|
92 |
arguments. The first is the name that will be given to the disabled
|
|
|
93 |
statement, say "abc". The second is the statement or statements we want to
|
|
|
94 |
disable. The complete TRACE macro would look like this:
|
|
|
95 |
|
|
|
96 |
TRACE("abc", printf("The value of i is %d\n", i));
|
|
|
97 |
|
|
|
98 |
Let's look at this carefully. The name given to the print statement is
|
|
|
99 |
represented by the C string "abc". The comma after the "abc" separates the
|
|
|
100 |
two arguments. Next comes the printf statement and two right
|
|
|
101 |
parentheses, one for the printf statement and one for the TRACE macro.
|
|
|
102 |
Notice that the semicolon that ends the printf statement has been omitted.
|
|
|
103 |
It would also be all right to leave it in, like this:
|
|
|
104 |
|
|
|
105 |
TRACE("abc", printf("The value of i is %d\n", i););
|
|
|
106 |
|
|
|
107 |
The effect of this macro is as follows: the print statement is executed when
|
|
|
108 |
control reaches the macro only if the symbol "abc" has already been
|
|
|
109 |
enabled.
|
|
|
110 |
|
|
|
111 |
Please note: the operation of the TRACE macro varies drastically from the
|
|
|
112 |
more traditional kind of debugging macros often used in programming
|
|
|
113 |
projects. Sherlock macros enable or disable tracing code during the
|
|
|
114 |
execution of the program.. Traditional debugging macros require that the
|
|
|
115 |
program be recompiled in order to enable or disable the code in the macros
|
|
|
116 |
The effect of this difference is enormous.
|
|
|
117 |
|
|
|
118 |
|
|
|
119 |
Can other kinds of statements besides print statements be used?
|
|
|
120 |
|
|
|
121 |
Yes. You can disable any executable C statement or sequence of
|
|
|
122 |
statements, including blocks. For instance, a very useful kind of tracing
|
|
|
123 |
statement might be a function call which would print out a complicated data
|
|
|
124 |
structure.
|
|
|
125 |
|
|
|
126 |
|
|
|
127 |
How do you tell Sherlock which macros you want to enable or disable?
|
|
|
128 |
|
|
|
129 |
The most common way is to add special arguments to the command line.
|
|
|
130 |
For instance, to enable any macro whose name is "abc" you would add the
|
|
|
131 |
following argument to the command line:
|
|
|
132 |
|
|
|
133 |
++abc
|
|
|
134 |
|
|
|
135 |
You can also enable macros while your program is running using other
|
|
|
136 |
Sherlock macros.
|
|
|
137 |
|
|
|
138 |
Won't the extra command line arguments interfere with my program?
|
|
|
139 |
|
|
|
140 |
No. Sherlock removes these special arguments from the command line so
|
|
|
141 |
they will be completely invisible to your program. They will not interfere
|
|
|
142 |
with the argument processing logic of your program in any way.
|
|
|
143 |
|
|
|
144 |
|
|
|
145 |
How does Sherlock know which arguments to delete from the command line?
|
|
|
146 |
|
|
|
147 |
All Sherlock arguments are preceded by one of two prefixes: an "on
|
|
|
148 |
prefix" that enables macros and an "off-prefix" that disables macros. You
|
|
|
149 |
should choose each prefix to be something that will distinguish Sherlock
|
|
|
150 |
arguments from all other arguments to your program. In the example
|
|
|
151 |
above, the prefix is ++.
|
|
|
152 |
|
|
|
153 |
|
|
|
154 |
Putting these macros into my programs seems like a lot of work to me.
|
|
|
155 |
|
|
|
156 |
Sherlock includes a utility program called SPP, for Sherlock Pre-Processor,
|
|
|
157 |
which will put macros at the entry and exit of all your functions
|
|
|
158 |
automatically, which is where you most often want them.
|
|
|
159 |
|
|
|
160 |
|
|
|
161 |
You mentioned that Sherlock is also a profiling tool. What does that mean?
|
|
|
162 |
|
|
|
163 |
Sherlock gathers statistics automatically. Sherlock counts how many times
|
|
|
164 |
each macro was encountered and also computes timing statistics using an
|
|
|
165 |
interrupt handler. Sherlock associates these statistics with the names
|
|
|
166 |
defined by the macros. All the details are handled by the macros. You
|
|
|
167 |
may print a report of the statistics at any time.
|
|
|
168 |
|
|
|
169 |
|
|
|
170 |
How many Sherlock macros are there?
|
|
|
171 |
|
|
|
172 |
Over 30.
|
|
|
173 |
|
|
|
174 |
|
|
|
175 |
Why so many?
|
|
|
176 |
|
|
|
177 |
Many macros do the same basic thing with minor variations. For instance,
|
|
|
178 |
there is a TRACEP macro which is acts the same as TRACE except that
|
|
|
179 |
TRACEP prints its first argument, i.e., the name associated with the
|
|
|
180 |
macro, before executing the disabled instruction. This saves some space in
|
|
|
181 |
your program. There are also macros used to initialize the Sherlock
|
|
|
182 |
system, to enable or disable macros, and to print a report of statistics.
|
|
|
183 |
|
|
|
184 |
|
|
|
185 |
Must I remove all the macros when I am done debugging?
|
|
|
186 |
|
|
|
187 |
No. You can simply undefine a single compile-time variable, recompile
|
|
|
188 |
and relink. All the code generated by the macros will disappear and the
|
|
|
189 |
executable portion of your program will contain absolutely no evidence that
|
|
|
190 |
Sherlock macros exist in the source code. Thus, there is no need to
|
|
|
191 |
physically eliminate the macros from your source files. There is a utility
|
|
|
192 |
program, called SDEL, which will remove Sherlock macros from a source
|
|
|
193 |
file if you want.
|
|
|
194 |
|
|
|
195 |
|
|
|
196 |
Can I choose different names for the Sherlock macros?
|
|
|
197 |
|
|
|
198 |
Yes. All you have to do is to change names defined in a standard header
|
|
|
199 |
file. You will still be able to use SPP and SDEL. Both tools allow you to
|
|
|
200 |
specify alternate macro names to be used instead of the standard macro
|
|
|
201 |
names.
|
|
|
202 |
|
|
|
203 |
|
|
|
204 |
What if I want to change how the macros work?
|
|
|
205 |
|
|
|
206 |
Full source code is provided for all macros, support routines and utility
|
|
|
207 |
programs except SPP. To use the Sherlock system on another machine you
|
|
|
208 |
need only recompile the support routines on the new machines. You will
|
|
|
209 |
need to rewrite the interrupt handler only if you wish to gather timing
|
|
|
210 |
statistics on the new machineDSherlock will work without the interrupt
|
|
|
211 |
handler.
|
|
|
212 |
|
|
|
213 |
|
|
|
214 |
|
|
|
215 |
CHAPTER 2 BEFORE USING SHERLOCK
|
|
|
216 |
|
|
|
217 |
|
|
|
218 |
This chapter provides information you should know before using
|
|
|
219 |
Sherlock. It lists the hardware and software required, it reminds you to
|
|
|
220 |
create a backup copy of the distribution disk containing Sherlock, and it
|
|
|
221 |
lists the files that are distributed with the Sherlock system.
|
|
|
222 |
|
|
|
223 |
|
|
|
224 |
System Requirements
|
|
|
225 |
|
|
|
226 |
o An IBM PC/XT/AT computer or compatible with two floppy disks or a
|
|
|
227 |
hard disk.
|
|
|
228 |
|
|
|
229 |
o The MS-DOS operating system.
|
|
|
230 |
|
|
|
231 |
o Either the Microsoft C compiler or the Turbo C compiler. Minor
|
|
|
232 |
modifications in Sherlock's source code will allow Sherlock to compile
|
|
|
233 |
using other C compilers.
|
|
|
234 |
|
|
|
235 |
o The Microsoft MASM macro assembler. (Used only when changing the
|
|
|
236 |
interrupt handler.)
|
|
|
237 |
|
|
|
238 |
|
|
|
239 |
Backing Up Your Disks
|
|
|
240 |
|
|
|
241 |
Please back up the distribution disks before using Sherlock. Use the DOS
|
|
|
242 |
COPY command to copy all the files on the distribution disks to backup
|
|
|
243 |
disks. Your backup disks will be used as working disks.
|
|
|
244 |
|
|
|
245 |
|
|
|
246 |
Files on Your Disk
|
|
|
247 |
|
|
|
248 |
File Description
|
|
|
249 |
|
|
|
250 |
read.me Late breaking news and information. Please read
|
|
|
251 |
this file first.
|
|
|
252 |
*.mak Make files for the Turbo C compiler version 1.5.
|
|
|
253 |
*.mmk Make files for the Microsoft C compiler version
|
|
|
254 |
5.00 or later.
|
|
|
255 |
*.lnk Link files for the Turbo C linker.
|
|
|
256 |
*.ml Link files for the Microsoft linker.
|
|
|
257 |
cpp.exe C Preprocessor whose source code illustrates the
|
|
|
258 |
use of Sherlock's macros.
|
|
|
259 |
\cpp\*.c Source code for CPP.
|
|
|
260 |
\cpp\*.h Header file for CPP.
|
|
|
261 |
dumpregs.c C Language source code for a program illustrating
|
|
|
262 |
the use of regs.asm.
|
|
|
263 |
prf.asm Assembly language source code for the interrupt
|
|
|
264 |
handler.
|
|
|
265 |
prfnear.obj Object code for interrupt handlerDfor memory
|
|
|
266 |
models with small code spaces.
|
|
|
267 |
prffar.obj Object code for interrupt handlerDfor memory
|
|
|
268 |
models with large code spaces.
|
|
|
269 |
regs.asm Assembly language source code for the register
|
|
|
270 |
dumper.
|
|
|
271 |
regsnear.obj Object code for the register dumperDfor memory
|
|
|
272 |
models with small code spaces.
|
|
|
273 |
regsfar.obj Object code for the register dumperDfor memory
|
|
|
274 |
models with large code spaces.
|
|
|
275 |
sdel.exe Utility program which deletes all Sherlock macros
|
|
|
276 |
from a single source file.
|
|
|
277 |
sdel.c C language source code for SDEL illustrating the
|
|
|
278 |
use of Sherlock's macros.
|
|
|
279 |
sdif.exe Special purpose file comparison program.
|
|
|
280 |
sdif.c The C language source code for SDIF.
|
|
|
281 |
sherlock.c C language source code for support routines.
|
|
|
282 |
sl.h Preferred definitions of macros.
|
|
|
283 |
sl1.h Alternate definitions of macros.
|
|
|
284 |
spp.exe Utility program which inserts Sherlock macros
|
|
|
285 |
into a single source file.
|
|
|
286 |
|
|
|
287 |
|
|
|
288 |
Quick Start
|
|
|
289 |
|
|
|
290 |
This is the super-condensed version of the installation procedure.
|
|
|
291 |
|
|
|
292 |
1. Insert Sherlock macros into functions that you want to trace. Sherlock
|
|
|
293 |
comes with a stand alone tool, called SPP, which will do this automatically
|
|
|
294 |
for you. See the section called SPP of the User's Manual for details.
|
|
|
295 |
|
|
|
296 |
2. Insert the SL_INIT and SL_PARSE macros into your main() function as
|
|
|
297 |
the first executable statements. Again, SPP will do this automatically for
|
|
|
298 |
you.
|
|
|
299 |
|
|
|
300 |
3. Insert the line #include "sl.h" in each source file containing a
|
|
|
301 |
Sherlock macro. This can be done automatically using the -i option of
|
|
|
302 |
SPP. Alternatively, if you have a single header file which is inserted in all
|
|
|
303 |
your source files, insert the line #include "sl.h" in that header file.
|
|
|
304 |
|
|
|
305 |
4. Recompile all files which contain Sherlock macros. Make sure to
|
|
|
306 |
#define the compile time symbol called SHERLOCK. The easiest and best
|
|
|
307 |
way to do this is with a command line option to the compiler.
|
|
|
308 |
|
|
|
309 |
5. Compile the source code for the Sherlock support routines, located in
|
|
|
310 |
sherlock.c. Make sure the memory model used when compiling the
|
|
|
311 |
support routines is the same as the memory model used when compiling
|
|
|
312 |
the rest of the files of your program. Sample make and link files to
|
|
|
313 |
accomplish this step are included in the directory called sherlock.
|
|
|
314 |
|
|
|
315 |
6. Link the following files together to produce an executable version of
|
|
|
316 |
your program:
|
|
|
317 |
|
|
|
318 |
o All the .obj files produced by compiling the files of your program.
|
|
|
319 |
o The .obj file produced by compiling sherlock.c.
|
|
|
320 |
o One (and only one) of the following two files: prffar.obj or prfnear.obj.
|
|
|
321 |
|
|
|
322 |
Note: Use prffar.obj when using memory models that have a code space
|
|
|
323 |
larger than 64K. Use prfnear when using memory models that have a code
|
|
|
324 |
space limited to 64K or less.
|
|
|
325 |
|
|
|
326 |
7. Run your program. To enable traces, add Sherlock command line
|
|
|
327 |
arguments to your program's command line. For example, to enable
|
|
|
328 |
tracing of a function called f(), add the argument ++f to the command line.
|
|
|
329 |
|
|
|
330 |
8. When you are done debugging, recompile all your files which contain
|
|
|
331 |
Sherlock macros with the compile time constant SHERLOCK not
|
|
|
332 |
#define'd. The code produced by the Sherlock macros will disappear.
|
|
|
333 |
Relink all those files to produce a production version of your program. Do
|
|
|
334 |
not link in the .obj file produced by compiling sherlock.c. Do not link in
|
|
|
335 |
either prffar.obj or prfnear.obj.
|
|
|
336 |
|
|
|
337 |
|
|
|
338 |
|
|
|
339 |
CHAPTER 3 USING SHERLOCK
|
|
|
340 |
|
|
|
341 |
|
|
|
342 |
This chapter contains a tutorial introduction to Sherlock. It tells you
|
|
|
343 |
everything you need to know to start using Sherlock. After an initial
|
|
|
344 |
overview, the various macros comprising Sherlock will be discussed in
|
|
|
345 |
detail, with numerous examples along the way. The last section discusses
|
|
|
346 |
how to enable macros using command line arguments. For some tips
|
|
|
347 |
about debugging C programs, see the next chapter. For the most complete
|
|
|
348 |
information about any aspect of the Sherlock system, see chapter five.
|
|
|
349 |
|
|
|
350 |
|
|
|
351 |
Overview
|
|
|
352 |
|
|
|
353 |
The Sherlock system consists of three main parts: tracing macros, other
|
|
|
354 |
macros including initialization and statistics reporting macros and support
|
|
|
355 |
routines called by the macros. The support routines form the "hidden
|
|
|
356 |
machinery" of the Sherlock system and will not be discussed further in this
|
|
|
357 |
overview.
|
|
|
358 |
|
|
|
359 |
Sherlock's tracing macros are the most visible and important part of the
|
|
|
360 |
Sherlock system. These tracing macros allow you to create tracing
|
|
|
361 |
statements embedded throughout your program which can be enabled or
|
|
|
362 |
disabled without recompiling your program or changing the executable
|
|
|
363 |
image of your program in any way. Tracing macros also provide a
|
|
|
364 |
framework for gathering statistics about your program.
|
|
|
365 |
|
|
|
366 |
Each tracing macro defines a tracepoint, a tracepoint name and a list of
|
|
|
367 |
tracepoint actions. A tracepoint is simply the location of the macro, the
|
|
|
368 |
tracepoint name is a C language string which names the tracepoint and the
|
|
|
369 |
tracepoint actions consist of one or more executable C language statements
|
|
|
370 |
which are executed only if the tracepoint has been enabled.
|
|
|
371 |
|
|
|
372 |
Let's look at one kind of tracing macro, called TRACE. The format of this
|
|
|
373 |
macro is:
|
|
|
374 |
|
|
|
375 |
TRACE(tracepoint_name, tracepoint_actions);
|
|
|
376 |
|
|
|
377 |
In other words, this macro takes two arguments, a tracepoint name and a
|
|
|
378 |
list of tracepoint actions. For example:
|
|
|
379 |
|
|
|
380 |
TRACE("print_abc", printf("The value of abc is %d/n", abc));
|
|
|
381 |
|
|
|
382 |
Notice the two closing parentheses. The first ends the printf statement and
|
|
|
383 |
the second ends the TRACE macro. In this example, the tracepoint name is
|
|
|
384 |
a string
|
|
|
385 |
|
|
|
386 |
literal, namely "print_abc", and the tracepoint actions consists of the single
|
|
|
387 |
statement:
|
|
|
388 |
|
|
|
389 |
printf("The value of abc is %d/n", abc);
|
|
|
390 |
|
|
|
391 |
The operation of this TRACE macro is straightforward: the print statement
|
|
|
392 |
will be executed only if the tracepoint named print_abc has been enabled.
|
|
|
393 |
|
|
|
394 |
Please note: the operation of the TRACE macro varies drastically from the
|
|
|
395 |
more traditional kind of debugging macros often used in programming
|
|
|
396 |
projects. Sherlock macros enable or disable tracing code during the
|
|
|
397 |
execution of the program. Traditional debugging macros require that the
|
|
|
398 |
program be recompiled in order to enable or disable the code in the macros.
|
|
|
399 |
The effect of this difference is enormous. With Sherlock, you can scatter
|
|
|
400 |
tracing macros throughout your program with no ill effects. With
|
|
|
401 |
traditional debugging macros, this strategy is simply not possible because
|
|
|
402 |
you would be buried in tracing output.
|
|
|
403 |
|
|
|
404 |
How are tracepoints enabled? There are two ways: from the command line
|
|
|
405 |
using special Sherlock arguments or from within your program using
|
|
|
406 |
Sherlock macros. In practice, the command line is most often used.
|
|
|
407 |
Sherlock arguments consist of a prefix followed by a tracepoint name.
|
|
|
408 |
There are two possible prefixes: an on_prefix which enables the following
|
|
|
409 |
tracepoint name and an off_prefix which disables the following tracepoint
|
|
|
410 |
name. These prefixes are defined by an initialization macro called
|
|
|
411 |
SL_PARSE and should be chosen so that Sherlock arguments can be
|
|
|
412 |
distinguished from all other command line arguments. The SL_PARSE
|
|
|
413 |
macro processes all Sherlock arguments and then deletes them from the
|
|
|
414 |
command line so that they will not interfere with the argument processing
|
|
|
415 |
logic of your program.
|
|
|
416 |
|
|
|
417 |
Any string may be used for these prefixes, and in this manual we will
|
|
|
418 |
assume that the on prefix is ++ and the off prefix is - -. For example, to
|
|
|
419 |
enable tracing for the tracepoint named print_abc, the following command
|
|
|
420 |
line argument could be used:
|
|
|
421 |
|
|
|
422 |
++print_abc
|
|
|
423 |
|
|
|
424 |
Wildcard characters and other construction may be used in Sherlock
|
|
|
425 |
arguments. See the section on command line arguments for more details.
|
|
|
426 |
|
|
|
427 |
To summarize, here are the steps to use Sherlock:
|
|
|
428 |
|
|
|
429 |
1. Insert Sherlock macros throughout your program. This is easy because
|
|
|
430 |
Sherlock comes with a utility program called the Sherlock Preprocessor
|
|
|
431 |
(SPP) which will insert tracing macros automatically at the beginning and
|
|
|
432 |
end of every function in a file. The tracing macros created by SPP will
|
|
|
433 |
print the values of all arguments to functions as well as the value returned
|
|
|
434 |
from all functions.
|
|
|
435 |
|
|
|
436 |
2. The Sherlock macros are defined in a header file called sl.h. Insert the
|
|
|
437 |
following statement in every file that contains a Sherlock macro:
|
|
|
438 |
|
|
|
439 |
#include <sl.h>
|
|
|
440 |
|
|
|
441 |
The SPP program will insert this statement for you if you desire.
|
|
|
442 |
|
|
|
443 |
3. Compile the files containing the Sherlock macros as usual and link in the
|
|
|
444 |
support routines to create an executable version of your program.
|
|
|
445 |
|
|
|
446 |
4. Run your program and enable various tracepoints using Sherlock
|
|
|
447 |
command line arguments. On successive runs, focus on important details
|
|
|
448 |
by enabling different tracepoints.
|
|
|
449 |
|
|
|
450 |
5. After debugging is complete, remove the code generated by Sherlock
|
|
|
451 |
macros. You can do this without removing the macros themselves by
|
|
|
452 |
undefining the compile time constant called SHERLOCK and recompiling.
|
|
|
453 |
Absolutely no overhead from the Sherlock macros will remain in your
|
|
|
454 |
program.
|
|
|
455 |
|
|
|
456 |
6. Most people will want to leave Sherlock macros inside their source file
|
|
|
457 |
so that they may be reactivated later by redefining the SHERLOCK
|
|
|
458 |
constant and recompiling. However, a utility called SDEL will remove all
|
|
|
459 |
Sherlock macros from a source file if you desire.
|
|
|
460 |
|
|
|
461 |
This concludes the overview of the Sherlock system. The next sections
|
|
|
462 |
introduce you to all of the Sherlock macros and will discuss details
|
|
|
463 |
concerning Sherlock command line arguments, header files and statistics.
|
|
|
464 |
|
|
|
465 |
|
|
|
466 |
Initialization: SL_INIT, SL_PARSE, SL_ON, and SL_OFF
|
|
|
467 |
|
|
|
468 |
Right at the start of your program, Sherlock's support routines must be
|
|
|
469 |
initialized and the Sherlock arguments on the command line must be
|
|
|
470 |
processed and removed.
|
|
|
471 |
|
|
|
472 |
The SL_INIT macro initializes Sherlock's support routines. This macro
|
|
|
473 |
must be executed before any other macro. The best place for the SL_INIT
|
|
|
474 |
macro is the very first executable statement of the main() routine. The SPP
|
|
|
475 |
program will insert the SL_INIT macro at that spot for you. Note that the
|
|
|
476 |
name is all UPPER CASE, as are the names of all Sherlock macros.
|
|
|
477 |
|
|
|
478 |
In the language of the draft C standard, the SL_INIT macro, like all of the
|
|
|
479 |
Sherlock macros, is a "function-like" macro, which means that parentheses
|
|
|
480 |
are required after it even though the macro takes no arguments. Like this:
|
|
|
481 |
SL_INIT();
|
|
|
482 |
|
|
|
483 |
The SL_PARSE macro enables or disables tracepoints by processing an
|
|
|
484 |
argument list vector. Most often, the vector is simply the argv vector
|
|
|
485 |
passed by the operating system to the main() routine, but it doesn't have to
|
|
|
486 |
beDyou can set up your own if you want. The SL_PARSE macro may be
|
|
|
487 |
called more than once, so you can enable or disable tracepoints from inside
|
|
|
488 |
your program as well as from the command line. Typically, the
|
|
|
489 |
SL_PARSE macro should be placed immediately following the SL_INIT
|
|
|
490 |
macro in the main() routine. Again, the SPP program will insert the
|
|
|
491 |
SL_PARSE macro for you there.
|
|
|
492 |
|
|
|
493 |
SL_PARSE takes four arguments. The format is:
|
|
|
494 |
|
|
|
495 |
SL_PARSE(argc, argv, on_prefix, off_prefix);
|
|
|
496 |
int argc; char *argv[], *on_prefix, *off_prefix;
|
|
|
497 |
|
|
|
498 |
The first two arguments describe an argument list vector just like the argc
|
|
|
499 |
and argv arguments passed to main(). In other words, argv is a pointer to
|
|
|
500 |
a list of strings and argc is one more than the number of arguments in
|
|
|
501 |
argv[]. The argv vector is terminated by a NULL string so that argv[argc]
|
|
|
502 |
is NULL.
|
|
|
503 |
|
|
|
504 |
The on_prefix and off_prefix arguments must be C strings, either string
|
|
|
505 |
literals or pointers to arrays of characters. All arguments (i.e., all strings in
|
|
|
506 |
the argv vector) whose prefix is either on_prefix or off_prefix are
|
|
|
507 |
processed as Sherlock arguments and removed from the argv vector. The
|
|
|
508 |
argc count is decremented by one for every deleted argument. Arguments
|
|
|
509 |
that do not start with either the on_prefix or the off_prefix are not changed
|
|
|
510 |
by SL_PARSE.
|
|
|
511 |
|
|
|
512 |
Here is an example of a typical main routine:
|
|
|
513 |
|
|
|
514 |
main(int argc, char ** argv)
|
|
|
515 |
{
|
|
|
516 |
declarations of local variables.
|
|
|
517 |
|
|
|
518 |
SL_INIT();
|
|
|
519 |
SL_PARSE(argc, argv, "++", "- -");
|
|
|
520 |
|
|
|
521 |
executable statements...
|
|
|
522 |
}
|
|
|
523 |
|
|
|
524 |
All examples in this manual will assume that the prefixes are ++ and - -.
|
|
|
525 |
However, any C string may be used for the off prefix or on prefix. For
|
|
|
526 |
example, to set the on_prefix to !+ and the off_prefix to !-, you would use
|
|
|
527 |
the following call to SL_PARSE:
|
|
|
528 |
|
|
|
529 |
SL_PARSE(argc, argv, "!+", "!-");
|
|
|
530 |
|
|
|
531 |
Here is a program that simply prints its command line arguments. Note
|
|
|
532 |
that it will not print any Sherlock argument, i.e., any argument starting
|
|
|
533 |
with ++ or - -.
|
|
|
534 |
|
|
|
535 |
/* Echo command line arguments. */
|
|
|
536 |
main(argc, argv)
|
|
|
537 |
int argc;
|
|
|
538 |
char **argv;
|
|
|
539 |
{
|
|
|
540 |
int i;
|
|
|
541 |
|
|
|
542 |
/* Process and remove Sherlock arguments. */
|
|
|
543 |
SL_INIT();
|
|
|
544 |
SL_PARSE(argc, argv, "++", "- -");
|
|
|
545 |
|
|
|
546 |
/* Print non-Sherlock arguments. */
|
|
|
547 |
argc- -;
|
|
|
548 |
argv++;
|
|
|
549 |
for (i = 1; i < argc; i++) {
|
|
|
550 |
printf("argv[%d] = %s\n", i, *argv);
|
|
|
551 |
argv++;
|
|
|
552 |
}
|
|
|
553 |
}
|
|
|
554 |
|
|
|
555 |
The SL_ON and SL_OFF macros also enable or disable tracepoints from
|
|
|
556 |
within your program and are easier to use than SL_PARSE. Each macro
|
|
|
557 |
takes one argument, the name of the tracepoint to be enabled or disabled.
|
|
|
558 |
SL_ON enables the tracepoint while SL_OFF disables the tracepoint. The
|
|
|
559 |
name of the tracepoint is not preceded by either the on_prefix or the
|
|
|
560 |
off_prefix.
|
|
|
561 |
The following example shows how to enable tracing for a selected range of
|
|
|
562 |
loop iterations:
|
|
|
563 |
|
|
|
564 |
for (i = 0; i < 100; i++) {
|
|
|
565 |
if (i = = 20) {
|
|
|
566 |
SL_ON("complicated_function");
|
|
|
567 |
}
|
|
|
568 |
complicated_function(i);
|
|
|
569 |
if (i = = 30) {
|
|
|
570 |
SL_OFF("complicated_function");
|
|
|
571 |
}
|
|
|
572 |
}
|
|
|
573 |
|
|
|
574 |
The following sections discuss tracing macros, the heart of the Sherlock
|
|
|
575 |
system.
|
|
|
576 |
|
|
|
577 |
|
|
|
578 |
Tracepoint Names and Statistics: STAT, STATB and STATX
|
|
|
579 |
|
|
|
580 |
STAT is the simplest tracing macro. It takes one argument, a tracepoint
|
|
|
581 |
name. For example:
|
|
|
582 |
|
|
|
583 |
STAT("rose");
|
|
|
584 |
|
|
|
585 |
Although closely related to the other tracing macros, STAT produces no
|
|
|
586 |
output. STAT's only function is to provide a label for a count statistic,
|
|
|
587 |
which is simply the number of times control reaches the tracepoint defined
|
|
|
588 |
by STAT. All tracing macros have a count statistic associated with their
|
|
|
589 |
tracepoint name. Count statistics are always updated regardless of whether
|
|
|
590 |
tracing for a particular tracepoint has been enabled or not.
|
|
|
591 |
|
|
|
592 |
In order to provide better error checking, there are restrictions on the kinds
|
|
|
593 |
of characters that may appear in tracepoint names; tracepoint names may
|
|
|
594 |
contain lower case letters, numerals and the underscore character, but not
|
|
|
595 |
blanks or special characters such as ( ) { } + etc. The following are valid
|
|
|
596 |
tracepoint names:
|
|
|
597 |
|
|
|
598 |
STAT("rose_is_a_rose");
|
|
|
599 |
STAT("rose25");
|
|
|
600 |
|
|
|
601 |
The following are NOT valid tracepoint names:
|
|
|
602 |
|
|
|
603 |
STAT("rose water"); blank character
|
|
|
604 |
STAT("wine&roses"); & special character
|
|
|
605 |
|
|
|
606 |
There are two additional members of the STAT family, STATB and
|
|
|
607 |
STATX. These two macros are used to gather timing statistics. Timing
|
|
|
608 |
statistics are generally more useful than count statistics since they relate
|
|
|
609 |
directly to program speed. On the other hand, timing statistics are a little
|
|
|
610 |
more difficult to gather than count statistics. Timing statistics measure the
|
|
|
611 |
time spent in timing code.
|
|
|
612 |
|
|
|
613 |
The STATB macro works just like the STAT macro, except that the STATB
|
|
|
614 |
macro is an entry macro, that is, STATB defines the start of a section of
|
|
|
615 |
timing code. Similarly, the STATX macro is an exit macro, that is, STATX
|
|
|
616 |
defines the end of a section of timing code. In general, the suffix 'B' in the
|
|
|
617 |
name of a tracing macro indicates that the macro is an entry macro, while
|
|
|
618 |
the suffix 'X' in the name of a tracing macro indicates the macro is an exit
|
|
|
619 |
macro. Count statistics are updated for STATB but not STATX.
|
|
|
620 |
|
|
|
621 |
Most often, timing code consists of an entire function, though that is not
|
|
|
622 |
required. For example, to measure the time spent in a function without
|
|
|
623 |
generating any tracing message you would do something like:
|
|
|
624 |
|
|
|
625 |
int f()
|
|
|
626 |
{
|
|
|
627 |
STATB("f");
|
|
|
628 |
body of f;
|
|
|
629 |
STATX("f");
|
|
|
630 |
}
|
|
|
631 |
|
|
|
632 |
The support routines keep track of statistics using an internal timing stack.
|
|
|
633 |
At run time, each entry macro must be paired eventually with an exit
|
|
|
634 |
macro. For example, if you put an entry macro at the beginning of a
|
|
|
635 |
function then every exit from the macro must contain an exit macro. When
|
|
|
636 |
an exit macro is executed, Sherlock verifies that its tracepoint name
|
|
|
637 |
matches the tracepoint name of the last entry macro, i.e., the macro on the
|
|
|
638 |
top of the timing stack. A warning message occurs if there is a mismatch.
|
|
|
639 |
Such a warning indicates that timing statistics are not accurate.
|
|
|
640 |
|
|
|
641 |
The current nesting level is the number of entry macros that have been
|
|
|
642 |
executed for which an exit macro has not been executed. The output from
|
|
|
643 |
all tracing macros is preceded by level dots, i.e., one period for each level
|
|
|
644 |
of nesting.
|
|
|
645 |
|
|
|
646 |
Sherlock provides two kinds of timing statistics: cumulative and non-
|
|
|
647 |
cumulative. Cumulative timing statistics measure the total time spent in
|
|
|
648 |
timing code, including any time spent in nested timing code. Non-
|
|
|
649 |
cumulative timing statistics excludes time spent in nested timing code. In
|
|
|
650 |
other words, cumulative statistics are incremented at all levels of the timing
|
|
|
651 |
stack, while non-cumulative statistics are updated only at the top of the
|
|
|
652 |
timing stack.
|
|
|
653 |
|
|
|
654 |
The following paragraphs will be of interest only to advanced users of
|
|
|
655 |
Sherlock who wish to gather the best timing statistics possible. Thanks go
|
|
|
656 |
to James E.G. Morris of Atari Games Corporation for suggesting
|
|
|
657 |
improvements in the way timing statistics are handled.
|
|
|
658 |
|
|
|
659 |
Version 1.5 of the support routines provides ways to adjust the timing
|
|
|
660 |
statistics gathered by Sherlock to factor out the overhead caused by calling
|
|
|
661 |
and returning from the Sherlock macros. The Sherlock support routine
|
|
|
662 |
sl_dump() now subtracts a "fudge factor," called TIME_ADJUST, from
|
|
|
663 |
the timing statistics as the report of the statistics is being generated. This
|
|
|
664 |
fudge factor affects only the output of the SL_DUMP macroDthe actual
|
|
|
665 |
gathering of timing statistics is not affected in any way by
|
|
|
666 |
TIME_ADJUST.
|
|
|
667 |
|
|
|
668 |
The units of TIME_ADJUST are ticks per 1000 calls to Sherlock macros,
|
|
|
669 |
and TIME_ADJUST is supplied as a compile-time constant on the
|
|
|
670 |
command line when compiling sherlock.c. If no value for
|
|
|
671 |
TIME_ADJUST is supplied, it is set to zero, which is what you get by
|
|
|
672 |
default.
|
|
|
673 |
|
|
|
674 |
The proper value of TIME_ADJUST depends on several factors: the speed
|
|
|
675 |
of your machine, its "tick" rate, the "speed up rate," i.e., the value of
|
|
|
676 |
sl_speed used in sherlock.c, which version of Sherlock macros is used,
|
|
|
677 |
preferred or alternate, and which memory model is used to compile your
|
|
|
678 |
program. A new utility program, called measure.c, measures the time
|
|
|
679 |
overhead involved in calling Sherlock macros, and suggests appropriate
|
|
|
680 |
values for TIME_ADJUST.
|
|
|
681 |
|
|
|
682 |
|
|
|
683 |
Here I am Messages: TICK, TICKB, TICKN and TICKX
|
|
|
684 |
|
|
|
685 |
The simplest kind of tracing output is a "here I am" message. The TICK
|
|
|
686 |
family of macros provide such messages. The TICK macro takes exactly
|
|
|
687 |
one argument, a tracepoint name. Examples:
|
|
|
688 |
|
|
|
689 |
char name[] = "petunia";
|
|
|
690 |
TICK(name);
|
|
|
691 |
TICK("marigold");
|
|
|
692 |
|
|
|
693 |
If enabled, TICK simply prints the name of the tracepoint followed by a
|
|
|
694 |
colon. The output created from the examples above would look like:
|
|
|
695 |
|
|
|
696 |
petunia:
|
|
|
697 |
marigold:
|
|
|
698 |
|
|
|
699 |
The only difference between TICK and TICKN is that TICK updates the
|
|
|
700 |
count statistic associated with the tracepoint name and TICKN does not. In
|
|
|
701 |
general, the suffix 'N' in the name of a tracing macro indicates that count
|
|
|
702 |
statistics are not updated by the macro.
|
|
|
703 |
|
|
|
704 |
Why suppress the gathering of count statistics? You might use TICKN
|
|
|
705 |
rather than TICK in order not to count the same section of code twice. For
|
|
|
706 |
example:
|
|
|
707 |
|
|
|
708 |
do {
|
|
|
709 |
TICK("loop");
|
|
|
710 |
...
|
|
|
711 |
TICKN("loop");
|
|
|
712 |
} while (waiting);
|
|
|
713 |
|
|
|
714 |
Since only one TICK macro was used in the loop, the count statistic for
|
|
|
715 |
"loop" will reflect how many times the loop was executed.
|
|
|
716 |
|
|
|
717 |
As you would expect, the TICKB and TICKX macros are entry and exit
|
|
|
718 |
macros that otherwise work just like TICK. Count statistics are updated
|
|
|
719 |
for TICKB but not TICKX.
|
|
|
720 |
|
|
|
721 |
|
|
|
722 |
Tracepoints Actions: TRACE, TRACEB, TRACEN and TRACEX
|
|
|
723 |
|
|
|
724 |
The TRACE family of tracing macros create code that lies dormant until the
|
|
|
725 |
appropriate tracepoint is enabled.
|
|
|
726 |
|
|
|
727 |
The members of the TRACE family take exactly two arguments. As usual,
|
|
|
728 |
the first is a tracepoint name. The second is a list of tracepoint actions,
|
|
|
729 |
consisting of one or more C language statements or blocks. Statements in
|
|
|
730 |
the list of tracepoint actions are separated by semicolons as usual. The list
|
|
|
731 |
may be terminated by a semicolon, but it doesn't have to be. For example:
|
|
|
732 |
|
|
|
733 |
TRACE("violet", printf("variable v = %d at xyz\n", v));
|
|
|
734 |
|
|
|
735 |
The tracepoint actions consist of a single print statement, namely:
|
|
|
736 |
|
|
|
737 |
printf("variable v = %d at xyz\n", v);
|
|
|
738 |
|
|
|
739 |
The print statement will be executed only if the tracepoint named "violet"
|
|
|
740 |
has been enabled.
|
|
|
741 |
|
|
|
742 |
Any number of C statements may appear in the list of tracepoint actions.
|
|
|
743 |
For example:
|
|
|
744 |
|
|
|
745 |
TRACE("peach",
|
|
|
746 |
arg = xyz;
|
|
|
747 |
p=f(arg);
|
|
|
748 |
printf("f(xyz) is %lx at xyz\n", p));
|
|
|
749 |
|
|
|
750 |
The tracepoint actions consist of the three C statements:
|
|
|
751 |
|
|
|
752 |
arg = xyz;
|
|
|
753 |
p=f(arg);
|
|
|
754 |
printf("f(xyz) is %lx at xyz\n", p);
|
|
|
755 |
|
|
|
756 |
Note that commas within an instruction in the list of tracepoint actions do
|
|
|
757 |
not change the number of arguments to TRACE. You can write any C
|
|
|
758 |
statements in the list of tracepoint actions. Make sure, though, that you get
|
|
|
759 |
enough parentheses at the end of the macro. Without a trailing parenthesis,
|
|
|
760 |
the C preprocessor will complain about the actual parameters to the macro
|
|
|
761 |
being too long.
|
|
|
762 |
|
|
|
763 |
Statements in the list of tracepoint actions may even contain other macros.
|
|
|
764 |
For example:
|
|
|
765 |
|
|
|
766 |
TRACE("abc",TRACE("xyz",
|
|
|
767 |
printf("abc and xyz both enabled\n")));
|
|
|
768 |
|
|
|
769 |
The TRACEB, TRACEN and TRACEX macros function similarly to the
|
|
|
770 |
TRACE macroDthe TRACEN macro does not update count statistics,
|
|
|
771 |
while the TRACEB macro is an entry macro and the TRACEX macro is an
|
|
|
772 |
exit macro.
|
|
|
773 |
|
|
|
774 |
|
|
|
775 |
TRACEP, TRACEPB, TRACEPN and TRACEPX
|
|
|
776 |
|
|
|
777 |
The four members of the TRACEP family function just like the
|
|
|
778 |
corresponding four members of the TRACE family except that the
|
|
|
779 |
members of the TRACEP family print the name of the tracepoint, a colon
|
|
|
780 |
and a space before executing the tracepoint actions. This is often just what
|
|
|
781 |
you want and it saves a little space in your program. For example, the
|
|
|
782 |
following two macros are exactly equivalent, except that the TRACEP
|
|
|
783 |
macro takes less space:
|
|
|
784 |
|
|
|
785 |
TRACE("daisy", printf("daisy: (arg: %d)\n", n));
|
|
|
786 |
TRACEP("daisy", printf("(arg: %d\n", n));
|
|
|
787 |
|
|
|
788 |
In order to keep the names of the macros straight, it is useful to think of
|
|
|
789 |
TRACE and TRACEP as separate families of macros. In other words, the
|
|
|
790 |
letter 'P' is not a suffix. For example, there is a macro named TRACEPB
|
|
|
791 |
but no macro named TRACEBP.
|
|
|
792 |
|
|
|
793 |
The SPP program uses TRACEPB macros to trace the arguments on entry
|
|
|
794 |
to a function. For example, SPP will insert a TRACEPB as shown:
|
|
|
795 |
|
|
|
796 |
int example (char *s, int i, float f)
|
|
|
797 |
{
|
|
|
798 |
TRACEPB("example",
|
|
|
799 |
printf("(%s, %d, %f)\n", s, i, f));
|
|
|
800 |
...
|
|
|
801 |
}
|
|
|
802 |
|
|
|
803 |
|
|
|
804 |
Other Tracepoint Actions
|
|
|
805 |
|
|
|
806 |
All the tracepoint actions shown so far have consisted of printf statements.
|
|
|
807 |
While that is common, it is often useful to use other statements. Sherlock
|
|
|
808 |
is an open ended tool; the following paragraphs discuss various kinds of
|
|
|
809 |
statements that may be used inside macros.
|
|
|
810 |
|
|
|
811 |
fprintf statements: Useful for sending tracing output to someplace other
|
|
|
812 |
than the console. Note that output generated from macros is sent to the
|
|
|
813 |
standard output stream so that if you redirect output using fprintf be sure to
|
|
|
814 |
redirect the standard output stream as well. For example:
|
|
|
815 |
|
|
|
816 |
TRACE("mum", fprintf(out_file, "mum: (%s)\n", flower_name));
|
|
|
817 |
|
|
|
818 |
Function calls: Useful for printing the contents of complicated data
|
|
|
819 |
structures. This is an important benefitDyou can afford to create tracing
|
|
|
820 |
tools that produce a lot of output, because they will be called only when
|
|
|
821 |
needed. You won't get swamped with unwanted output.
|
|
|
822 |
|
|
|
823 |
For example, suppose you have written a routine called print_vcs() which
|
|
|
824 |
prints the contents of a complicated data structure. You would want to
|
|
|
825 |
control that routine by putting it in a Sherlock macro as follows:
|
|
|
826 |
|
|
|
827 |
struct very_complicated_struct *vcsp;
|
|
|
828 |
...
|
|
|
829 |
TRACE("vcs2", print_vcs(vcsp));
|
|
|
830 |
|
|
|
831 |
Assignment statements: Useful for controlling debugging switches using
|
|
|
832 |
command line arguments. Use assignment statements with caution: they
|
|
|
833 |
may produce unexpected results if you enable all tracepoints with a
|
|
|
834 |
wildcard. For example, suppose you have a variable called enable_pass2
|
|
|
835 |
which controls whether your program will call a routine called pass2().
|
|
|
836 |
You can disable that routine from the command line if you insert the
|
|
|
837 |
following into your program:
|
|
|
838 |
|
|
|
839 |
TRACE("no_pass2", enable_pass2 = FALSE);
|
|
|
840 |
|
|
|
841 |
Flow of control statements: These may sometimes be useful for altering the
|
|
|
842 |
operation of your program while debugging. Just as with assignment
|
|
|
843 |
statements, use these kinds of statements with caution. For example, you
|
|
|
844 |
might want to set up a header for some kind of report as follows:
|
|
|
845 |
|
|
|
846 |
TRACE("hdr", if(hdr= =NULL){hdr="Pre-Release Version";});
|
|
|
847 |
|
|
|
848 |
Other Sherlock macros: Sherlock macros may be nested. This can be used
|
|
|
849 |
to create levels of debugging. Indeed, it is often helpful to have several
|
|
|
850 |
tracepoints with the same name, e.g., v for verbose. In the following
|
|
|
851 |
example, the function named dump() is called only if both the verbose
|
|
|
852 |
option and the dump_x option have been enabled.
|
|
|
853 |
|
|
|
854 |
TRACEN("v", TRACE("dump_x", dump(x)));
|
|
|
855 |
|
|
|
856 |
|
|
|
857 |
The RETURN_xxx Family of Macros
|
|
|
858 |
|
|
|
859 |
There are eleven members of the RETURN_xxx family. All are exit
|
|
|
860 |
macros. In addition to signaling the end of timing code, these macros take
|
|
|
861 |
the place of return instructions. There is one RETURN_xxx macro for
|
|
|
862 |
each type that a function can return: char, double, float, int, long, unsigned
|
|
|
863 |
int, unsigned long and void, and several additional macros for types that
|
|
|
864 |
benefit from special formatting: bool, pointer and string.
|
|
|
865 |
|
|
|
866 |
The RETURN family consists of the following members:
|
|
|
867 |
RETURN_BOOL, RETURN_CHAR, RETURN_DOUBLE,
|
|
|
868 |
RETURN_FLOAT, RETURN_INT, RETURN_LONG,
|
|
|
869 |
RETURN_UINT, RETURN_ULONG, RETURN_PTR,
|
|
|
870 |
RETURN_STRING and RETURN_VOID.
|
|
|
871 |
|
|
|
872 |
All RETURN_xxx macros except RETURN_VOID take two arguments,
|
|
|
873 |
the second of which is an expression of the type indicated by the macro.
|
|
|
874 |
The expression is evaluated exactly once, regardless of whether the
|
|
|
875 |
tracepoint is enabled. If so, the macro prints out a message telling the
|
|
|
876 |
value of the expression. For example:
|
|
|
877 |
|
|
|
878 |
RETURN_BOOL("begonia", 0);
|
|
|
879 |
|
|
|
880 |
|
|
|
881 |
The last example prints the following message if begonia is enabled:
|
|
|
882 |
|
|
|
883 |
begonia: returns: FALSE
|
|
|
884 |
|
|
|
885 |
Here are some more examples:
|
|
|
886 |
|
|
|
887 |
RETURN_VOID("void_function");
|
|
|
888 |
RETURN_BOOL("boolean", pi = = 3);
|
|
|
889 |
RETURN_CHAR("character", '@');
|
|
|
890 |
RETURN_DOUBLE("double_precision", (double) sin(x));
|
|
|
891 |
RETURN_FLOAT("floating_point", sin(pi/2.0));
|
|
|
892 |
RETURN_INT("integer", floor(i));
|
|
|
893 |
RETURN_UINT("unsigned_int", 0xffff);
|
|
|
894 |
RETURN_ULONG("unsigned_long", 0xffff);
|
|
|
895 |
RETURN_LONG("long", 0L);
|
|
|
896 |
RETURN_PTR("pointer", malloc(255));
|
|
|
897 |
RETURN_STRING("string", p -> name);
|
|
|
898 |
|
|
|
899 |
SPP will replace all return instructions by RETURN_xxx macros. For
|
|
|
900 |
example, the following instruction:
|
|
|
901 |
|
|
|
902 |
return &array[25];
|
|
|
903 |
|
|
|
904 |
will be replaced by:
|
|
|
905 |
|
|
|
906 |
RETURN_PTR(&array[25]);
|
|
|
907 |
|
|
|
908 |
SPP will generate RETURN_BOOL macros for all functions declared bool
|
|
|
909 |
as long as the following typedef appears before the function:
|
|
|
910 |
|
|
|
911 |
typedef int bool;
|
|
|
912 |
|
|
|
913 |
Be aware that SPP treats all pointers to char as being pointers to a valid
|
|
|
914 |
string. This will cause problems in functions such as malloc() which return
|
|
|
915 |
a pointer to char which may not be used as a string. Change
|
|
|
916 |
RETURN_STRING to RETURN_PTR in such cases.
|
|
|
917 |
|
|
|
918 |
|
|
|
919 |
Printing Statistics: SL_DUMP and SL_CLEAR
|
|
|
920 |
|
|
|
921 |
The SL_DUMP macro prints out a report of all statistics gathered so far.
|
|
|
922 |
It takes no arguments and can be called at any time. For example:
|
|
|
923 |
|
|
|
924 |
SL_DUMP();
|
|
|
925 |
|
|
|
926 |
The report contains several columns. The tracepoints column is an
|
|
|
927 |
alphabetized list of tracepoint names, the ticks column gives count statistics
|
|
|
928 |
for each tracepoint name, the times1 column gives non-cumulative timing
|
|
|
929 |
statistics, the times2 column gives cumulative timing statistics and the
|
|
|
930 |
tracing column indicates whether the tracepoint was enabled at the time
|
|
|
931 |
SL_DUMP was called.
|
|
|
932 |
|
|
|
933 |
The SL_CLEAR macro zeros all statistics. Statistics are zeroed by
|
|
|
934 |
SL_INIT so you normally don't need to use SL_CLEAR. It might be
|
|
|
935 |
useful, though, if your program were divided into phases and you wanted
|
|
|
936 |
to keep separate statistics for each phase.
|
|
|
937 |
|
|
|
938 |
|
|
|
939 |
Command Line Arguments
|
|
|
940 |
|
|
|
941 |
Any command line argument which starts either with the on_prefix or the
|
|
|
942 |
off_prefix is interpreted as a command to enable or disable a tracepoint or
|
|
|
943 |
group of tracepoints. For example, suppose the program you are testing,
|
|
|
944 |
called z, is usually invoked with two arguments as follows:
|
|
|
945 |
|
|
|
946 |
z in out
|
|
|
947 |
|
|
|
948 |
To enable the tracepoint called abc, precede its name with the on_prefix,
|
|
|
949 |
i.e., ++. Like this:
|
|
|
950 |
|
|
|
951 |
z ++abc in out
|
|
|
952 |
|
|
|
953 |
A Sherlock argument may appear anywhere on the command lineDits
|
|
|
954 |
position relative to non-Sherlock arguments does not matter because
|
|
|
955 |
SL_PARSE eliminates all Sherlock arguments from the argv vector. As far
|
|
|
956 |
as the rest of your program is concerned, the command line is:
|
|
|
957 |
|
|
|
958 |
z in out
|
|
|
959 |
|
|
|
960 |
Use the asterisk wildcard and question mark wildcard to select groups of
|
|
|
961 |
tracepoints. The asterisk (*) matches zero or more characters and the
|
|
|
962 |
question mark (?) matches exactly one character. For example, the
|
|
|
963 |
following enables all tracepoint names that start with "abc" :
|
|
|
964 |
|
|
|
965 |
z ++abc* in out
|
|
|
966 |
|
|
|
967 |
The following enables all tracepoint names that start with abc and contain
|
|
|
968 |
exactly five letters:
|
|
|
969 |
|
|
|
970 |
z ++abc?? in out
|
|
|
971 |
|
|
|
972 |
Any argument which starts with the off_prefix, i.e., '- -', disables one or
|
|
|
973 |
more tracepoints. Sherlock evaluates arguments from left to right, so that
|
|
|
974 |
their order is significant. The following enables all tracepoint names
|
|
|
975 |
starting with abc except abc1:
|
|
|
976 |
|
|
|
977 |
z ++abc* - -abc1 in out
|
|
|
978 |
|
|
|
979 |
The following enables all tracepoint names starting with abc except those
|
|
|
980 |
containing exactly five characters, and in addition the tracepoint named
|
|
|
981 |
abc12 is also enabled:
|
|
|
982 |
|
|
|
983 |
z ++abc* - -abc?? ++abc12 in out
|
|
|
984 |
|
|
|
985 |
It is easy to use wildcards to enable or disable groups of tracepoints if you
|
|
|
986 |
name your breakpoints in a systematic manner. A good scheme is to prefix
|
|
|
987 |
all tracepoint names in a function with the name of that function.
|
|
|
988 |
|
|
|
989 |
The tracepoint name called "trace" is treated as a special case. Disabling
|
|
|
990 |
that tracepoint name disables all tracepoints. For example, the following
|
|
|
991 |
two command lines will produce identical results, but the first will execute
|
|
|
992 |
more quickly than the second:
|
|
|
993 |
|
|
|
994 |
z - -trace in out
|
|
|
995 |
z in out
|
|
|
996 |
|
|
|
997 |
Tracepoints can be re-enabled using the SL_PARSE or SL_ON macros,
|
|
|
998 |
but beware of putting those macros inside some other macro, such as
|
|
|
999 |
TRACE. In other words, the following will not work if all tracing has
|
|
|
1000 |
been disabled:
|
|
|
1001 |
|
|
|
1002 |
TRACE("any", SL_ON("*"));
|
|
|
1003 |
|
|
|
1004 |
You can temporarily disable a tracepoint by preceding its name with a
|
|
|
1005 |
disable count. For example, the following will suppress the execution of
|
|
|
1006 |
the first 100 calls to the tracepoint called loop_trace, after which it will be
|
|
|
1007 |
enabled.
|
|
|
1008 |
|
|
|
1009 |
z in out ++100loop_trace
|
|
|
1010 |
|
|
|
1011 |
You can temporarily disable all tracepoints (except STAT macros) by giving
|
|
|
1012 |
a global disable count, which is simply the on_prefix followed by a count.
|
|
|
1013 |
For example, the following will suppress all tracepoints until 1000 macros
|
|
|
1014 |
have been encountered, after which only abc will be enabled:
|
|
|
1015 |
|
|
|
1016 |
z ++1000 ++abc in out
|
|
|
1017 |
|
|
|
1018 |
Beware of extra spaces in command line arguments. Compare the
|
|
|
1019 |
following lines:
|
|
|
1020 |
|
|
|
1021 |
++99abc
|
|
|
1022 |
++99 abc
|
|
|
1023 |
|
|
|
1024 |
The first command line has an argument containing a disable count for abc.
|
|
|
1025 |
The second command line contains two arguments: a global disable count
|
|
|
1026 |
and a second argument which is not a Sherlock argument at all.
|
|
|
1027 |
|
|
|
1028 |
|
|
|
1029 |
Macro Definitions: Header Files and the SHERLOCK Constant
|
|
|
1030 |
|
|
|
1031 |
Sherlock's macros are defined in a header file called sl.h. This header file
|
|
|
1032 |
must be included in each source file that contains a macro. A good way to
|
|
|
1033 |
do this is to put the following line in a "master header file" which is
|
|
|
1034 |
included in all source files of your program:
|
|
|
1035 |
|
|
|
1036 |
#include "sl.h"
|
|
|
1037 |
|
|
|
1038 |
The expansion of macros is controlled by a compile time constant called
|
|
|
1039 |
SHERLOCK. Macros expand to code only if this variable is defined. The
|
|
|
1040 |
value of SHERLOCK is not important, only whether it has been defined or
|
|
|
1041 |
not. The constant SHERLOCK must be defined before the file sl.h is
|
|
|
1042 |
included. Thus, the following lines must appear in the order shown:
|
|
|
1043 |
|
|
|
1044 |
#define SHERLOCK 1
|
|
|
1045 |
#include "sl.h"
|
|
|
1046 |
|
|
|
1047 |
To completely remove the effects of all Sherlock macros from a file,
|
|
|
1048 |
without removing the macros themselves, you need only undefine the
|
|
|
1049 |
constant SHERLOCK as follows:
|
|
|
1050 |
|
|
|
1051 |
#undef SHERLOCK
|
|
|
1052 |
#include "sl.h"
|
|
|
1053 |
|
|
|
1054 |
If you want to disable a single Sherlock macro, just bracket it with #undef
|
|
|
1055 |
SHERLOCK and #define SHERLOCK statements as follows:
|
|
|
1056 |
|
|
|
1057 |
#undef SHERLOCK
|
|
|
1058 |
sherlock macro
|
|
|
1059 |
#define SHERLOCK 1
|
|
|
1060 |
|
|
|
1061 |
There may be times when you may want to bracket code with #ifdef
|
|
|
1062 |
SHERLOCK and #endif. For example, you might define two different
|
|
|
1063 |
signon messages, depending on whether Sherlock macros are in effect:
|
|
|
1064 |
|
|
|
1065 |
#ifdef SHERLOCK
|
|
|
1066 |
#define USAGE "usage: cb [++- -tracing routine] in [out]"
|
|
|
1067 |
#else
|
|
|
1068 |
#define USAGE "usage: cb in [out]"
|
|
|
1069 |
#endif
|
|
|
1070 |
|
|
|
1071 |
The file s11.h contains a set of alternate macro definitions. Most compilers
|
|
|
1072 |
will have no problems with the macros defined in sl.h. However, some
|
|
|
1073 |
compilers complain about duplicate definitions of a variable called h when
|
|
|
1074 |
compiling the macros defined in sl.h. If that happens, use the file sl1.h
|
|
|
1075 |
instead of sl.hDthat will fix the problem. Make sure, though, that you use
|
|
|
1076 |
sl1.h only as a last resort. The macros defined in sl1.h work much more
|
|
|
1077 |
slowly than the preferred macro definitions in sl.h.
|
|
|
1078 |
|
|
|
1079 |
|
|
|
1080 |
|
|
|
1081 |
CHAPTER 4 DEBUGGING WITH SHERLOCK
|
|
|
1082 |
|
|
|
1083 |
|
|
|
1084 |
This chapter offers tips on how to find and correct bugs more effectively.
|
|
|
1085 |
Whether you are a student, a hobbyist or a professional programmer, you
|
|
|
1086 |
would probably tackle any kind of programming task with confidence and
|
|
|
1087 |
enthusiasm if you could be assured of finding all the bugs that might be
|
|
|
1088 |
lurking in your code. Debugging is a crucial step in the programming
|
|
|
1089 |
processDit separates working, successful programs from non-working
|
|
|
1090 |
failures. C programs are particularly challenging to debug because the C
|
|
|
1091 |
language does not limit what you can do. C does not attempt protect you
|
|
|
1092 |
from your own mistakes. The challenge of debugging C stems directly
|
|
|
1093 |
from the flexibility and power which C provides.
|
|
|
1094 |
|
|
|
1095 |
|
|
|
1096 |
Pointer Bugs
|
|
|
1097 |
|
|
|
1098 |
The key to learning how to debug C programs is recognizing,
|
|
|
1099 |
understanding and correcting pointer bugs. Pointers pervade all of C and
|
|
|
1100 |
they give the C language much of its power and flexibility. However,
|
|
|
1101 |
pointers are dangerous, as well as useful.
|
|
|
1102 |
|
|
|
1103 |
This section addresses the most common situations involving pointer bugs:
|
|
|
1104 |
|
|
|
1105 |
o Pointer bugs arise from uninitialized pointers, dangling pointers and
|
|
|
1106 |
incorrect use of arguments to function.
|
|
|
1107 |
|
|
|
1108 |
o Pointer bugs often destroy the computer code. The code destroyed by
|
|
|
1109 |
pointer bugs may have been the code you wrote, code comprising run-time
|
|
|
1110 |
functions such as printf(), or operating system code.
|
|
|
1111 |
|
|
|
1112 |
o To the new C programmer, pointer bugs produce symptoms that look like
|
|
|
1113 |
hardware malfunctions or compiler bugs. The experienced C programmer
|
|
|
1114 |
recognizes these same symptoms as clear indications of the existence of
|
|
|
1115 |
pointer bugs.
|
|
|
1116 |
|
|
|
1117 |
|
|
|
1118 |
Types of Pointer Bugs
|
|
|
1119 |
|
|
|
1120 |
Pointer bugs arise from uninitialized pointers, dangling pointers and
|
|
|
1121 |
incorrect use of arguments to functions. An uninitialized pointer is simply
|
|
|
1122 |
a pointer variable which is used before it has been given a value.
|
|
|
1123 |
|
|
|
1124 |
For example,
|
|
|
1125 |
|
|
|
1126 |
error1()
|
|
|
1127 |
{
|
|
|
1128 |
char *p;
|
|
|
1129 |
*p = 'a';
|
|
|
1130 |
}
|
|
|
1131 |
|
|
|
1132 |
In this example, p does not point to any specified location at the time that it
|
|
|
1133 |
used to store the character 'a'. The location in memory is not specified by
|
|
|
1134 |
the code, and the results are unpredictable. Possible symptoms will be
|
|
|
1135 |
discussed later.
|
|
|
1136 |
|
|
|
1137 |
The second type of pointer bug is the dangling pointer. A dangling pointer
|
|
|
1138 |
refers to an area of memory which is no longer being used for its original
|
|
|
1139 |
purpose. For example,
|
|
|
1140 |
|
|
|
1141 |
error2()
|
|
|
1142 |
{
|
|
|
1143 |
char *p, *malloc();
|
|
|
1144 |
p = malloc(25);
|
|
|
1145 |
free(p);
|
|
|
1146 |
}
|
|
|
1147 |
|
|
|
1148 |
The call to malloc() makes p point to an area of memory containing room
|
|
|
1149 |
for 25 characters. The call to free() deallocates the space and causes p to
|
|
|
1150 |
become a dangling pointer. However, there is no bug in this code. Any
|
|
|
1151 |
time you deallocate memory you create a dangling pointerDbugs arise from
|
|
|
1152 |
using dangling pointers rather than just creating them.
|
|
|
1153 |
|
|
|
1154 |
Again, the results of using a dangling pointer are unpredictable. They are
|
|
|
1155 |
not specified by the C program. In this example, if the memory released by
|
|
|
1156 |
the call to free() is later reallocated, using p will probably corrupt the newly
|
|
|
1157 |
allocated memory.
|
|
|
1158 |
|
|
|
1159 |
A third kind of pointer bug is the mistaken parameter bug. A good example
|
|
|
1160 |
is the following:
|
|
|
1161 |
|
|
|
1162 |
error3()
|
|
|
1163 |
{
|
|
|
1164 |
int i;
|
|
|
1165 |
scanf("%d", i);
|
|
|
1166 |
}
|
|
|
1167 |
|
|
|
1168 |
This will not work as expected. The second argument to scanf() should
|
|
|
1169 |
have been &i, not i. The scanf() function expects a pointer to i and gets the
|
|
|
1170 |
value of i instead. Thus, the pointer that scanf() expects is incorrect. Once
|
|
|
1171 |
again this creates a hard-to-find bug.
|
|
|
1172 |
|
|
|
1173 |
This kind of error can corrupt the system stack. This happens because the
|
|
|
1174 |
called routines assume the stack has a different structure from the stack that
|
|
|
1175 |
was actually created by the caller. If the called program alters any stack
|
|
|
1176 |
variable, it will be altering a part of the stack that may not actually
|
|
|
1177 |
correspond to the location of the stack variable.
|
|
|
1178 |
|
|
|
1179 |
Note: this kind of bug may largely be eliminated by using function
|
|
|
1180 |
prototyping which will be part of the new ANSI C standard.
|
|
|
1181 |
|
|
|
1182 |
|
|
|
1183 |
Effects of Pointer Bugs
|
|
|
1184 |
|
|
|
1185 |
Having looked at three kinds of pointer bugs, we see that their effects can
|
|
|
1186 |
be devastating. Any pointer bug has the potential for destroying any part of
|
|
|
1187 |
memoryDexecutable code, library functions such as printf(), the system
|
|
|
1188 |
stack used to keep track of procedure calls and returns or even the operating
|
|
|
1189 |
system itself. Exactly which part of memory depends on the value the
|
|
|
1190 |
pointer had at the time your program was loaded.
|
|
|
1191 |
|
|
|
1192 |
|
|
|
1193 |
Symptoms of Pointer Bugs
|
|
|
1194 |
|
|
|
1195 |
The symptoms of pointer bugs vary depending on just what kind of code or
|
|
|
1196 |
data area are destroyed by the bug. Such symptoms can not be taken at
|
|
|
1197 |
face value. When confronted with behavior such as described below,
|
|
|
1198 |
always think first of pointer bugs.
|
|
|
1199 |
|
|
|
1200 |
|
|
|
1201 |
Symptom 1:
|
|
|
1202 |
Your program crashes inside a function which you have
|
|
|
1203 |
written and which you know to be debugged.
|
|
|
1204 |
|
|
|
1205 |
Cause:
|
|
|
1206 |
A pointer bug has destroyed your carefully debugged function.
|
|
|
1207 |
|
|
|
1208 |
Symptom 2:
|
|
|
1209 |
A library function suddenly ceases to work correctly.
|
|
|
1210 |
|
|
|
1211 |
Cause:
|
|
|
1212 |
A pointer bug has destroyed the library function instead of your own code.
|
|
|
1213 |
|
|
|
1214 |
Symptom 3:
|
|
|
1215 |
A bug is solid, i.e., it manifests itself in the same way when you run
|
|
|
1216 |
the program several times. However, the bug goes away when you insert print
|
|
|
1217 |
statements into the code to get more information about it.
|
|
|
1218 |
|
|
|
1219 |
Cause:
|
|
|
1220 |
Inserting the print statements changed the location of various parts
|
|
|
1221 |
of your code. Before the print statements were inserted, the pointer bug
|
|
|
1222 |
destroyed code that was still to be executed. After inserting the print
|
|
|
1223 |
statements, the pointer bug destroyed a part of the program which was no
|
|
|
1224 |
longer executed after the pointer bug occurred.
|
|
|
1225 |
|
|
|
1226 |
Symptom 4:
|
|
|
1227 |
The symptoms of a bug change after you insert print statements.
|
|
|
1228 |
|
|
|
1229 |
Cause:
|
|
|
1230 |
Inserting print statements changed the code destroyed by the pointer bug.
|
|
|
1231 |
|
|
|
1232 |
Symptom 5:
|
|
|
1233 |
By inserting print statements you can determine that control reaches a
|
|
|
1234 |
particular statement but not the statement immediately following.
|
|
|
1235 |
|
|
|
1236 |
Cause:
|
|
|
1237 |
A pointer bug has destroyed one or both of the statements.
|
|
|
1238 |
|
|
|
1239 |
Symptom 6:
|
|
|
1240 |
Your program calls a function, but control never reaches the function.
|
|
|
1241 |
|
|
|
1242 |
Cause:
|
|
|
1243 |
A pointer bug has destroyed either the system stack or the function itself.
|
|
|
1244 |
|
|
|
1245 |
Symptom 7:
|
|
|
1246 |
Control never returns to the caller of a function after the called function
|
|
|
1247 |
returns.
|
|
|
1248 |
|
|
|
1249 |
Cause:
|
|
|
1250 |
A pointer bug has destroyed either the run-time stack or the function itself.
|
|
|
1251 |
|
|
|
1252 |
Symptom 8:
|
|
|
1253 |
Your program sometimes works and sometimes crashes.
|
|
|
1254 |
|
|
|
1255 |
Cause:
|
|
|
1256 |
An uninitialized variable is destroying random parts of your program depending
|
|
|
1257 |
on the contents of certain memory locations before your program was invoked.
|
|
|
1258 |
The pointer bug is destroying different memory locations each time your program
|
|
|
1259 |
is being run. Sometimes the destroyed locations do not affect your program and
|
|
|
1260 |
sometimes they do.
|
|
|
1261 |
|
|
|
1262 |
Symptom 9:
|
|
|
1263 |
Your program always works once, but fails the second time it is run.
|
|
|
1264 |
|
|
|
1265 |
Cause:
|
|
|
1266 |
Your program contains an uninitialized variable. The first time your
|
|
|
1267 |
program runs the variable is initialized in a uniform way which does not
|
|
|
1268 |
cause any apparent harm. The second time your program runs, the variable
|
|
|
1269 |
has a new initial value which depends on the program's first run. This
|
|
|
1270 |
second initial value causes the symptoms the second time the program is
|
|
|
1271 |
run.
|
|
|
1272 |
|
|
|
1273 |
|
|
|
1274 |
Using Sherlock to Find Bugs
|
|
|
1275 |
|
|
|
1276 |
Using Sherlock to locate bugs is a two-step process. The process requires
|
|
|
1277 |
that the bug happen consistently and that you make a plausible guess about
|
|
|
1278 |
its cause.
|
|
|
1279 |
|
|
|
1280 |
|
|
|
1281 |
Step 1: Stabilize the Symptoms.
|
|
|
1282 |
|
|
|
1283 |
The first step in finding the cause of any bug is to make the bug "stand
|
|
|
1284 |
still" so that you can study it. You can do this in the following ways:
|
|
|
1285 |
|
|
|
1286 |
1. Fill memory with a constant value before you run your program. This
|
|
|
1287 |
will insure that uninitialized pointers get the same (though probably still
|
|
|
1288 |
incorrect) value from run to run. If filling memory with a constant value
|
|
|
1289 |
makes the symptoms of your bug go away, you can be reasonably sure that
|
|
|
1290 |
some kind of initialization problem is causing the bug.
|
|
|
1291 |
|
|
|
1292 |
2. Eliminate the effects (including symptoms) of most dangling pointers by
|
|
|
1293 |
disabling any routine which frees a dynamically allocated data structure.
|
|
|
1294 |
You can do that by providing an alternative deallocation routine which is a
|
|
|
1295 |
dummy routine. When you do that, dangling pointers no longer dangle,
|
|
|
1296 |
i.e., they no longer point to deallocated memory. If disabling a routine
|
|
|
1297 |
such as free() makes the symptoms of your bug go away, you can be
|
|
|
1298 |
reasonably sure that a dangling pointer is at hand.
|
|
|
1299 |
|
|
|
1300 |
3. Keep precise records about how you invoked your program. An easy
|
|
|
1301 |
way to do this is by invoking the program from a batch file, also known as
|
|
|
1302 |
a submit file or shell file. That way the batch file serves as a record for
|
|
|
1303 |
exactly what you have done. A tip: when you change the arguments to
|
|
|
1304 |
your program, comment out the old line and save it in the batch file as a
|
|
|
1305 |
record of the your previous runs. This is especially handy when using
|
|
|
1306 |
numerous Sherlock tracepoints to change the behavior of your program
|
|
|
1307 |
during testing.
|
|
|
1308 |
|
|
|
1309 |
4. Keep your program unchanged. Since pointer bugs destroy code, even
|
|
|
1310 |
the smallest change in your program, or even a change in the order in
|
|
|
1311 |
which functions are linked together, may cause the symptoms of pointer
|
|
|
1312 |
bugs to change or even go away. Sherlock is a huge help here. Enabling
|
|
|
1313 |
or disabling different tracepoints does not change the location of any code
|
|
|
1314 |
in your program. You can run test after test on your program, getting very
|
|
|
1315 |
different information each time, and the symptoms of pointer bugs will not
|
|
|
1316 |
change.
|
|
|
1317 |
|
|
|
1318 |
|
|
|
1319 |
Step 2: Make a Reasonable Guess about the Cause.
|
|
|
1320 |
|
|
|
1321 |
The next step in finding a bug is to make a guess about what is causing it.
|
|
|
1322 |
If any of the symptoms mentioned above appear, you probably should
|
|
|
1323 |
assume that a pointer bug is causing your problems. Use Sherlock to look
|
|
|
1324 |
for bad pointers by tracing the parameters passed to all your functions.
|
|
|
1325 |
|
|
|
1326 |
If a supposed pointer has a small negative number as its value (.e.g.,
|
|
|
1327 |
FFFFE hex), you can be sure that the pointer has already been corrupted.
|
|
|
1328 |
You may also notice that a pointer does not have a reasonable value in some
|
|
|
1329 |
other way. Now ask yourself, "Which routines could have passed that
|
|
|
1330 |
pointer on to the called routine?" Rerun your program with different
|
|
|
1331 |
tracepoints enabled which will trace the likely culprits. Once you find the
|
|
|
1332 |
source of a bad pointer, ask whether the code which created the bad pointer
|
|
|
1333 |
was ultimately at fault or whether some other error resulted in the bad
|
|
|
1334 |
pointer as a by-product.
|
|
|
1335 |
|
|
|
1336 |
Again, Sherlock stands out in being able to try numerous tracing runs on a
|
|
|
1337 |
program without having to change the program in any way. You will find
|
|
|
1338 |
that patterns jump out at you as you look at traces and dumps produced by
|
|
|
1339 |
Sherlock. When you get a hint of something in a trace being "not quite
|
|
|
1340 |
right," you can immediately start a new trace to zero in on those parts of the
|
|
|
1341 |
program that are related to what caught your attention. By varying your
|
|
|
1342 |
traces to home in on suspects, you are eliminating vast amounts of
|
|
|
1343 |
extraneous information in the debugging output.
|
|
|
1344 |
|
|
|
1345 |
|
|
|
1346 |
|
|
|
1347 |
CHAPTER 5 SHERLOCK REFERENCE
|
|
|
1348 |
|
|
|
1349 |
|
|
|
1350 |
This chapter provides reference information about all aspects of the
|
|
|
1351 |
Sherlock systemDit contains the most detailed and complete information
|
|
|
1352 |
on any particular topic. The first sections discuss the following subjects:
|
|
|
1353 |
Header Files, Command Line Arguments, Entry and Exit Macros and the
|
|
|
1354 |
Timing Stack, The Interrupt Handler, Compiling Support Routines,
|
|
|
1355 |
Tracepoint Names and Tracepoint Actions. The conclusion of this chapter
|
|
|
1356 |
discusses each macro, symbol and support routine in alphabetical order.
|
|
|
1357 |
|
|
|
1358 |
|
|
|
1359 |
Header Files
|
|
|
1360 |
|
|
|
1361 |
There are two sets of definitions of the Sherlock macros, the preferred
|
|
|
1362 |
definitions in sl.h and the alternate definitions in sl1.h.The support routines
|
|
|
1363 |
called by the alternate macros search an internal symbol table for their
|
|
|
1364 |
tracepoint name every time they are called. The preferred macros define a
|
|
|
1365 |
static variable named h which is used to avoid searching the symbol table
|
|
|
1366 |
after an initial search. As a consequence, preferred macros are much faster
|
|
|
1367 |
than the alternate macros.
|
|
|
1368 |
|
|
|
1369 |
Alas, some compilers do not allow multiple static variables with the same
|
|
|
1370 |
name, even if the variables are declared in different blocks. Use the
|
|
|
1371 |
preferred macro definitions unless your compiler objects to constructions
|
|
|
1372 |
such as:
|
|
|
1373 |
|
|
|
1374 |
void test()
|
|
|
1375 |
{
|
|
|
1376 |
{static char *h = 0;}
|
|
|
1377 |
{static char *h = 0;}
|
|
|
1378 |
}
|
|
|
1379 |
|
|
|
1380 |
|
|
|
1381 |
Command Line Arguments
|
|
|
1382 |
|
|
|
1383 |
A Sherlock argument is any command line argument whose prefix is either
|
|
|
1384 |
the on_prefix or the off_prefix. These prefixes are defined by the
|
|
|
1385 |
SL_PARSE macro. For example:
|
|
|
1386 |
|
|
|
1387 |
SL_PARSE(argc, argv, "++", "- -");
|
|
|
1388 |
|
|
|
1389 |
All examples in this manual assume that the on_prefix is "++" and the
|
|
|
1390 |
off_prefix is "- -", but any string of any length may be used for either
|
|
|
1391 |
prefix.
|
|
|
1392 |
|
|
|
1393 |
The SL_PARSE macro processes all Sherlock arguments, deleting them
|
|
|
1394 |
from the argv vector and adjusting the argc count appropriately. Thus, any
|
|
|
1395 |
code following the SL_PARSE macro will be completely unaware of the
|
|
|
1396 |
existence of Sherlock arguments.
|
|
|
1397 |
|
|
|
1398 |
Two wildcard characters allow Sherlock arguments to specify classes of
|
|
|
1399 |
tracepoints. The asterisk (*) character matches zero or more characters.
|
|
|
1400 |
For example, the argument
|
|
|
1401 |
|
|
|
1402 |
++abc*
|
|
|
1403 |
|
|
|
1404 |
enables tracing for any tracepoint whose name begins with abc. The
|
|
|
1405 |
asterisk, if present, should be the last character of a Sherlock argument.
|
|
|
1406 |
|
|
|
1407 |
The question mark (?) character matches exactly one character. For
|
|
|
1408 |
example, the argument
|
|
|
1409 |
|
|
|
1410 |
- -abc??
|
|
|
1411 |
|
|
|
1412 |
disables tracing for abc12 and abc34 but not abc1 or abc123.
|
|
|
1413 |
|
|
|
1414 |
Sherlock arguments are processed left to right. The order is significant.
|
|
|
1415 |
For example, the following (partial) command line turns on tracing for
|
|
|
1416 |
abc1
|
|
|
1417 |
|
|
|
1418 |
- -abc* ++abc1
|
|
|
1419 |
|
|
|
1420 |
As another example, the effect of the first argument in the command line
|
|
|
1421 |
below will always be immediately canceled by the second argument.
|
|
|
1422 |
|
|
|
1423 |
++abc? - -abc*
|
|
|
1424 |
|
|
|
1425 |
If the on_prefix or off_prefix is immediately followed by a number, that
|
|
|
1426 |
number is taken to be a disable count. If a name follows the disable count,
|
|
|
1427 |
tracing for that tracepoint is disabled until that tracepoint has been executed
|
|
|
1428 |
n times, where n is the disable count. For example,
|
|
|
1429 |
|
|
|
1430 |
++100abc
|
|
|
1431 |
|
|
|
1432 |
disables tracing for the tracepoint named abc until abc has been reached 100
|
|
|
1433 |
times.
|
|
|
1434 |
|
|
|
1435 |
If no string appears after the disable count, it is a global disable count
|
|
|
1436 |
which applies to all tracepoints. All tracing is disabled until n tracepoints
|
|
|
1437 |
have been encountered. For example:
|
|
|
1438 |
|
|
|
1439 |
++1000
|
|
|
1440 |
|
|
|
1441 |
disables all tracing until 1000 tracepoints have been executed.
|
|
|
1442 |
|
|
|
1443 |
|
|
|
1444 |
Entry and Exit Macros and the Timing Stack
|
|
|
1445 |
|
|
|
1446 |
Timing statistics measure the time spent in timing code delimited by two
|
|
|
1447 |
special kinds of macros. Entry macros signal the beginning of timing
|
|
|
1448 |
code, while exit macros signal the end of timing code. The support
|
|
|
1449 |
routines use an internal timing stack to gather timing statistics in nested
|
|
|
1450 |
sections of timing code.
|
|
|
1451 |
|
|
|
1452 |
There are two kinds of timing statistics: cumulative and non-cumulative.
|
|
|
1453 |
Cumulative statistics measure the total time spent in timing code, including
|
|
|
1454 |
any time spent in nested timing code. Non-cumulative statistics excludes
|
|
|
1455 |
time spent in nested timing code.
|
|
|
1456 |
|
|
|
1457 |
At run time, each entry macro requires a corresponding exit macro. If an
|
|
|
1458 |
exit macro is omitted, a timing stack overflow will eventually result. If an
|
|
|
1459 |
extra exit macro is encountered, a timing stack underflow may follow. A
|
|
|
1460 |
timing stack overflow or underflow indicates that the timing statistics
|
|
|
1461 |
gathered are not accurate. Sherlock prints a warning message and a stack
|
|
|
1462 |
traceback when either an overflow or an underflow is detected. The global
|
|
|
1463 |
variable, sl_level, indicates the current nesting depth of timing macrosDit
|
|
|
1464 |
is incremented by entry macros and decremented by exit macros. You can
|
|
|
1465 |
use the sl_level variable to track down timing stack overflows or
|
|
|
1466 |
underflows.
|
|
|
1467 |
|
|
|
1468 |
|
|
|
1469 |
The Interrupt Handler
|
|
|
1470 |
|
|
|
1471 |
An interrupt handler is used to gather timing statistics. In concept, the
|
|
|
1472 |
purpose of the handler is simple: to increment the global C variable called
|
|
|
1473 |
sl_count each time a timing interrupt occurs. However, the code for the
|
|
|
1474 |
interrupt handler is tricky.
|
|
|
1475 |
|
|
|
1476 |
Warning: The interrupt handler is inherently machine dependent. It will
|
|
|
1477 |
work only on machines which are 100% compatible with the IBM PC, XT
|
|
|
1478 |
or AT. It will be necessary to rewrite the interrupt handler if you want to
|
|
|
1479 |
gather timing statistics on other machines.
|
|
|
1480 |
|
|
|
1481 |
The interrupt handler consists of three parts: an initializer, a tick handler
|
|
|
1482 |
and an exit handler. The initializer changes the hardware interrupt trap
|
|
|
1483 |
vectors to point to entry points inside the tick handler and the exit handler.
|
|
|
1484 |
The initializer also increases the frequency of the hardware timer interrupt.
|
|
|
1485 |
It does this by directly writing to one of the timer chips. The speed up
|
|
|
1486 |
factor is determined by the value of the global C variable called sl_speed,
|
|
|
1487 |
which is defined in the file sherlock.c. The default speed-up factor is 55,
|
|
|
1488 |
which gives an interrupt rate of about 1 interrupt per millisecond, assuming
|
|
|
1489 |
a basic tick frequency of 18.2 ticks per second.
|
|
|
1490 |
|
|
|
1491 |
|
|
|
1492 |
The tick handler receives control as the result of tick interrupts. It
|
|
|
1493 |
increments the global C variable called SL_COUNT. It also passes on
|
|
|
1494 |
selected ticks on to the default tick handler so that the nominal tick
|
|
|
1495 |
frequency of 18.2 ticks per second is maintained.
|
|
|
1496 |
|
|
|
1497 |
The exit handler gets control from any DOS function call or interrupt that
|
|
|
1498 |
results in an exit from the program. This exit handler restores all the
|
|
|
1499 |
interrupt vectors which were changed by the initializer.
|
|
|
1500 |
|
|
|
1501 |
|
|
|
1502 |
Compiling Support Routines
|
|
|
1503 |
|
|
|
1504 |
The source code for the support routines was developed on the Turbo C
|
|
|
1505 |
compiler version 1.5 and will compile correctly with the Microsoft C
|
|
|
1506 |
compiler version 5.0 or later.
|
|
|
1507 |
|
|
|
1508 |
The source code for the support routines uses function prototypes which
|
|
|
1509 |
are a part of the draft ANSI C standard. Not all current compilers support
|
|
|
1510 |
function prototypes. To compile
|
|
|
1511 |
Sherlock on compilers that do not, comment out the definition of the
|
|
|
1512 |
compile time variable called HAS_PROTOTYPES at the start of the header
|
|
|
1513 |
file sl.h.
|
|
|
1514 |
|
|
|
1515 |
|
|
|
1516 |
Tracepoint Names
|
|
|
1517 |
|
|
|
1518 |
Tracepoint names are strings which must contain only the following
|
|
|
1519 |
characters: the letters a-z and A-Z, the numbers 0-9 and the underscore
|
|
|
1520 |
character. A warning message is printed if a macro is passed a tracepoint
|
|
|
1521 |
name which contains any other character.
|
|
|
1522 |
|
|
|
1523 |
|
|
|
1524 |
Tracepoint Actions
|
|
|
1525 |
|
|
|
1526 |
Tracepoint actions consist of a statement list consisting of zero, one or
|
|
|
1527 |
more C language statements. Statements must be separated by semicolons
|
|
|
1528 |
as usual. The statement list may be terminated by a semicolon, but need
|
|
|
1529 |
not be.
|
|
|
1530 |
|
|
|
1531 |
|
|
|
1532 |
Macros, Global Variables and Support Routines
|
|
|
1533 |
|
|
|
1534 |
The following sections discuss each Sherlock macro and variable and a few
|
|
|
1535 |
globally visible support routines. All entries appear in alphabetical order.
|
|
|
1536 |
|
|
|
1537 |
|
|
|
1538 |
Macros:
|
|
|
1539 |
RETURN_BOOL (tracepoint_name, boolean_expression)
|
|
|
1540 |
RETURN_CHAR (tracepoint_name, char_expression)
|
|
|
1541 |
RETURN_DOUBLE(tracepoint_name, double_expression)
|
|
|
1542 |
RETURN_FLOAT (tracepoint_name, float_expression)
|
|
|
1543 |
RETURN_INT (tracepoint_name, int_expression)
|
|
|
1544 |
RETURN_LONG (tracepoint_name, long_expression)
|
|
|
1545 |
RETURN_PTR (tracepoint_name, pointer_expression)
|
|
|
1546 |
RETURN_STRING(tracepoint_name, string_expression)
|
|
|
1547 |
RETURN_UINT (tracepoint_name, unsigned_int_expression)
|
|
|
1548 |
RETURN_ULONG (tracepoint_name, unsigned_long_expression)
|
|
|
1549 |
RETURN_VOID (tracepoint_name)
|
|
|
1550 |
|
|
|
1551 |
Synopsis: Print tracepoint name. Print and return the value of the
|
|
|
1552 |
expression.
|
|
|
1553 |
|
|
|
1554 |
Examples:
|
|
|
1555 |
RETURN_BOOL ("abc", a ? 0 : 1);
|
|
|
1556 |
RETURN_CHAR ("abc", "\n");
|
|
|
1557 |
RETURN_DOUBLE("abc", 0.6666666666666666);
|
|
|
1558 |
RETURN_FLOAT ("abc", 3.14159);
|
|
|
1559 |
RETURN_INT ("abc", a - 15);
|
|
|
1560 |
RETURN_LONG ("abc", 1L);
|
|
|
1561 |
RETURN_PTR ("abc", &abc);
|
|
|
1562 |
RETURN_STRING("abc", "this is a test");
|
|
|
1563 |
RETURN_UINT ("abc", (unsigned) 0xffff);
|
|
|
1564 |
RETURN_ULONG ("abc", (unsigned) 0xffff0000);
|
|
|
1565 |
RETURN_VOID ("abc");
|
|
|
1566 |
|
|
|
1567 |
These macros are all exit macros. Each macro prints the tracepoint name, a
|
|
|
1568 |
colon, a space, "returns", a colon, a space, followed by the value of the
|
|
|
1569 |
expression. The RETURN_VOID macro prints "void" in place of the
|
|
|
1570 |
value of the expression. Each macro completes and records the timing
|
|
|
1571 |
statistics associated with the timing section begun by the corresponding
|
|
|
1572 |
entry macro. Each macro then returns from a function of the indicated
|
|
|
1573 |
type.
|
|
|
1574 |
|
|
|
1575 |
At run time, each of these macros must be matched with an entry macro. If
|
|
|
1576 |
an exit macro is encountered without a corresponding entry macro, a timing
|
|
|
1577 |
stack underflow will eventually occur.
|
|
|
1578 |
|
|
|
1579 |
The SPP utility program will generate RETURN_BOOL macros for all
|
|
|
1580 |
functions declared bool as long as the following typedef appears before the
|
|
|
1581 |
function:
|
|
|
1582 |
|
|
|
1583 |
typedef int bool;
|
|
|
1584 |
|
|
|
1585 |
Be aware that SPP treats all pointers to char as being pointers to a valid
|
|
|
1586 |
string. This will cause problems in functions such as malloc() which return
|
|
|
1587 |
a pointer to char which may not be used as a string. Change
|
|
|
1588 |
RETURN_STRING to RETURN_PTR in such cases.
|
|
|
1589 |
|
|
|
1590 |
|
|
|
1591 |
Compile time symbol: SHERLOCK
|
|
|
1592 |
|
|
|
1593 |
Synopsis: Enable or disable expansion of all Sherlock macros.
|
|
|
1594 |
|
|
|
1595 |
Example: #define SHERLOCK 1
|
|
|
1596 |
#include "sl.h"
|
|
|
1597 |
|
|
|
1598 |
Sherlock's macros expand into actual code only if this symbol is defined.
|
|
|
1599 |
The value assigned to the variable SHERLOCK does not matter, only
|
|
|
1600 |
whether it is defined or not. If SHERLOCK is not defined, then all
|
|
|
1601 |
Sherlock's macros expand to no code, or a return statement in the case of
|
|
|
1602 |
RETURN_xxx macros.
|
|
|
1603 |
|
|
|
1604 |
Notice that the definition of SHERLOCK must precede the definitions of
|
|
|
1605 |
the macros in sl.h. The following will not work as expected:
|
|
|
1606 |
|
|
|
1607 |
#include "sl.h"
|
|
|
1608 |
#define SHERLOCK 1
|
|
|
1609 |
|
|
|
1610 |
Do this instead:
|
|
|
1611 |
|
|
|
1612 |
#define SHERLOCK 1
|
|
|
1613 |
#include "sl.h"
|
|
|
1614 |
|
|
|
1615 |
Actually, it is usually a good idea to enable the SHERLOCK constant from
|
|
|
1616 |
the command line. When using the Microsoft C compiler, use the /D
|
|
|
1617 |
option, like this:
|
|
|
1618 |
|
|
|
1619 |
/DSHERLOCK
|
|
|
1620 |
|
|
|
1621 |
When using the Turbo C compiler, use the -D option, as follows:
|
|
|
1622 |
|
|
|
1623 |
-DSHERLOCK
|
|
|
1624 |
|
|
|
1625 |
|
|
|
1626 |
Support Routines:
|
|
|
1627 |
typedef int bool;
|
|
|
1628 |
void sl_bout(bool b);
|
|
|
1629 |
void sl_cout(char c);
|
|
|
1630 |
void sl_dout(double d);
|
|
|
1631 |
void sl_iout(int i);
|
|
|
1632 |
void sl_lout(long l);
|
|
|
1633 |
void sl_pout(void * s);
|
|
|
1634 |
void sl_sout(char * p);
|
|
|
1635 |
void sl_uiout(unsigned int ui);
|
|
|
1636 |
void sl_ulout(unsigned long ul);
|
|
|
1637 |
|
|
|
1638 |
Synopsis:
|
|
|
1639 |
sl_bout: Print a boolean expression using sl_cout().
|
|
|
1640 |
sl_cout: Print a character using putchar().
|
|
|
1641 |
sl_dout: Print a double or float expression using sl_cout().
|
|
|
1642 |
sl_iout: Print an int expression using sl_cout().
|
|
|
1643 |
sl_lout: Print a long expression using sl_cout().
|
|
|
1644 |
sl_pout: Print a pointer expression using sl_cout().
|
|
|
1645 |
sl_sout: Print a string using sl_cout().
|
|
|
1646 |
sl_uiout: Print an unsigned int expression using sl_cout().
|
|
|
1647 |
sl_ulout: Print an unsigned long expression using sl_cout().
|
|
|
1648 |
|
|
|
1649 |
Example:
|
|
|
1650 |
void sample(b, c, d, f, i, l, p, s, u, ul)
|
|
|
1651 |
bool b; char c;
|
|
|
1652 |
double d; float f;
|
|
|
1653 |
int i; long l;
|
|
|
1654 |
struct some_struct *p; char *s;
|
|
|
1655 |
unsigned ui; unsigned long ul;
|
|
|
1656 |
{
|
|
|
1657 |
TICKB("sample",
|
|
|
1658 |
sl_bout(b); sl_sout(", ");
|
|
|
1659 |
sl_cout(c); sl_sout(", ");
|
|
|
1660 |
sl_dout(d); sl_sout(", ");
|
|
|
1661 |
sl_dout(f); sl_sout(", ");
|
|
|
1662 |
sl_iout(i); sl_sout(", ");
|
|
|
1663 |
sl_lout(l); sl_sout(", ");
|
|
|
1664 |
sl_pout(p); sl_sout(", ");
|
|
|
1665 |
sl_sout(s); sl_sout(", ");
|
|
|
1666 |
sl_uiout(u); sl_sout(", ");
|
|
|
1667 |
sl_ulout(ul));
|
|
|
1668 |
...
|
|
|
1669 |
TICKX("sample");
|
|
|
1670 |
}
|
|
|
1671 |
|
|
|
1672 |
These support routines print a single expression of the indicated type. The
|
|
|
1673 |
sprintf() function is used to format the value into a character buffer, which
|
|
|
1674 |
is then printed using sl_sout(). The sl_sout() routine calls sl_cout() so the
|
|
|
1675 |
output of all these routines eventually is funneled through sl_cout().
|
|
|
1676 |
Indeed, all output produced by the macros and the support routines
|
|
|
1677 |
eventually is handled by sl_cout().
|
|
|
1678 |
|
|
|
1679 |
|
|
|
1680 |
Macro: SL_CLEAR()
|
|
|
1681 |
|
|
|
1682 |
Synopsis: Clear all statistics.
|
|
|
1683 |
|
|
|
1684 |
Example: SL_CLEAR();
|
|
|
1685 |
|
|
|
1686 |
See also: SL_DUMP
|
|
|
1687 |
|
|
|
1688 |
This macro clears all the statistics gathered so far. The SL_INIT macro
|
|
|
1689 |
also does this, so normally there is no need to use this macro. You might
|
|
|
1690 |
use this macro to begin gathering statistics about a selected portion of your
|
|
|
1691 |
code. Call SL_CLEAR at the start of the section and SL_DUMP at the end
|
|
|
1692 |
of the section.
|
|
|
1693 |
|
|
|
1694 |
|
|
|
1695 |
Macro: SL_DUMP()
|
|
|
1696 |
|
|
|
1697 |
Synopsis: Write a report of statistics.
|
|
|
1698 |
|
|
|
1699 |
Example: TRACE("dump", SL_DUMP());
|
|
|
1700 |
|
|
|
1701 |
See Also: SL_CLEAR
|
|
|
1702 |
|
|
|
1703 |
This macro writes a report of all the statistics gathered for all tracepoints
|
|
|
1704 |
encountered so far. Output is written using the sl_cout() support routine.
|
|
|
1705 |
|
|
|
1706 |
The report contains five columns. The tracepoints column is an
|
|
|
1707 |
alphabetized list of tracepoint names. The ticks column gives count
|
|
|
1708 |
statistics for each tracepoint name. The times1 column gives non-
|
|
|
1709 |
cumulative timing statistics and the times2 column gives cumulative timing
|
|
|
1710 |
statistics. The tracing column indicates whether the tracepoint was enabled
|
|
|
1711 |
when SL_DUMP was called.
|
|
|
1712 |
|
|
|
1713 |
Reports may be enabled from the command line by inserting the
|
|
|
1714 |
SL_DUMP macro in another macro such as TRACE or TRACEN.
|
|
|
1715 |
|
|
|
1716 |
|
|
|
1717 |
Macro: SL_INIT()
|
|
|
1718 |
|
|
|
1719 |
Synopsis: Initialize Sherlock's support routines.
|
|
|
1720 |
|
|
|
1721 |
Example:
|
|
|
1722 |
main(argc, argv)
|
|
|
1723 |
int argc;
|
|
|
1724 |
char **argv;
|
|
|
1725 |
{
|
|
|
1726 |
/* Local declarations. */
|
|
|
1727 |
SL_INIT();
|
|
|
1728 |
SL_PARSE(argc, arg, "++", "- -");
|
|
|
1729 |
|
|
|
1730 |
/* Sherlock arguments not visible here. */
|
|
|
1731 |
...
|
|
|
1732 |
}
|
|
|
1733 |
|
|
|
1734 |
This macro initializes Sherlock's support routines. It must be called before
|
|
|
1735 |
any other Sherlock macro.
|
|
|
1736 |
|
|
|
1737 |
|
|
|
1738 |
Global Variable:
|
|
|
1739 |
sl_level
|
|
|
1740 |
|
|
|
1741 |
Synopsis:
|
|
|
1742 |
The current nesting level.
|
|
|
1743 |
|
|
|
1744 |
Example:
|
|
|
1745 |
if (sl_level > 0) {
|
|
|
1746 |
printf("unmatched entry macro.\n");
|
|
|
1747 |
}
|
|
|
1748 |
|
|
|
1749 |
This global variable is incremented every time an entry macro is
|
|
|
1750 |
encountered and is decremented every time an exit macro is encountered.
|
|
|
1751 |
This variable can be used to find unpaired entry and exit macros.
|
|
|
1752 |
|
|
|
1753 |
|
|
|
1754 |
Macro: SL_NAME(tracepoint_tag, tracepoint_name)
|
|
|
1755 |
|
|
|
1756 |
Synopsis: Define a static char array which can be used as a tracepoint
|
|
|
1757 |
name.
|
|
|
1758 |
|
|
|
1759 |
Example:
|
|
|
1760 |
|
|
|
1761 |
int
|
|
|
1762 |
long_winded_function_name()
|
|
|
1763 |
{
|
|
|
1764 |
SL_NAME(func2_tag, "long_winded_function_name");
|
|
|
1765 |
TICKB(func2_tag);
|
|
|
1766 |
...
|
|
|
1767 |
RETURN_VOID(func2_tag);
|
|
|
1768 |
}
|
|
|
1769 |
|
|
|
1770 |
Use the SL_NAME macro to reduce the space required to store tracepoint
|
|
|
1771 |
names. In the example above, space for the string "func2" is allocated
|
|
|
1772 |
once, rather than twice.
|
|
|
1773 |
|
|
|
1774 |
Note: The SDEL program will retain all SL_NAME macros if the -r option
|
|
|
1775 |
is given to SDEL. Use the -r option when using SDEL to delete Sherlock
|
|
|
1776 |
macros just prior to reinserting them with SPP.
|
|
|
1777 |
|
|
|
1778 |
|
|
|
1779 |
Macros:
|
|
|
1780 |
SL_OFF(tracepoint_name)
|
|
|
1781 |
SL_ON(tracepoint_name)
|
|
|
1782 |
|
|
|
1783 |
Synopsis:
|
|
|
1784 |
SL_OFF: Disable one or more tracepoints.
|
|
|
1785 |
SL_ON: Enable one or more tracepoints.
|
|
|
1786 |
|
|
|
1787 |
Examples:
|
|
|
1788 |
SL_OFF("abc");
|
|
|
1789 |
SL_ON("200abc");
|
|
|
1790 |
|
|
|
1791 |
Special cases:
|
|
|
1792 |
SL_OFF("trace");
|
|
|
1793 |
SL_ON("trace");
|
|
|
1794 |
|
|
|
1795 |
See Also: SL_PARSE
|
|
|
1796 |
|
|
|
1797 |
These macros enable or disable the tracing for a single tracepoint, just as if
|
|
|
1798 |
the name of the tracepoint were appended to the end of the command line.
|
|
|
1799 |
Neither the on_prefix nor the off_prefix is used. Wildcard characters and
|
|
|
1800 |
disable counts are allowed. The name "trace" is a special case which
|
|
|
1801 |
enables or disables the tracing of all tracepoints.
|
|
|
1802 |
|
|
|
1803 |
|
|
|
1804 |
Macro:
|
|
|
1805 |
SL_PARSE(argc, argv, on_prefix, off_prefix)
|
|
|
1806 |
|
|
|
1807 |
Synopsis:
|
|
|
1808 |
Enable or disable tracepoints indicated by an argument vector.
|
|
|
1809 |
|
|
|
1810 |
Example:
|
|
|
1811 |
SL_INIT();
|
|
|
1812 |
SL_PARSE(argc, argv, "++", "- -");
|
|
|
1813 |
|
|
|
1814 |
See also: SL_ON, SL_OFF
|
|
|
1815 |
|
|
|
1816 |
This macro enables or disables tracepoints indicated by an argument vector
|
|
|
1817 |
and removes all Sherlock arguments from the vector.
|
|
|
1818 |
|
|
|
1819 |
The argc argument gives a count of the number of elements in the argv
|
|
|
1820 |
argument, which is an array of pointers to strings. The on_prefix and
|
|
|
1821 |
off_prefix arguments are strings which denote Sherlock command line
|
|
|
1822 |
arguments. Arguments in argv starting with on_prefix enable tracing,
|
|
|
1823 |
while arguments in argv starting with off_prefix disable tracing.
|
|
|
1824 |
|
|
|
1825 |
The argv vector is scanned for argc - 1 arguments starting with argv[1].
|
|
|
1826 |
Argv[0] is ignored. When arguments starting with either the on_prefix or
|
|
|
1827 |
off_prefix are found, the indicated tracepoint is enabled or disabled, the
|
|
|
1828 |
argument is removed from the argv vector and the argc count is
|
|
|
1829 |
decremented. On entry to SL_PARSE, argv[argc] must be NULL.
|
|
|
1830 |
|
|
|
1831 |
This macro may be called more than once and the argc and argv arguments
|
|
|
1832 |
need not be the same as the argc and argv arguments passed to the main()
|
|
|
1833 |
function by the operating system. In other words, you are free to call this
|
|
|
1834 |
macro with a "simulated command line." For example:
|
|
|
1835 |
|
|
|
1836 |
static int count = 4;
|
|
|
1837 |
static char * vect [] =
|
|
|
1838 |
{NULL, "++*", "- -sys*", "++sys_fopen", NULL};
|
|
|
1839 |
|
|
|
1840 |
...
|
|
|
1841 |
|
|
|
1842 |
SL_PARSE(count, vect, "++", "- -");
|
|
|
1843 |
|
|
|
1844 |
|
|
|
1845 |
Support Routine:
|
|
|
1846 |
sl_regs()
|
|
|
1847 |
|
|
|
1848 |
Synopsis:
|
|
|
1849 |
Put the contents of all machine registers into global variables.
|
|
|
1850 |
|
|
|
1851 |
Example:
|
|
|
1852 |
TRACE("dump_regs", sl_regs());
|
|
|
1853 |
|
|
|
1854 |
This support routine does not have a corresponding macro. It places the
|
|
|
1855 |
contents of the PC's registers into global memory locations. See regs.asm
|
|
|
1856 |
for details.
|
|
|
1857 |
|
|
|
1858 |
|
|
|
1859 |
Macros:
|
|
|
1860 |
STAT(tracepoint_name)
|
|
|
1861 |
STATB(tracepoint_name)
|
|
|
1862 |
STATX(tracepoint_name)
|
|
|
1863 |
|
|
|
1864 |
Synopsis:
|
|
|
1865 |
STAT: Update the count statistics for a tracepoint.
|
|
|
1866 |
STATB: Entry macro. Otherwise same as STAT.
|
|
|
1867 |
STATX: Exit macro. Otherwise same as STAT.
|
|
|
1868 |
|
|
|
1869 |
Example:
|
|
|
1870 |
int f1()
|
|
|
1871 |
{
|
|
|
1872 |
int i, val;
|
|
|
1873 |
STATB("f1");
|
|
|
1874 |
for (i = 0; i < 5; i++) {
|
|
|
1875 |
STAT("f1_loop");
|
|
|
1876 |
val++;
|
|
|
1877 |
}
|
|
|
1878 |
STATX("f1");
|
|
|
1879 |
}
|
|
|
1880 |
|
|
|
1881 |
These STAT family of macros update the count statistics associated with the
|
|
|
1882 |
tracepoint name, regardless of whether the tracepoint name is enabled or
|
|
|
1883 |
not. This family of macros never produces output. The STATB macro
|
|
|
1884 |
begins timing code and the STATX macro ends timing code.
|
|
|
1885 |
|
|
|
1886 |
|
|
|
1887 |
Macros:
|
|
|
1888 |
TICK(tracepoint_name)
|
|
|
1889 |
TICKB(tracepoint_name)
|
|
|
1890 |
TICKN(tracepoint_name)
|
|
|
1891 |
TICKX(tracepoint_name)
|
|
|
1892 |
|
|
|
1893 |
Synopsis:
|
|
|
1894 |
TICK: Print the tracepoint name, a colon and a newline and update
|
|
|
1895 |
count statistic.
|
|
|
1896 |
TICKB: Entry macro. Otherwise same as TICK.
|
|
|
1897 |
TICKN: Do not update count statistic. Otherwise same as TICK.
|
|
|
1898 |
TICKX: Exit macro. Otherwise same as TICK.
|
|
|
1899 |
|
|
|
1900 |
Example:
|
|
|
1901 |
int f2(int i)
|
|
|
1902 |
{
|
|
|
1903 |
int val;
|
|
|
1904 |
|
|
|
1905 |
TICKB("f2");
|
|
|
1906 |
for (i = 0; i < 5; i++) {
|
|
|
1907 |
TICK("f2_before");
|
|
|
1908 |
val++;
|
|
|
1909 |
}
|
|
|
1910 |
TICKX("f2");
|
|
|
1911 |
|
|
|
1912 |
return val+5;
|
|
|
1913 |
}
|
|
|
1914 |
|
|
|
1915 |
If enabled, the TICK family of macros print the tracepoint name, a colon
|
|
|
1916 |
and a newline using the sl_sout() support routine.
|
|
|
1917 |
|
|
|
1918 |
The TICK, TICKB and TICKX macros update the count statistics
|
|
|
1919 |
associated with the tracepoint, whether enabled or disabled. However, the
|
|
|
1920 |
statistics are not updated if all tracing has been disabled as the result of
|
|
|
1921 |
disabling the special tracepoint named "trace". The TICKN macro never
|
|
|
1922 |
updates any statistics.
|
|
|
1923 |
|
|
|
1924 |
The TICKB macro begins timing code and the TICKX macro ends timing
|
|
|
1925 |
code.
|
|
|
1926 |
|
|
|
1927 |
|
|
|
1928 |
Macros:
|
|
|
1929 |
TRACE(tracepoint_name, code_list)
|
|
|
1930 |
TRACEB(tracepoint_name, code_list)
|
|
|
1931 |
TRACEN(tracepoint_name, code_list)
|
|
|
1932 |
TRACEX(tracepoint_name, code_list)
|
|
|
1933 |
|
|
|
1934 |
Synopsis:
|
|
|
1935 |
TRACE: Execute code list and update count statistics.
|
|
|
1936 |
TRACEB: Entry macro. Otherwise same as TRACE.
|
|
|
1937 |
TRACEN: Do not update count statistics. Otherwise same as TRACE.
|
|
|
1938 |
TRACEX: Exit macro. Otherwise same as TRACE.
|
|
|
1939 |
|
|
|
1940 |
Example:
|
|
|
1941 |
int f3(int i)
|
|
|
1942 |
{
|
|
|
1943 |
int val;
|
|
|
1944 |
|
|
|
1945 |
TRACEB("f3", printf("f3 entry: %d\n", i));
|
|
|
1946 |
for (i = 0; i < 5; i++) {
|
|
|
1947 |
TRACE("f3_loop",
|
|
|
1948 |
printf("f3: i = %d\n", i));
|
|
|
1949 |
val++;
|
|
|
1950 |
}
|
|
|
1951 |
RETURN_INT("f3", val+5);
|
|
|
1952 |
}
|
|
|
1953 |
|
|
|
1954 |
If enabled, the TRACE family of macros execute a code list containing
|
|
|
1955 |
zero, one, or more executable C statements of any kind.
|
|
|
1956 |
|
|
|
1957 |
The TRACE, TRACEB and TRACEX macros update the count statistics
|
|
|
1958 |
associated with the tracepoint, whether enabled or disabled. However, the
|
|
|
1959 |
statistics are not updated if all tracing has been disabled as the result of
|
|
|
1960 |
disabling the special tracepoint named "trace". The TRACEN macro never
|
|
|
1961 |
updates any statistics.
|
|
|
1962 |
|
|
|
1963 |
The TRACEB macro begins timing code and the TRACEX macro ends
|
|
|
1964 |
timing code.
|
|
|
1965 |
|
|
|
1966 |
|
|
|
1967 |
Macros:
|
|
|
1968 |
TRACEP(tracepoint_name, code_list)
|
|
|
1969 |
TRACEPB(tracepoint_name, code_list)
|
|
|
1970 |
TRACEPN(tracepoint_name, code_list)
|
|
|
1971 |
TRACEPX(tracepoint_name, code_list)
|
|
|
1972 |
|
|
|
1973 |
Synopsis:
|
|
|
1974 |
TRACEP: Print the tracepoint name, execute code list and
|
|
|
1975 |
update count statistics.
|
|
|
1976 |
TRACEPB: Entry macro. Otherwise same as TRACEP.
|
|
|
1977 |
TRACEPN: Do not update count statistics. Otherwise same as
|
|
|
1978 |
TRACEP.
|
|
|
1979 |
TRACEPX: Exit macro. Otherwise same as TRACEP.
|
|
|
1980 |
|
|
|
1981 |
Example:
|
|
|
1982 |
int f4(int i)
|
|
|
1983 |
{
|
|
|
1984 |
int val;
|
|
|
1985 |
|
|
|
1986 |
TRACEPB("f4", printf("(%d)\n", i));
|
|
|
1987 |
for (i = 0; i < 5; i++) {
|
|
|
1988 |
TRACEP("f4_loop", printf("i = %d\n", i));
|
|
|
1989 |
val++;
|
|
|
1990 |
}
|
|
|
1991 |
RETURN_INT("f4", val+5);
|
|
|
1992 |
}
|
|
|
1993 |
|
|
|
1994 |
If enabled, the TRACEP family of macros print the tracepoint name, a
|
|
|
1995 |
colon and a blank, and then execute a code list containing zero, one, or
|
|
|
1996 |
more executable C statements of any kind. The tracepoint name, colon and
|
|
|
1997 |
blank are printed using the sl_sout() support routine.
|
|
|
1998 |
|
|
|
1999 |
The TRACEP, TRACEPB and TRACEPX macros update the count
|
|
|
2000 |
statistics associated with the tracepoint, whether enabled or disabled.
|
|
|
2001 |
However, the statistics are not updated if all tracing has been disabled as
|
|
|
2002 |
the result of disabling the special tracepoint named "trace". The
|
|
|
2003 |
TRACEPN macro never updates any statistics.
|
|
|
2004 |
|
|
|
2005 |
The TRACEPB macro begins timing code and the TRACEPX macro ends
|
|
|
2006 |
timing code.
|
|
|
2007 |
|
|
|
2008 |
|
|
|
2009 |
|
|
|
2010 |
CHAPTER 6 SPP REFERENCE
|
|
|
2011 |
|
|
|
2012 |
SPP is a utility program that copies an input file to an output file, inserting
|
|
|
2013 |
Sherlock macros that trace the entry and exit of all functions. TICKB
|
|
|
2014 |
macros or TRACEPB macros containing printf statements are inserted at
|
|
|
2015 |
the start of functions, return instructions are replaced by RETURN_xxx
|
|
|
2016 |
macros, and TICKX macros are inserted where control might "fall off the
|
|
|
2017 |
end" of functions. SPP also inserts SL_INIT and SL_PARSE macros at
|
|
|
2018 |
the start of the main() function. Several command line options vary the
|
|
|
2019 |
kind and quantity of macros output inserted by SPP.
|
|
|
2020 |
|
|
|
2021 |
SPP is essentially a source-to-source C compiler which understands the
|
|
|
2022 |
type of all variables and functions. SPP handles all styles of C syntax,
|
|
|
2023 |
from K&R to the ANSI draft standard of January 11, 1988. SPP is
|
|
|
2024 |
robust: it flags all syntax errors and will place correct macros in the
|
|
|
2025 |
appropriate locations in spite of most syntax errors. It is recommended,
|
|
|
2026 |
however, that SPP be used only on files that contain no syntax errors,
|
|
|
2027 |
i.e., on files that have been previously been compiled without generating
|
|
|
2028 |
any error messages.
|
|
|
2029 |
|
|
|
2030 |
SPP generates RETURN_BOOL macros in functions declared bool as long
|
|
|
2031 |
as the declaration:
|
|
|
2032 |
|
|
|
2033 |
typedef int bool;
|
|
|
2034 |
|
|
|
2035 |
appears before the bool function. SPP generates printf statements that
|
|
|
2036 |
print boolean arguments as either "TRUE" or "FALSE" instead of 1 or 0.
|
|
|
2037 |
This is done using calls to a support routine called sl_sbout(). The
|
|
|
2038 |
RETURN_BOOL macro is not affected by this feature.For example, SPP
|
|
|
2039 |
will insert the following macros:
|
|
|
2040 |
|
|
|
2041 |
bool f(bool b)
|
|
|
2042 |
{
|
|
|
2043 |
TRACEPB("f", printf("(%s)\n", sl_sbout(b)));
|
|
|
2044 |
...
|
|
|
2045 |
RETURN_BOOL("f", 1);
|
|
|
2046 |
}
|
|
|
2047 |
|
|
|
2048 |
SPP assumes that all pointers to characters are pointers to a valid string.
|
|
|
2049 |
As a result, you should change the RETURN_STRING macros generated
|
|
|
2050 |
by SPP to RETURN_PTR macros in functions such as malloc() which
|
|
|
2051 |
return a pointer that can not be printed as a string.
|
|
|
2052 |
|
|
|
2053 |
SPP warns about functions that do not return a value and are not explicitly
|
|
|
2054 |
declared void.
|
|
|
2055 |
|
|
|
2056 |
SPP issues the warning, "Macro found where entry macro should be," if
|
|
|
2057 |
SPP finds a macro call where the first executable statement of a function is
|
|
|
2058 |
expected. In such cases, SPP will skip the generation of an entry macro,
|
|
|
2059 |
i.e., TICKB or TRACEPB. Instead, SPP assumes the macro starts
|
|
|
2060 |
executable code.
|
|
|
2061 |
|
|
|
2062 |
For example:
|
|
|
2063 |
|
|
|
2064 |
int f(void)
|
|
|
2065 |
{
|
|
|
2066 |
int a;
|
|
|
2067 |
MY_TRACE_MACRO(a);
|
|
|
2068 |
return a;
|
|
|
2069 |
}
|
|
|
2070 |
|
|
|
2071 |
SPP will generate the following code:
|
|
|
2072 |
|
|
|
2073 |
int f(void)
|
|
|
2074 |
{
|
|
|
2075 |
int a;
|
|
|
2076 |
MY_TRACE_MACRO(a);
|
|
|
2077 |
RETURN_INT("f",a);
|
|
|
2078 |
}
|
|
|
2079 |
|
|
|
2080 |
SPP generates macros for a function only if the first executable statement
|
|
|
2081 |
of that function is not already a Sherlock macro. SPP will generate the
|
|
|
2082 |
warning, "Sherlock macros generated for this function," if a Sherlock
|
|
|
2083 |
macro is encountered while generating macros for a function. That is, the
|
|
|
2084 |
warning will be generated if the function contains Sherlock macros but the
|
|
|
2085 |
first executable statement is not a Sherlock macro. This new feature is
|
|
|
2086 |
very handyDyou can now run your source files through SPP any time you
|
|
|
2087 |
add any function and SPP will leave the functions already containing
|
|
|
2088 |
Sherlock macros alone.
|
|
|
2089 |
|
|
|
2090 |
Two new macros, SL_ENABLE() and SL_DISABLE(), allow function-
|
|
|
2091 |
by-function control over SPP. Both macros always expand to empty code.
|
|
|
2092 |
Insert SL_DISABLE() as the first executable statement of a function in
|
|
|
2093 |
which you want no more Sherlock macros to be inserted. For example:
|
|
|
2094 |
|
|
|
2095 |
int f(void)
|
|
|
2096 |
{
|
|
|
2097 |
declarations;
|
|
|
2098 |
SL_DISABLE();
|
|
|
2099 |
No Sherlock macros will be generated in this function.
|
|
|
2100 |
}
|
|
|
2101 |
|
|
|
2102 |
The SL_ENABLE() macro forces SPP to insert macros into a function.
|
|
|
2103 |
Use this macro when a function starts with a Sherlock macro that you
|
|
|
2104 |
inserted yourself. For example:
|
|
|
2105 |
|
|
|
2106 |
int do_command_line(int argc, char **argv)
|
|
|
2107 |
{
|
|
|
2108 |
declarations;
|
|
|
2109 |
SL_ENABLE();
|
|
|
2110 |
TRACEP("do_command_line",
|
|
|
2111 |
for (i = 1; i < argc; i++) {
|
|
|
2112 |
printf("argv[%d]: %s\n", argc, argv);
|
|
|
2113 |
}
|
|
|
2114 |
);
|
|
|
2115 |
Sherlock macros will be generated as usual.
|
|
|
2116 |
}
|
|
|
2117 |
|
|
|
2118 |
Be sure to delete the SL_ENABLE() macro after SPP processes the
|
|
|
2119 |
function.
|
|
|
2120 |
|
|
|
2121 |
|
|
|
2122 |
Invoke SPP as follows:
|
|
|
2123 |
|
|
|
2124 |
SPP input_file output_file [options]
|
|
|
2125 |
|
|
|
2126 |
SPP supports the INCLUDE environment variable, which is set with the
|
|
|
2127 |
DOS set command. For example, the DOS command:
|
|
|
2128 |
|
|
|
2129 |
set INCLUDE=c:\include;d:\sherlock
|
|
|
2130 |
|
|
|
2131 |
will cause SPP to search the c:\include and d:\sherlock directories for
|
|
|
2132 |
#include files. The directories specified by the INCLUDE environment
|
|
|
2133 |
variable are searched after any directories specified by the -s SPP option.
|
|
|
2134 |
|
|
|
2135 |
Options are one of the following:
|
|
|
2136 |
|
|
|
2137 |
|
|
|
2138 |
-d <id>=<string>
|
|
|
2139 |
|
|
|
2140 |
Define <id> to be <string>, as if the statement #define <id> <string>
|
|
|
2141 |
appeared at the start of the program. A space must separate -d and <id>,
|
|
|
2142 |
but no space may appear in <string> or around the equal sign. The
|
|
|
2143 |
<string> is optional, in which case the equal sign can be omitted.
|
|
|
2144 |
Examples:
|
|
|
2145 |
|
|
|
2146 |
-d STDC=1
|
|
|
2147 |
-d SHERLOCK
|
|
|
2148 |
|
|
|
2149 |
|
|
|
2150 |
-f <file name>
|
|
|
2151 |
|
|
|
2152 |
Use alternate macro names. The file named in <file name> contains a list
|
|
|
2153 |
of synonym lines. Each line contains two macro names, a standard name
|
|
|
2154 |
and a synonym. SPP will output the synonyms instead of the standard
|
|
|
2155 |
macro names. The pound character (#) starts a comment which continues
|
|
|
2156 |
to the end of the line. An example synonym file:
|
|
|
2157 |
|
|
|
2158 |
#synonym file: May 20, 1988
|
|
|
2159 |
#
|
|
|
2160 |
TICKB BEGIN_TIMING_CODE
|
|
|
2161 |
TICKX END_TIMING_CODE
|
|
|
2162 |
SL_DUMP REPORT_STATISTICS
|
|
|
2163 |
|
|
|
2164 |
|
|
|
2165 |
-i
|
|
|
2166 |
|
|
|
2167 |
Insert the line #include <sl.h> at the start of the output file.
|
|
|
2168 |
|
|
|
2169 |
|
|
|
2170 |
-n
|
|
|
2171 |
|
|
|
2172 |
Allow nested comments. By default, comments do not nest.
|
|
|
2173 |
|
|
|
2174 |
|
|
|
2175 |
-o
|
|
|
2176 |
Output sl_cout() and related support routines instead of printf(). SPP
|
|
|
2177 |
generates more compact code when using the -o option by generating calls
|
|
|
2178 |
to three new support routines: sl_lpout(void), sl_rpout(void) and
|
|
|
2179 |
sl_csout(void). These routines are equivalent to sl_cout("("), sl_sout(")"),
|
|
|
2180 |
and sl_sout(", ") respectively.
|
|
|
2181 |
|
|
|
2182 |
|
|
|
2183 |
-s <path>
|
|
|
2184 |
|
|
|
2185 |
Add <path> to the list of paths used to search for include files. More than
|
|
|
2186 |
one -s option may be used. A space must separate -s and <path>. Example:
|
|
|
2187 |
|
|
|
2188 |
-s \usr\include -s \sources -s \sherlock
|
|
|
2189 |
|
|
|
2190 |
-t
|
|
|
2191 |
|
|
|
2192 |
Suppress the generation of entry or exit macros. TICK and TRACEP macros are
|
|
|
2193 |
generated instead of TICKB and TRACEPB macros. No RETURN_xxx macros are
|
|
|
2194 |
generated.
|
|
|
2195 |
|
|
|
2196 |
|
|
|
2197 |
-u <id>
|
|
|
2198 |
|
|
|
2199 |
Undefine <id>, as if the statement #undef <id> appeared at the start of the
|
|
|
2200 |
program. A space must separate -u and <id>.
|
|
|
2201 |
|
|
|
2202 |
-x
|
|
|
2203 |
|
|
|
2204 |
Do not recognize single-line comments.
|
|
|
2205 |
|
|
|
2206 |
By default, SPP recognizes single-line comments, which start with // and
|
|
|
2207 |
continue to the end of the line. As you would expect, the // sequence is
|
|
|
2208 |
treated as ordinary characters in comments and inside strings. Single-line
|
|
|
2209 |
comments are not part of the Draft ANSI C standard, but are offered as
|
|
|
2210 |
language extensions by several C compilers, including the Microsoft C
|
|
|
2211 |
compiler.
|
|
|
2212 |
|
|
|
2213 |
A fine point: each single-line comment is converted to a single blank in the
|
|
|
2214 |
replacement text of a #define preprocessor directive. The // characters and
|
|
|
2215 |
any following characters do not become part of the replacement text of the
|
|
|
2216 |
macro being defined. This is consistent with how ordinary C comments
|
|
|
2217 |
are handled in the Draft ANSI C Standard, and is also consistent with how
|
|
|
2218 |
current C++ compilers work. However, old C++ translators handled //
|
|
|
2219 |
differently. Warning: the description of single-line comments on page 130
|
|
|
2220 |
of The C++ Programming Language, by Bjarne Stroustrup, describes the
|
|
|
2221 |
anachronistic operation of the old C++ translators, not current C and C++
|
|
|
2222 |
compilers.
|
|
|
2223 |
|
|
|
2224 |
|
|
|
2225 |
Example:
|
|
|
2226 |
|
|
|
2227 |
Original program:
|
|
|
2228 |
|
|
|
2229 |
int example(char * string, double)
|
|
|
2230 |
{
|
|
|
2231 |
int i;
|
|
|
2232 |
i = 25;
|
|
|
2233 |
return i;
|
|
|
2234 |
}
|
|
|
2235 |
|
|
|
2236 |
Default output from SPP:
|
|
|
2237 |
|
|
|
2238 |
int example(char * string, double d)
|
|
|
2239 |
{
|
|
|
2240 |
int i;
|
|
|
2241 |
TRACEPB("example",printf("(%s, %f)\n", string, d));
|
|
|
2242 |
i = 25;
|
|
|
2243 |
RETURN_INT("example", i);
|
|
|
2244 |
}
|
|
|
2245 |
|
|
|
2246 |
Output from SPP with the -t option on:
|
|
|
2247 |
|
|
|
2248 |
int example(char * string, double d)
|
|
|
2249 |
{
|
|
|
2250 |
int i;
|
|
|
2251 |
TRACEP("example",printf("(%s, %f)\n", string, d));
|
|
|
2252 |
i = 25;
|
|
|
2253 |
return i;
|
|
|
2254 |
}
|
|
|
2255 |
|
|
|
2256 |
Output from SPP with the -o option on:
|
|
|
2257 |
|
|
|
2258 |
int example(char * string, double d)
|
|
|
2259 |
{
|
|
|
2260 |
int i;
|
|
|
2261 |
TRACEPB("example", sl_lpout();
|
|
|
2262 |
sl_sout(string); sl_csout();
|
|
|
2263 |
sl_dout(d); sl_rlout());
|
|
|
2264 |
i = 25;
|
|
|
2265 |
RETURN_INT("example", i);
|
|
|
2266 |
}
|
|
|
2267 |
|
|
|
2268 |
|
|
|
2269 |
|
|
|
2270 |
CHAPTER 7 SDEL REFERENCE
|
|
|
2271 |
|
|
|
2272 |
|
|
|
2273 |
SDEL is a utility program that copies an input file to an output file, deleting
|
|
|
2274 |
all calls to Sherlock macros as it does so. It is not usually necessary to
|
|
|
2275 |
remove Sherlock macros from a program in order to eliminate all the code
|
|
|
2276 |
generated by Sherlock macros. Indeed, you can eliminate all Sherlock
|
|
|
2277 |
tracing code from your application simply by undefining the constant called
|
|
|
2278 |
SHERLOCK and recompiling your program. However, there may be
|
|
|
2279 |
times when you want to remove all Sherlock macros from one of your
|
|
|
2280 |
source files. For instance, you may want to delete all Sherlock macros
|
|
|
2281 |
before automatically re-introducing them with SPP.
|
|
|
2282 |
|
|
|
2283 |
Invoke SDEL as follows:
|
|
|
2284 |
|
|
|
2285 |
SDEL input_file output_file [options]
|
|
|
2286 |
|
|
|
2287 |
For your protection, the name of the input file may not be the same as the
|
|
|
2288 |
output file, and the output file must not already exist.
|
|
|
2289 |
|
|
|
2290 |
Options are one of the following:
|
|
|
2291 |
|
|
|
2292 |
|
|
|
2293 |
-d
|
|
|
2294 |
|
|
|
2295 |
Do not delete SL_DISABLE() macros.
|
|
|
2296 |
|
|
|
2297 |
|
|
|
2298 |
|
|
|
2299 |
-f <file name>
|
|
|
2300 |
|
|
|
2301 |
Use alternate macro names. The file named in <file name> contains a list
|
|
|
2302 |
of synonym lines. Each line contains two macro names, a standard name
|
|
|
2303 |
and a synonym. SDEL will delete the synonyms instead of the standard
|
|
|
2304 |
macro names. The pound character (#) starts a comment which continues
|
|
|
2305 |
to the end of the line. An example synonym file:
|
|
|
2306 |
|
|
|
2307 |
#synonym file: May 20, 1988
|
|
|
2308 |
#
|
|
|
2309 |
TICKB BEGIN_TIMING_CODE
|
|
|
2310 |
TICKX END_TIMING_CODE
|
|
|
2311 |
SL_DUMP REPORT_STATISTICS
|
|
|
2312 |
|
|
|
2313 |
|
|
|
2314 |
-i
|
|
|
2315 |
|
|
|
2316 |
Remove any lines consisting solely of:
|
|
|
2317 |
|
|
|
2318 |
#include "sl.h"
|
|
|
2319 |
|
|
|
2320 |
|
|
|
2321 |
-n
|
|
|
2322 |
|
|
|
2323 |
Allow nested comments. By default, comments do not nest.
|
|
|
2324 |
|
|
|
2325 |
|
|
|
2326 |
-r
|
|
|
2327 |
|
|
|
2328 |
Retain all SL_NAME macros (or synonyms for SL_NAME) in the output.
|
|
|
2329 |
|
|
|
2330 |
|
|
|
2331 |
-t
|
|
|
2332 |
|
|
|
2333 |
Output trigraph sequences instead of the following nine characters:
|
|
|
2334 |
|
|
|
2335 |
# [ ] \ { } ^ | ~
|
|
|
2336 |
|
|
|
2337 |
|
|
|
2338 |
|
|
|
2339 |
CHAPTER 8 SDIF REFERENCE
|
|
|
2340 |
|
|
|
2341 |
|
|
|
2342 |
SDIF is a special purpose file comparison programDit compares two files
|
|
|
2343 |
which should be identical except for the presence of Sherlock macros.
|
|
|
2344 |
SDIF allows you to see at a glance which macros where inserted into a file
|
|
|
2345 |
by SPP. You can also use SDIF to check the operation of SPP and SDEL.
|
|
|
2346 |
Given any file f.c containing Sherlock macros, the following sequence of
|
|
|
2347 |
commands should produce output from SDIF consisting of lines containing
|
|
|
2348 |
only white space:
|
|
|
2349 |
|
|
|
2350 |
sdel f.c temp1.c
|
|
|
2351 |
spp temp1.c temp2.c
|
|
|
2352 |
sdel temp2.c temp3.c
|
|
|
2353 |
sdif temp1.c temp3.c
|
|
|
2354 |
|
|
|
2355 |
Invoke SDIF as follows:
|
|
|
2356 |
|
|
|
2357 |
SDIF file1(with_macros) file2(without_macros) [-b] [-v]
|
|
|
2358 |
|
|
|
2359 |
File1 is assumed to be identical to file2 except that file1 contains Sherlock
|
|
|
2360 |
macros and file2 does not.
|
|
|
2361 |
|
|
|
2362 |
The -b option causes SDIF to display inserted or deleted lines consisting
|
|
|
2363 |
only on blanks or tabs. By default SDIF does not display such lines
|
|
|
2364 |
unless the -v option is in effect.
|
|
|
2365 |
|
|
|
2366 |
If the -v option is present, each line of file1 is printed, preceded by its
|
|
|
2367 |
position in file1 and its position in file2 if the line also appears in file2. If
|
|
|
2368 |
the -v option is not present, only lines which are present in one file but not
|
|
|
2369 |
the other are printed.
|
|
|
2370 |
|
|
|
2371 |
All output is sent to the standard output stream and may be redirected on
|
|
|
2372 |
the command line.
|
|
|
2373 |
|
|
|
2374 |
|
|
|
2375 |
|
|
|
2376 |
CHAPTER 9 CPP REFERENCE
|
|
|
2377 |
|
|
|
2378 |
|
|
|
2379 |
CPP is a preprocessor for the C language which has been included as an
|
|
|
2380 |
extensive example of how to use Sherlock macros. CPP fully implements
|
|
|
2381 |
the draft ANSI standard of January 11, 1988. For a complete discussion
|
|
|
2382 |
of what CPP does read section 3.8 of the draft standard. A more general
|
|
|
2383 |
discussion of what CPP does can be found in the book, The C
|
|
|
2384 |
Programming Language, by Brian W. Kernighan and Dennis M. Ritchie,
|
|
|
2385 |
published by Prentice-Hall.
|
|
|
2386 |
|
|
|
2387 |
Basically, CPP copies an input file to an output file doing the following as
|
|
|
2388 |
it does so:
|
|
|
2389 |
|
|
|
2390 |
o It includes files whenever it sees an include directive. Included files may
|
|
|
2391 |
themselves contain include directives, which may be nested to any depth.
|
|
|
2392 |
|
|
|
2393 |
o It expands macros. Macros may have arguments and may be call other
|
|
|
2394 |
macros.
|
|
|
2395 |
|
|
|
2396 |
o It conditionally includes lines based on whether symbols have been
|
|
|
2397 |
defined or on the value of constant expressions. The directives used for
|
|
|
2398 |
this purpose may be nested to any depth.
|
|
|
2399 |
|
|
|
2400 |
o It eliminates all white space, including comments, thereby reducing the
|
|
|
2401 |
size of the output. White space can be included in the output using a
|
|
|
2402 |
command line option.
|
|
|
2403 |
|
|
|
2404 |
Invoke CPP as follows:
|
|
|
2405 |
|
|
|
2406 |
CPP input_file output_file [options]
|
|
|
2407 |
|
|
|
2408 |
Options are one of the following:
|
|
|
2409 |
|
|
|
2410 |
|
|
|
2411 |
-c
|
|
|
2412 |
|
|
|
2413 |
Include comments and white space in the output file.
|
|
|
2414 |
|
|
|
2415 |
|
|
|
2416 |
-d <id>=<string>
|
|
|
2417 |
|
|
|
2418 |
Define an identifier as if a define directive appeared before the first line of
|
|
|
2419 |
the program. For example:
|
|
|
2420 |
|
|
|
2421 |
CPP in out -d a=xyz
|
|
|
2422 |
|
|
|
2423 |
The last example defines the macro a to have the replacement text xyz. The
|
|
|
2424 |
equal sign is not part of the replacement text. If the equal sign and
|
|
|
2425 |
replacement text are omitted, a null definition is created. For example, the
|
|
|
2426 |
following is valid:
|
|
|
2427 |
|
|
|
2428 |
CPP in out -d a
|
|
|
2429 |
|
|
|
2430 |
One or more spaces are required following the -d argument and spaces are
|
|
|
2431 |
prohibited around the equal sign. In other words, the -d and a=5 are two,
|
|
|
2432 |
and only two, separate command line arguments.
|
|
|
2433 |
|
|
|
2434 |
|
|
|
2435 |
-n
|
|
|
2436 |
|
|
|
2437 |
Allow nested comments. For example, the following is a nested comment
|
|
|
2438 |
which is valid only when using the -n option.
|
|
|
2439 |
|
|
|
2440 |
/*comment out - - - - -
|
|
|
2441 |
a = 5;
|
|
|
2442 |
/* This is a nested comment. */
|
|
|
2443 |
b = 5;
|
|
|
2444 |
- - - - - end comment out */
|
|
|
2445 |
|
|
|
2446 |
|
|
|
2447 |
|
|
|
2448 |
-s <path>
|
|
|
2449 |
|
|
|
2450 |
Add a path to the list of "standard places" which is used when searching
|
|
|
2451 |
for included files.
|
|
|
2452 |
For example:
|
|
|
2453 |
|
|
|
2454 |
CPP in out -s \src -s \etc
|
|
|
2455 |
|
|
|
2456 |
adds the directories called \src and \etc to the end of the list of standard
|
|
|
2457 |
places. Initially, the list of standard places is obtained by reading the
|
|
|
2458 |
INCLUDE environment variable. For example:
|
|
|
2459 |
|
|
|
2460 |
set INCLUDE=c:\include;c:\usr\include
|
|
|
2461 |
|
|
|
2462 |
causes the list of standard places to contain c:\include and c:\usr\include.
|
|
|
2463 |
|
|
|
2464 |
|
|
|
2465 |
-u <id>
|
|
|
2466 |
|
|
|
2467 |
Cancel the initial definition of a macro. For example,
|
|
|
2468 |
|
|
|
2469 |
CPP in out -u SHERLOCK
|
|
|
2470 |
|
|
|
2471 |
cancels the effect of the first definition of the macro called SHERLOCK,
|
|
|
2472 |
just as if that definition had been immediately followed by
|
|
|
2473 |
|
|
|
2474 |
#undef SHERLOCK
|
|
|
2475 |
|
|
|
2476 |
|
|
|
2477 |
|
|
|
2478 |
APPENDIX A: RUN TIME ERROR MESSAGES
|
|
|
2479 |
|
|
|
2480 |
|
|
|
2481 |
This appendix lists the error messages that are generated by the support
|
|
|
2482 |
routines in the file sherlock.c. You will encounter these messages only
|
|
|
2483 |
while you are running a program containing Sherlock macros, never
|
|
|
2484 |
while compiling. There are two sources of errors that will produce these
|
|
|
2485 |
messages: faulty Sherlock command line arguments and faulty tracepoint
|
|
|
2486 |
names in Sherlock macros. The following abbreviations will be used in
|
|
|
2487 |
the explanation of these error messages:
|
|
|
2488 |
|
|
|
2489 |
<addr> The hexadecimal address where the error occurred.
|
|
|
2490 |
<char> A single character, printed in %c format.
|
|
|
2491 |
<name> The name of the macro, i.e., TICK, TRACE, etc.
|
|
|
2492 |
<on_prefix> The on_prefix parameter to the SL_PARSE macro.
|
|
|
2493 |
<off_prefix> The off_string parameter to the SL_PARSE macro.
|
|
|
2494 |
<string> The string representing the tracepoint name.
|
|
|
2495 |
|
|
|
2496 |
|
|
|
2497 |
sl_check:<name>: null string @ <addr>.
|
|
|
2498 |
|
|
|
2499 |
The tracepoint name passed to a macro was the NULL string.
|
|
|
2500 |
|
|
|
2501 |
|
|
|
2502 |
sl_check:<name>: bad character <char> in <string> @ <addr>.
|
|
|
2503 |
|
|
|
2504 |
The tracepoint name of a macro contains an invalid character. Only
|
|
|
2505 |
the following characters are valid in tracepoint names:
|
|
|
2506 |
|
|
|
2507 |
o The letters a through z and A through Z.
|
|
|
2508 |
o The numerals 0 through 9.
|
|
|
2509 |
o The underscore character.
|
|
|
2510 |
o The wildcard characters * and ? (on the command line only.)
|
|
|
2511 |
|
|
|
2512 |
|
|
|
2513 |
sl_check: <name>: run on argument: <string> @ <addr>.
|
|
|
2514 |
|
|
|
2515 |
The tracepoint name passed to a macro contained more than 25 characters.
|
|
|
2516 |
|
|
|
2517 |
|
|
|
2518 |
sl_init: Header version does not match run-time version.
|
|
|
2519 |
|
|
|
2520 |
The version of the macros in the file sl.h or sl1.h does not match the
|
|
|
2521 |
version of the code in the file sherlock.c. Change either the version of
|
|
|
2522 |
the header file that you use to compile your programs or the version of
|
|
|
2523 |
the support routines that are linked with your program.
|
|
|
2524 |
|
|
|
2525 |
|
|
|
2526 |
sl_ret: Entry/Exit mismatch at exit point <string>.
|
|
|
2527 |
Check for missing or misnamed exit macros.
|
|
|
2528 |
Dump of call stack:
|
|
|
2529 |
|
|
|
2530 |
The tracepoint name passed to an exit macro does not match the
|
|
|
2531 |
tracepoint name on top of the timing stack. This indicates that name of
|
|
|
2532 |
the most recently executed entry macro does not match the name of the
|
|
|
2533 |
current exit macro. As an aid in finding out where the problem occurred,
|
|
|
2534 |
the tracepoint names on the call stack are printed out.
|
|
|
2535 |
|
|
|
2536 |
|
|
|
2537 |
Lone <on_prefix>
|
|
|
2538 |
|
|
|
2539 |
The on_prefix appeared alone on the command line. It must be
|
|
|
2540 |
followed immediately with no intervening spaces by a tracepoint name.
|
|
|
2541 |
This command line error immediately terminates the program.
|
|
|
2542 |
|
|
|
2543 |
|
|
|
2544 |
Lone <off_prefix>
|
|
|
2545 |
|
|
|
2546 |
The off_prefix appeared alone on the command line. It must be followed
|
|
|
2547 |
immediately with no intervening spaces by a tracepoint name. This
|
|
|
2548 |
command line error immediately terminates the program.
|
|
|
2549 |
|
|
|
2550 |
|
|
|
2551 |
Trace table overflow.
|
|
|
2552 |
|
|
|
2553 |
Too many tracepoint names were encountered during execution of your
|
|
|
2554 |
program. Different tracepoints with the same names do not add to this
|
|
|
2555 |
total. Neither do tracepoints that are never executed.
|
|
|
2556 |
|
|
|
2557 |
To increase the maximum allowable number of tracepoint names, increase
|
|
|
2558 |
the MAX_STAT variable in sherlock.c and recompile sherlock.c. To
|
|
|
2559 |
decrease the number of tracepoint names used by your program, undefine
|
|
|
2560 |
SHERLOCK in one or more of your source files and recompile those files.
|
|
|
2561 |
|
|
|
2562 |
The tracing tables used by Sherlock are statically allocated so they do not
|
|
|
2563 |
interfere with the tracing of routines that do dynamic storage allocation.
|