home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 318_02 / sherlock.doc < prev    next >
Text File  |  1990-06-18  |  96KB  |  2,564 lines

  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.
  2564.