home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 355_01 / slk1.exe / SHERLOCK.DOC < prev    next >
Text File  |  1991-06-11  |  80KB  |  2,143 lines

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