home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-07-02 | 61.2 KB | 2,261 lines |
- Newsgroups: comp.sources.misc
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Subject: v07i058: DBUG Package (Part 2 of 3)
- Reply-To: fnf@estinc.UUCP
-
- Posting-number: Volume 7, Issue 58
- Submitted-by: fnf@estinc.UUCP
- Archive-name: dbug/part02
-
- This is the latest version of my dbug package, a relatively portable and
- machine independent macro based C debugging package. The dbug package
- has proven to be a very flexible and useful tool for debugging, testing,
- and porting C programs.
-
- All of the features of the dbug package can be enabled or disabled
- dynamically at execution time. This means that production programs will
- run normally when debugging is not enabled, and eliminates the need to
- maintain two separate versions of a program during testing.
-
- Many of the things easily accomplished with conventional debugging tools,
- such as symbolic debuggers, are difficult or impossible with this package,
- and vice versa. Thus the dbug package should not be thought of as a
- replacement or substitute for other debugging tools, but simply as a useful
- addition to the program development and maintenance environment.
-
- One of the new features with this version is stack usage accounting. You
- can discover the total amount of stack used by your program, and the amount
- used by each individual function. You will need to know in which direction
- you stack grows (up or down).
-
- -Fred Fish 12-Jun-89
-
- #--------CUT---------CUT---------CUT---------CUT--------#
- #########################################################
- # #
- # This is a shell archive file. To extract files: #
- # #
- # 1) Make a directory for the files. #
- # 2) Write a file, such as "file.shar", containing #
- # this archive file into the directory. #
- # 3) Type "sh file.shar". Do not use csh. #
- # #
- #########################################################
- #
- #
- echo Extracting analyze.c:
- sed 's/^Z//' >analyze.c <<\STUNKYFLUFF
- Z/*
- Z * Analyze the profile file (cmon.out) written out by the dbug
- Z * routines with profiling enabled.
- Z *
- Z * Copyright June 1987, Binayak Banerjee
- Z * All rights reserved.
- Z *
- Z * This program may be freely distributed under the same terms and
- Z * conditions as Fred Fish's Dbug package.
- Z *
- Z * Compile with -- cc -O -s -o %s analyze.c
- Z *
- Z * Analyze will read an trace file created by the dbug package
- Z * (when run with traceing enabled). It will then produce a
- Z * summary on standard output listing the name of each traced
- Z * function, the number of times it was called, the percentage
- Z * of total calls, the time spent executing the function, the
- Z * proportion of the total time and the 'importance'. The last
- Z * is a metric which is obtained by multiplying the proportions
- Z * of calls and the proportions of time for each function. The
- Z * greater the importance, the more likely it is that a speedup
- Z * could be obtained by reducing the time taken by that function.
- Z *
- Z * Note that the timing values that you obtain are only rough
- Z * measures. The overhead of the dbug package is included
- Z * within. However, there is no need to link in special profiled
- Z * libraries and the like.
- Z *
- Z * CHANGES:
- Z *
- Z * 2-Mar-89: fnf
- Z * Changes to support tracking of stack usage. This required
- Z * reordering the fields in the profile log file to make
- Z * parsing of different record types easier. Corresponding
- Z * changes made in dbug runtime library. Also used this
- Z * opportunity to reformat the code more to my liking (my
- Z * apologies to Binayak Banerjee for "uglifying" his code).
- Z *
- Z * 24-Jul-87: fnf
- Z * Because I tend to use functions names like
- Z * "ExternalFunctionDoingSomething", I've rearranged the
- Z * printout to put the function name last in each line, so
- Z * long names don't screw up the formatting unless they are
- Z * *very* long and wrap around the screen width...
- Z *
- Z * 24-Jul-87: fnf
- Z * Modified to put out table very similar to Unix profiler
- Z * by default, but also puts out original verbose table
- Z * if invoked with -v flag.
- Z */
- Z
- Z#include <stdio.h>
- Z#include "useful.h"
- Z
- Zstatic char *my_name;
- Zstatic int verbose;
- Z
- Z/*
- Z * Structure of the stack.
- Z */
- Z
- Z#define PRO_FILE "dbugmon.out" /* Default output file name */
- Z#define STACKSIZ 100 /* Maximum function nesting */
- Z#define MAXPROCS 1000 /* Maximum number of function calls */
- Z
- Zstruct stack_t {
- Z unsigned int pos; /* which function? */
- Z unsigned long time; /* Time that this was entered */
- Z unsigned long children; /* Time spent in called funcs */
- Z};
- Z
- Zstatic struct stack_t fn_stack[STACKSIZ+1];
- Z
- Zstatic unsigned int stacktop = 0; /* Lowest stack position is a dummy */
- Z
- Zstatic unsigned long tot_time = 0;
- Zstatic unsigned long tot_calls = 0;
- Zstatic unsigned long highstack = 0;
- Zstatic unsigned long lowstack = ~0;
- Z
- Z/*
- Z * top() returns a pointer to the top item on the stack.
- Z * (was a function, now a macro)
- Z */
- Z
- Z#define top() &fn_stack[stacktop]
- Z
- Z/*
- Z * Push - Push the given record on the stack.
- Z */
- Z
- Zvoid push (name_pos, time_entered)
- Zregister unsigned int name_pos;
- Zregister unsigned long time_entered;
- Z{
- Z register struct stack_t *t;
- Z
- Z DBUG_ENTER("push");
- Z if (++stacktop > STACKSIZ) {
- Z fprintf (DBUG_FILE,"%s: stack overflow (%s:%d)\n",
- Z my_name, __FILE__, __LINE__);
- Z exit (EX_SOFTWARE);
- Z }
- Z DBUG_PRINT ("push", ("%d %ld",name_pos,time_entered));
- Z t = &fn_stack[stacktop];
- Z t -> pos = name_pos;
- Z t -> time = time_entered;
- Z t -> children = 0;
- Z DBUG_VOID_RETURN;
- Z}
- Z
- Z/*
- Z * Pop - pop the top item off the stack, assigning the field values
- Z * to the arguments. Returns 0 on stack underflow, or on popping first
- Z * item off stack.
- Z */
- Z
- Zunsigned int pop (name_pos, time_entered, child_time)
- Zregister unsigned int *name_pos;
- Zregister unsigned long *time_entered;
- Zregister unsigned long *child_time;
- Z{
- Z register struct stack_t *temp;
- Z register unsigned int rtnval;
- Z
- Z DBUG_ENTER ("pop");
- Z
- Z if (stacktop < 1) {
- Z rtnval = 0;
- Z } else {
- Z temp = &fn_stack[stacktop];
- Z *name_pos = temp->pos;
- Z *time_entered = temp->time;
- Z *child_time = temp->children;
- Z DBUG_PRINT ("pop", ("%d %d %d",*name_pos,*time_entered,*child_time));
- Z rtnval = stacktop--;
- Z }
- Z DBUG_RETURN (rtnval);
- Z}
- Z
- Z/*
- Z * We keep the function info in another array (serves as a simple
- Z * symbol table)
- Z */
- Z
- Zstruct module_t {
- Z char *name;
- Z unsigned long m_time;
- Z unsigned long m_calls;
- Z unsigned long m_stkuse;
- Z};
- Z
- Zstatic struct module_t modules[MAXPROCS];
- Z
- Z/*
- Z * We keep a binary search tree in order to look up function names
- Z * quickly (and sort them at the end.
- Z */
- Z
- Zstruct bnode {
- Z unsigned int lchild; /* Index of left subtree */
- Z unsigned int rchild; /* Index of right subtree */
- Z unsigned int pos; /* Index of module_name entry */
- Z};
- Z
- Zstatic struct bnode s_table[MAXPROCS];
- Z
- Zstatic unsigned int n_items = 0; /* No. of items in the array so far */
- Z
- Z/*
- Z * Need a function to allocate space for a string and squirrel it away.
- Z */
- Z
- Zchar *strsave (s)
- Zchar *s;
- Z{
- Z register char *retval;
- Z register unsigned int len;
- Z extern char *malloc ();
- Z
- Z DBUG_ENTER ("strsave");
- Z DBUG_PRINT ("strsave", ("%s",s));
- Z if (s == Nil (char) || (len = strlen (s)) == 0) {
- Z DBUG_RETURN (Nil (char));
- Z }
- Z MALLOC (retval, ++len, char);
- Z strcpy (retval, s);
- Z DBUG_RETURN (retval);
- Z}
- Z
- Z/*
- Z * add() - adds m_name to the table (if not already there), and returns
- Z * the index of its location in the table. Checks s_table (which is a
- Z * binary search tree) to see whether or not it should be added.
- Z */
- Z
- Zunsigned int add (m_name)
- Zchar *m_name;
- Z{
- Z register unsigned int ind = 0;
- Z register int cmp;
- Z
- Z DBUG_ENTER ("add");
- Z if (n_items == 0) { /* First item to be added */
- Z s_table[0].pos = ind;
- Z s_table[0].lchild = s_table[0].rchild = MAXPROCS;
- Z addit:
- Z modules[n_items].name = strsave (m_name);
- Z modules[n_items].m_time = 0;
- Z modules[n_items].m_calls = 0;
- Z modules[n_items].m_stkuse = 0;
- Z DBUG_RETURN (n_items++);
- Z }
- Z while (cmp = strcmp (m_name,modules[ind].name)) {
- Z if (cmp < 0) { /* In left subtree */
- Z if (s_table[ind].lchild == MAXPROCS) {
- Z /* Add as left child */
- Z if (n_items >= MAXPROCS) {
- Z fprintf (DBUG_FILE,
- Z "%s: Too many functions being profiled\n",
- Z my_name);
- Z exit (EX_SOFTWARE);
- Z }
- Z s_table[n_items].pos = s_table[ind].lchild = n_items;
- Z s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
- Z#ifdef notdef
- Z modules[n_items].name = strsave (m_name);
- Z modules[n_items].m_time = modules[n_items].m_calls = 0;
- Z DBUG_RETURN (n_items++);
- Z#else
- Z goto addit;
- Z#endif
- Z
- Z }
- Z ind = s_table[ind].lchild; /* else traverse l-tree */
- Z } else {
- Z if (s_table[ind].rchild == MAXPROCS) {
- Z /* Add as right child */
- Z if (n_items >= MAXPROCS) {
- Z fprintf (DBUG_FILE,
- Z "%s: Too many functions being profiled\n",
- Z my_name);
- Z exit (EX_SOFTWARE);
- Z }
- Z s_table[n_items].pos = s_table[ind].rchild = n_items;
- Z s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
- Z#ifdef notdef
- Z modules[n_items].name = strsave (m_name);
- Z modules[n_items].m_time = modules[n_items].m_calls = 0;
- Z DBUG_RETURN (n_items++);
- Z#else
- Z goto addit;
- Z#endif
- Z
- Z }
- Z ind = s_table[ind].rchild; /* else traverse r-tree */
- Z }
- Z }
- Z DBUG_RETURN (ind);
- Z}
- Z
- Z/*
- Z * process() - process the input file, filling in the modules table.
- Z */
- Z
- Zvoid process (inf)
- ZFILE *inf;
- Z{
- Z char buf[BUFSIZ];
- Z char fn_name[64]; /* Max length of fn_name */
- Z unsigned long fn_time;
- Z unsigned long fn_sbot;
- Z unsigned long fn_ssz;
- Z unsigned long lastuse;
- Z unsigned int pos;
- Z unsigned long time;
- Z unsigned int oldpos;
- Z unsigned long oldtime;
- Z unsigned long oldchild;
- Z struct stack_t *t;
- Z
- Z DBUG_ENTER ("process");
- Z while (fgets (buf,BUFSIZ,inf) != NULL) {
- Z switch (buf[0]) {
- Z case 'E':
- Z sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
- Z DBUG_PRINT ("erec", ("%ld %s", fn_time, fn_name));
- Z pos = add (fn_name);
- Z push (pos, fn_time);
- Z break;
- Z case 'X':
- Z sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
- Z DBUG_PRINT ("xrec", ("%ld %s", fn_time, fn_name));
- Z pos = add (fn_name);
- Z /*
- Z * An exited function implies that all stacked
- Z * functions are also exited, until the matching
- Z * function is found on the stack.
- Z */
- Z while (pop (&oldpos, &oldtime, &oldchild)) {
- Z DBUG_PRINT ("popped", ("%d %d", oldtime, oldchild));
- Z time = fn_time - oldtime;
- Z t = top ();
- Z t -> children += time;
- Z DBUG_PRINT ("update", ("%s", modules[t -> pos].name));
- Z DBUG_PRINT ("update", ("%d", t -> children));
- Z time -= oldchild;
- Z modules[oldpos].m_time += time;
- Z modules[oldpos].m_calls++;
- Z tot_time += time;
- Z tot_calls++;
- Z if (pos == oldpos) {
- Z goto next_line; /* Should be a break2 */
- Z }
- Z }
- Z /*
- Z * Assume that item seen started at time 0.
- Z * (True for function main). But initialize
- Z * it so that it works the next time too.
- Z */
- Z t = top ();
- Z time = fn_time - t -> time - t -> children;
- Z t -> time = fn_time; t -> children = 0;
- Z modules[pos].m_time += time;
- Z modules[pos].m_calls++;
- Z tot_time += time;
- Z tot_calls++;
- Z break;
- Z case 'S':
- Z sscanf (buf+2, "%lx %lx %64s", &fn_sbot, &fn_ssz, fn_name);
- Z DBUG_PRINT ("srec", ("%lx %lx %s", fn_sbot, fn_ssz, fn_name));
- Z pos = add (fn_name);
- Z lastuse = modules[pos].m_stkuse;
- Z#if 0
- Z /*
- Z * Needs further thought. Stack use is determined by
- Z * difference in stack between two functions with DBUG_ENTER
- Z * macros. If A calls B calls C, where A and C have the
- Z * macros, and B doesn't, then B's stack use will be lumped
- Z * in with either A's or C's. If somewhere else A calls
- Z * C directly, the stack use will seem to change. Just
- Z * take the biggest for now...
- Z */
- Z if (lastuse > 0 && lastuse != fn_ssz) {
- Z fprintf (stderr,
- Z "warning - %s stack use changed (%lx to %lx)\n",
- Z fn_name, lastuse, fn_ssz);
- Z }
- Z#endif
- Z if (fn_ssz > lastuse) {
- Z modules[pos].m_stkuse = fn_ssz;
- Z }
- Z if (fn_sbot > highstack) {
- Z highstack = fn_sbot;
- Z } else if (fn_sbot < lowstack) {
- Z lowstack = fn_sbot;
- Z }
- Z break;
- Z default:
- Z fprintf (stderr, "unknown record type '%s'\n", buf[0]);
- Z break;
- Z }
- Z next_line:;
- Z }
- Z
- Z /*
- Z * Now, we've hit eof. If we still have stuff stacked, then we
- Z * assume that the user called exit, so give everything the exited
- Z * time of fn_time.
- Z */
- Z while (pop (&oldpos,&oldtime,&oldchild)) {
- Z time = fn_time - oldtime;
- Z t = top ();
- Z t -> children += time;
- Z time -= oldchild;
- Z modules[oldpos].m_time += time;
- Z modules[oldpos].m_calls++;
- Z tot_time += time;
- Z tot_calls++;
- Z }
- Z DBUG_VOID_RETURN;
- Z}
- Z
- Z/*
- Z * out_header () -- print out the header of the report.
- Z */
- Z
- Zvoid out_header (outf)
- ZFILE *outf;
- Z{
- Z DBUG_ENTER ("out_header");
- Z if (verbose) {
- Z fprintf (outf, "Profile of Execution\n");
- Z fprintf (outf, "Execution times are in milliseconds\n\n");
- Z fprintf (outf, " Calls\t\t\t Time\n");
- Z fprintf (outf, " -----\t\t\t ----\n");
- Z fprintf (outf, "Times\tPercentage\tTime Spent\tPercentage\n");
- Z fprintf (outf, "Called\tof total\tin Function\tof total Importance\tFunction\n");
- Z fprintf (outf, "======\t==========\t===========\t========== ==========\t========\t\n");
- Z } else {
- Z fprintf (outf, "%ld bytes of stack used, from %lx down to %lx\n\n",
- Z highstack - lowstack, highstack, lowstack);
- Z fprintf (outf,
- Z " %%time sec #call ms/call %%calls weight stack name\n");
- Z }
- Z DBUG_VOID_RETURN;
- Z}
- Z
- Z/*
- Z * out_trailer () - writes out the summary line of the report.
- Z */
- Z
- Zvoid out_trailer (outf,sum_calls,sum_time)
- ZFILE *outf;
- Zunsigned long int sum_calls, sum_time;
- Z{
- Z DBUG_ENTER ("out_trailer");
- Z if (verbose) {
- Z fprintf (outf, "======\t==========\t===========\t==========\t========\n");
- Z fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f\t\t%-15s\n",
- Z sum_calls, 100.0, sum_time, 100.0, "Totals");
- Z }
- Z DBUG_VOID_RETURN;
- Z}
- Z
- Z/*
- Z * out_item () - prints out the output line for a single entry,
- Z * and sets the calls and time fields appropriately.
- Z */
- Z
- Zvoid out_item (outf, m,called,timed)
- ZFILE *outf;
- Zregister struct module_t *m;
- Zunsigned long int *called, *timed;
- Z{
- Z char *name = m -> name;
- Z register unsigned int calls = m -> m_calls;
- Z register unsigned long time = m -> m_time;
- Z register unsigned long stkuse = m -> m_stkuse;
- Z unsigned int import;
- Z double per_time = 0.0;
- Z double per_calls = 0.0;
- Z double ms_per_call, ftime;
- Z
- Z DBUG_ENTER ("out_item");
- Z
- Z if (tot_time > 0) {
- Z per_time = (double) (time * 100) / (double) tot_time;
- Z }
- Z if (tot_calls > 0) {
- Z per_calls = (double) (calls * 100) / (double) tot_calls;
- Z }
- Z import = (unsigned int) (per_time * per_calls);
- Z
- Z if (verbose) {
- Z fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f %10d\t%-15s\n",
- Z calls, per_calls, time, per_time, import, name);
- Z } else {
- Z ms_per_call = time;
- Z ms_per_call /= calls;
- Z ftime = time;
- Z ftime /= 1000;
- Z fprintf (outf, "%8.2f%8.3f%8u%8.3f%8.2f%8u%8u %-s\n",
- Z per_time, ftime, calls, ms_per_call, per_calls, import,
- Z stkuse, name);
- Z }
- Z *called = calls;
- Z *timed = time;
- Z DBUG_VOID_RETURN;
- Z}
- Z
- Z/*
- Z * out_body (outf, root,s_calls,s_time) -- Performs an inorder traversal
- Z * on the binary search tree (root). Calls out_item to actually print
- Z * the item out.
- Z */
- Z
- Zvoid out_body (outf, root,s_calls,s_time)
- ZFILE *outf;
- Zregister unsigned int root;
- Zregister unsigned long int *s_calls, *s_time;
- Z{
- Z unsigned long int calls, time;
- Z
- Z DBUG_ENTER ("out_body");
- Z DBUG_PRINT ("out_body", ("%d,%d",*s_calls,*s_time));
- Z if (root == MAXPROCS) {
- Z DBUG_PRINT ("out_body", ("%d,%d",*s_calls,*s_time));
- Z } else {
- Z while (root != MAXPROCS) {
- Z out_body (outf, s_table[root].lchild,s_calls,s_time);
- Z out_item (outf, &modules[s_table[root].pos],&calls,&time);
- Z DBUG_PRINT ("out_body", ("-- %d -- %d --", calls, time));
- Z *s_calls += calls;
- Z *s_time += time;
- Z root = s_table[root].rchild;
- Z }
- Z DBUG_PRINT ("out_body", ("%d,%d", *s_calls, *s_time));
- Z }
- Z DBUG_VOID_RETURN;
- Z}
- Z
- Z/*
- Z * output () - print out a nice sorted output report on outf.
- Z */
- Z
- Zvoid output (outf)
- ZFILE *outf;
- Z{
- Z unsigned long int sum_calls = 0;
- Z unsigned long int sum_time = 0;
- Z
- Z DBUG_ENTER ("output");
- Z if (n_items == 0) {
- Z fprintf (outf, "%s: No functions to trace\n", my_name);
- Z exit (EX_DATAERR);
- Z }
- Z out_header (outf);
- Z out_body (outf, 0,&sum_calls,&sum_time);
- Z out_trailer (outf, sum_calls,sum_time);
- Z DBUG_VOID_RETURN;
- Z}
- Z
- Z
- Z#define usage() fprintf (DBUG_FILE,"Usage: %s [-v] [prof-file]\n",my_name)
- Z
- Zmain (argc, argv, environ)
- Zint argc;
- Zchar *argv[], *environ[];
- Z{
- Z extern int optind, getopt ();
- Z extern char *optarg;
- Z register int c;
- Z int badflg = 0;
- Z FILE *infile;
- Z FILE *outfile = {stdout};
- Z
- Z DBUG_ENTER ("main");
- Z DBUG_PROCESS (argv[0]);
- Z my_name = argv[0];
- Z while ((c = getopt (argc,argv,"#:v")) != EOF) {
- Z switch (c) {
- Z case '#': /* Debugging Macro enable */
- Z DBUG_PUSH (optarg);
- Z break;
- Z case 'v': /* Verbose mode */
- Z verbose++;
- Z break;
- Z default:
- Z badflg++;
- Z break;
- Z }
- Z }
- Z if (badflg) {
- Z usage ();
- Z DBUG_RETURN (EX_USAGE);
- Z }
- Z if (optind < argc) {
- Z FILEOPEN (infile, argv[optind], "r");
- Z } else {
- Z FILEOPEN (infile, PRO_FILE, "r");
- Z }
- Z process (infile);
- Z output (outfile);
- Z DBUG_RETURN (EX_OK);
- Z}
- STUNKYFLUFF
- set `sum analyze.c`
- if test 37177 != $1
- then
- echo analyze.c: Checksum error. Is: $1, should be: 37177.
- fi
- #
- #
- echo Extracting doinstall.sh:
- sed 's/^Z//' >doinstall.sh <<\STUNKYFLUFF
- Z
- Z# Warning - first line left blank for sh/csh/ksh compatibility. Do not
- Z# remove it. fnf@Unisoft
- Z
- Z# doinstall.sh --- figure out environment and do recursive make with
- Z# appropriate pathnames. Works under SV or BSD.
- Z
- Zif [ -r /usr/include/search.h ]
- Zthen
- Z # System V
- Z $* LLIB=/usr/lib
- Zelse
- Z # 4.2 BSD
- Z $* LLIB=/usr/lib/lint
- Zfi
- STUNKYFLUFF
- set `sum doinstall.sh`
- if test 27205 != $1
- then
- echo doinstall.sh: Checksum error. Is: $1, should be: 27205.
- fi
- #
- #
- echo Extracting example1.c:
- sed 's/^Z//' >example1.c <<\STUNKYFLUFF
- Z#include <stdio.h>
- Z
- Zmain (argc, argv)
- Zint argc;
- Zchar *argv[];
- Z{
- Z printf ("argv[0] = %d\n", argv[0]);
- Z /*
- Z * Rest of program
- Z */
- Z printf ("== done ==\n");
- Z}
- STUNKYFLUFF
- set `sum example1.c`
- if test 12484 != $1
- then
- echo example1.c: Checksum error. Is: $1, should be: 12484.
- fi
- #
- #
- echo Extracting example2.c:
- sed 's/^Z//' >example2.c <<\STUNKYFLUFF
- Z#include <stdio.h>
- Z
- Zint debug = 0;
- Z
- Zmain (argc, argv)
- Zint argc;
- Zchar *argv[];
- Z{
- Z /* printf ("argv = %x\n", argv) */
- Z if (debug) printf ("argv[0] = %d\n", argv[0]);
- Z /*
- Z * Rest of program
- Z */
- Z#ifdef DEBUG
- Z printf ("== done ==\n");
- Z#endif
- Z}
- STUNKYFLUFF
- set `sum example2.c`
- if test 18642 != $1
- then
- echo example2.c: Checksum error. Is: $1, should be: 18642.
- fi
- #
- #
- echo Extracting example3.c:
- sed 's/^Z//' >example3.c <<\STUNKYFLUFF
- Z#include <stdio.h>
- Z
- Zmain (argc, argv)
- Zint argc;
- Zchar *argv[];
- Z{
- Z# ifdef DEBUG
- Z printf ("argv[0] = %d\n", argv[0]);
- Z# endif
- Z /*
- Z * Rest of program
- Z */
- Z# ifdef DEBUG
- Z printf ("== done ==\n");
- Z# endif
- Z}
- STUNKYFLUFF
- set `sum example3.c`
- if test 15886 != $1
- then
- echo example3.c: Checksum error. Is: $1, should be: 15886.
- fi
- #
- #
- echo Extracting factorial.c:
- sed 's/^Z//' >factorial.c <<\STUNKYFLUFF
- Z#include <stdio.h>
- Z/* User programs should use <local/dbug.h> */
- Z#include "dbug.h"
- Z
- Zint factorial (value)
- Zregister int value;
- Z{
- Z DBUG_ENTER ("factorial");
- Z DBUG_PRINT ("find", ("find %d factorial", value));
- Z if (value > 1) {
- Z value *= factorial (value - 1);
- Z }
- Z DBUG_PRINT ("result", ("result is %d", value));
- Z DBUG_RETURN (value);
- Z}
- STUNKYFLUFF
- set `sum factorial.c`
- if test 27082 != $1
- then
- echo factorial.c: Checksum error. Is: $1, should be: 27082.
- fi
- #
- #
- echo Extracting install.sh:
- sed 's/^Z//' >install.sh <<\STUNKYFLUFF
- Z
- Z# WARNING -- first line intentionally left blank for sh/csh/ksh
- Z# compatibility. Do not remove it! FNF, UniSoft Systems.
- Z#
- Z# Usage is:
- Z# install <from> <to>
- Z#
- Z# The file <to> is replaced with the file <from>, after first
- Z# moving <to> to a backup file. The backup file name is created
- Z# by prepending the filename (after removing any leading pathname
- Z# components) with "OLD".
- Z#
- Z# This script is currently not real robust in the face of signals
- Z# or permission problems. It also does not do (by intention) all
- Z# the things that the System V or BSD install scripts try to do
- Z#
- Z
- Zif [ $# -ne 2 ]
- Zthen
- Z echo "usage: $0 <from> <to>"
- Z exit 1
- Zfi
- Z
- Z# Now extract the dirname and basename components. Unfortunately, BSD does
- Z# not have dirname, so we do it the hard way.
- Z
- Zfd=`expr $1'/' : '\(/\)[^/]*/$' \| $1'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
- Zff=`basename $1`
- Ztd=`expr $2'/' : '\(/\)[^/]*/$' \| $2'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
- Ztf=`basename $2`
- Z
- Z# Now test to make sure that they are not the same files.
- Z
- Zif [ $fd/$ff = $td/$tf ]
- Zthen
- Z echo "install: input and output are same files"
- Z exit 2
- Zfi
- Z
- Z# Save a copy of the "to" file as a backup.
- Z
- Zif test -f $td/$tf
- Zthen
- Z if test -f $td/OLD$tf
- Z then
- Z rm -f $td/OLD$tf
- Z fi
- Z mv $td/$tf $td/OLD$tf
- Z if [ $? != 0 ]
- Z then
- Z exit 3
- Z fi
- Zfi
- Z
- Z# Now do the copy and return appropriate status
- Z
- Zcp $fd/$ff $td/$tf
- Zif [ $? != 0 ]
- Zthen
- Z exit 4
- Zelse
- Z exit 0
- Zfi
- Z
- STUNKYFLUFF
- set `sum install.sh`
- if test 46271 != $1
- then
- echo install.sh: Checksum error. Is: $1, should be: 46271.
- fi
- #
- #
- echo Extracting llib-ldbug:
- sed 's/^Z//' >llib-ldbug <<\STUNKYFLUFF
- Z/*
- Z ******************************************************************************
- Z * *
- Z * N O T I C E *
- Z * *
- Z * Copyright Abandoned, 1987, Fred Fish *
- Z * *
- Z * *
- Z * This previously copyrighted work has been placed into the public *
- Z * domain by the author and may be freely used for any purpose, *
- Z * private or commercial. *
- Z * *
- Z * Because of the number of inquiries I was receiving about the use *
- Z * of this product in commercially developed works I have decided to *
- Z * simply make it public domain to further its unrestricted use. I *
- Z * specifically would be most happy to see this material become a *
- Z * part of the standard Unix distributions by AT&T and the Berkeley *
- Z * Computer Science Research Group, and a standard part of the GNU *
- Z * system from the Free Software Foundation. *
- Z * *
- Z * I would appreciate it, as a courtesy, if this notice is left in *
- Z * all copies and derivative works. Thank you. *
- Z * *
- Z * The author makes no warranty of any kind with respect to this *
- Z * product and explicitly disclaims any implied warranties of mer- *
- Z * chantability or fitness for any particular purpose. *
- Z * *
- Z ******************************************************************************
- Z */
- Z
- Z
- Z/*
- Z * FILE
- Z *
- Z * llib-ldbug lint library source for debugging package
- Z *
- Z * SCCS ID
- Z *
- Z * @(#)llib-ldbug 1.9 6/12/89
- Z *
- Z * DESCRIPTION
- Z *
- Z * Function definitions for use in building lint library.
- Z * Note that these must stay in syncronization with actual
- Z * declarations in "dbug.c".
- Z *
- Z */
- Z
- Z
- Z/*LINTLIBRARY*/
- Z
- Z#include <stdio.h>
- Z
- Z#define VOID void
- Ztypedef int BOOLEAN;
- Z#define FALSE 0
- Z#define ARGLIST a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15
- Z
- Zint _db_on_ = FALSE;
- Zint _db_pon_ = FALSE;
- ZFILE *_db_fp_ = stderr;
- ZFILE *_db_pfp_ = stderr;
- Zchar *_db_process_ = "dbug";
- Z
- ZVOID _db_push_ (control)
- Zchar *control;
- Z{
- Z}
- Z
- ZVOID _db_pop_ ()
- Z{
- Z}
- Z
- ZVOID _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_, _sframep_)
- Zchar *_func_;
- Zchar *_file_;
- Zint _line_;
- Zchar **_sfunc_;
- Zchar **_sfile_;
- Zint *_slevel_;
- Zchar ***_sframep_;
- Z{
- Z}
- Z
- ZVOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
- Zint _line_;
- Zchar **_sfunc_;
- Zchar **_sfile_;
- Zint *_slevel_;
- Z{
- Z}
- Z
- ZVOID _db_pargs_ (_line_, keyword)
- Zint _line_;
- Zchar *keyword;
- Z{
- Z}
- Z
- Z/*VARARGS1*/
- ZVOID _db_doprnt_ (format, ARGLIST)
- Zchar *format;
- Zlong ARGLIST;
- Z{
- Z}
- Z
- Z/* WARNING -- the following function is obsolete and may not be supported */
- Z/* in future releases... */
- Z
- Z/*VARARGS3*/
- ZVOID _db_printf_ (_line_, keyword, format, ARGLIST)
- Zint _line_;
- Zchar *keyword, *format;
- Zlong ARGLIST;
- Z{
- Z}
- Z
- ZBOOLEAN _db_keyword_ (keyword)
- Zchar *keyword;
- Z{
- Z return (0);
- Z}
- Z
- ZVOID _db_longjmp_ ()
- Z{
- Z}
- Z
- ZVOID _db_setjmp_ ()
- Z{
- Z}
- STUNKYFLUFF
- set `sum llib-ldbug`
- if test 20072 != $1
- then
- echo llib-ldbug: Checksum error. Is: $1, should be: 20072.
- fi
- #
- #
- echo Extracting main.c:
- sed 's/^Z//' >main.c <<\STUNKYFLUFF
- Z#include <stdio.h>
- Z/* User programs should use <local/dbug.h> */
- Z#include "dbug.h"
- Z
- Zmain (argc, argv)
- Zint argc;
- Zchar *argv[];
- Z{
- Z register int result, ix;
- Z extern int factorial (), atoi ();
- Z
- Z DBUG_ENTER ("main");
- Z DBUG_PROCESS (argv[0]);
- Z for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
- Z switch (argv[ix][1]) {
- Z case '#':
- Z DBUG_PUSH (&(argv[ix][2]));
- Z break;
- Z }
- Z }
- Z for (; ix < argc; ix++) {
- Z DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
- Z result = factorial (atoi (argv[ix]));
- Z printf ("%d\n", result);
- Z }
- Z DBUG_RETURN (0);
- Z}
- STUNKYFLUFF
- set `sum main.c`
- if test 42153 != $1
- then
- echo main.c: Checksum error. Is: $1, should be: 42153.
- fi
- #
- #
- echo Extracting mklintlib.sh:
- sed 's/^Z//' >mklintlib.sh <<\STUNKYFLUFF
- Z
- Z# Warning - first line left blank for sh/csh/ksh compatibility. Do not
- Z# remove it. fnf@Unisoft
- Z
- Z# mklintlib --- make a lint library, under either System V or 4.2 BSD
- Z#
- Z# usage: mklintlib <infile> <outfile>
- Z#
- Z
- Zif test $# -ne 2
- Zthen
- Z echo "usage: mklintlib <infile> <outfile>"
- Z exit 1
- Zfi
- Z
- Zif grep SIGTSTP /usr/include/signal.h >/dev/null
- Zthen # BSD
- Z if test -r /usr/include/whoami.h # 4.1
- Z then
- Z /lib/cpp -C -Dlint $1 >hlint
- Z (/usr/lib/lint/lint1 <hlint >$2) 2>&1 | grep -v warning
- Z else # 4.2
- Z lint -Cxxxx $1
- Z mv llib-lxxxx.ln $2
- Z fi
- Zelse # USG
- Z cc -E -C -Dlint $1 | /usr/lib/lint1 -vx -Hhlint >$2
- Z rm -f hlint
- Zfi
- Zexit 0 # don't kill make
- STUNKYFLUFF
- set `sum mklintlib.sh`
- if test 51376 != $1
- then
- echo mklintlib.sh: Checksum error. Is: $1, should be: 51376.
- fi
- #
- #
- echo Extracting ranlib.sh:
- sed 's/^Z//' >ranlib.sh <<\STUNKYFLUFF
- Z
- Z# Warning - first line left blank for sh/csh/ksh compatibility. Do not
- Z# remove it. fnf@Unisoft
- Z
- Z# ranlib --- do a ranlib if necessary
- Z
- Zif [ -x /usr/bin/ranlib ]
- Zthen
- Z /usr/bin/ranlib $*
- Zelif [ -x /bin/ranlib ]
- Zthen
- Z /bin/ranlib $*
- Zelse
- Z :
- Zfi
- STUNKYFLUFF
- set `sum ranlib.sh`
- if test 20181 != $1
- then
- echo ranlib.sh: Checksum error. Is: $1, should be: 20181.
- fi
- #
- #
- echo Extracting useful.h:
- sed 's/^Z//' >useful.h <<\STUNKYFLUFF
- Z/*
- Z * Copyright June 1987, Binayak Banerjee
- Z * All rights reserved.
- Z *
- Z * This program may be freely distributed under the same terms and
- Z * conditions as Fred Fish's Dbug package.
- Z *
- Z * Useful macros which I use a lot.
- Z *
- Z * Conditionally include some useful files.
- Z */
- Z
- Z# ifndef EOF
- Z# include <stdio.h>
- Z# endif
- Z
- Z/*
- Z * For BSD systems, you can include <sysexits.h> for more detailed
- Z * exit information. For non-BSD systems (which also includes
- Z * non-unix systems) just map everything to "failure" = 1 and
- Z * "success" = 0. -Fred Fish 9-Sep-87
- Z */
- Z
- Z# ifdef BSD
- Z# include <sysexits.h>
- Z# else
- Z# define EX_SOFTWARE 1
- Z# define EX_DATAERR 1
- Z# define EX_USAGE 1
- Z# define EX_OSERR 1
- Z# define EX_IOERR 1
- Z# define EX_OK 0
- Z# endif
- Z
- Z
- Z/*
- Z * Fred Fish's debugging stuff. Define DBUG_OFF in order to disable if
- Z * you don't have these.
- Z */
- Z
- Z# ifndef DBUG_OFF
- Z# include "dbug.h" /* Use local version */
- Z# else
- Z# define DBUG_ENTER(a1)
- Z# define DBUG_RETURN(a1) return(a1)
- Z# define DBUG_VOID_RETURN return
- Z# define DBUG_EXECUTE(keyword,a1)
- Z# define DBUG_2(keyword,format)
- Z# define DBUG_3(keyword,format,a1)
- Z# define DBUG_4(keyword,format,a1,a2)
- Z# define DBUG_5(keyword,format,a1,a2,a3)
- Z# define DBUG_PUSH(a1)
- Z# define DBUG_POP()
- Z# define DBUG_PROCESS(a1)
- Z# define DBUG_PRINT(x,y)
- Z# define DBUG_FILE (stderr)
- Z# endif
- Z
- Z#define __MERF_OO_ "%s: Malloc Failed in %s: %d\n"
- Z
- Z#define Nil(Typ) ((Typ *) 0) /* Make Lint happy */
- Z
- Z#define MALLOC(Ptr,Num,Typ) do /* Malloc w/error checking & exit */ \
- Z if ((Ptr = (Typ *)malloc((Num)*(sizeof(Typ)))) == Nil(Typ)) \
- Z {fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
- Z exit(EX_OSERR);} while(0)
- Z
- Z#define Malloc(Ptr,Num,Typ) do /* Weaker version of above */\
- Z if ((Ptr = (Typ *)malloc((Num)*(sizeof(Typ)))) == Nil(Typ)) \
- Z fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
- Z while(0)
- Z
- Z#define FILEOPEN(Fp,Fn,Mod) do /* File open with error exit */ \
- Z if((Fp = fopen(Fn,Mod)) == Nil(FILE))\
- Z {fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
- Z exit(EX_IOERR);} while(0)
- Z
- Z#define Fileopen(Fp,Fn,Mod) do /* Weaker version of above */ \
- Z if((Fp = fopen(Fn,Mod)) == Nil(FILE)) \
- Z fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
- Z while(0)
- Z
- Z
- Zextern char *my_name; /* The name that this was called as */
- STUNKYFLUFF
- set `sum useful.h`
- if test 45206 != $1
- then
- echo useful.h: Checksum error. Is: $1, should be: 45206.
- fi
- #
- #
- echo Extracting user.r:
- sed 's/^Z//' >user.r <<\STUNKYFLUFF
- Z.\" @(#)user.r 1.16 8/7/88
- Z.\"
- Z.\" DBUG (Macro Debugger Package) nroff source
- Z.\"
- Z.\" nroff -mm user.r >user.t
- Z.\"
- Z.\" ===================================================
- Z.\"
- Z.\" === Some sort of black magic, but I forget...
- Z.tr ~
- Z.\" === Hyphenation control (1 = on)
- Z.\".nr Hy 1
- Z.\" === Force all first level headings to start on new page
- Z.nr Ej 1
- Z.\" === Set for breaks after headings for levels 1-3
- Z.nr Hb 3
- Z.\" === Set for space after headings for levels 1-3
- Z.nr Hs 3
- Z.\" === Set standard indent for one/half inch
- Z.nr Si 10
- Z.\" === Set page header
- Z.PH "/DBUG User Manual//\*(DT/"
- Z.\" === Set page footer
- Z.PF "// - % - //"
- Z.\" === Set page offset
- Z.\".po 0.60i
- Z.\" === Set line length
- Z.\".ll 6.5i
- Z.TL
- ZD B U G
- Z.P 0
- ZC Program Debugging Package
- Z.P 0
- Zby
- Z.AU "Fred Fish"
- Z.AF ""
- Z.SA 1
- Z.\" === All paragraphs indented.
- Z.nr Pt 1
- Z.AS 1
- ZThis document introduces
- Z.I dbug ,
- Za macro based C debugging
- Zpackage which has proven to be a very flexible and useful tool
- Zfor debugging, testing, and porting C programs.
- Z
- Z.P
- ZAll of the features of the
- Z.I dbug
- Zpackage can be enabled or disabled dynamically at execution time.
- ZThis means that production programs will run normally when
- Zdebugging is not enabled, and eliminates the need to maintain two
- Zseparate versions of a program.
- Z
- Z.P
- ZMany of the things easily accomplished with conventional debugging
- Ztools, such as symbolic debuggers, are difficult or impossible with this
- Zpackage, and vice versa.
- ZThus the
- Z.I dbug
- Zpackage should
- Z.I not
- Zbe thought of as a replacement or substitute for
- Zother debugging tools, but simply as a useful
- Z.I addition
- Zto the
- Zprogram development and maintenance environment.
- Z
- Z.AE
- Z.MT 4
- Z.SK
- Z.B
- ZINTRODUCTION
- Z.R
- Z
- Z.P
- ZAlmost every program development environment worthy of the name
- Zprovides some sort of debugging facility.
- ZUsually this takes the form of a program which is capable of
- Zcontrolling execution of other programs and examining the internal
- Zstate of other executing programs.
- ZThese types of programs will be referred to as external debuggers
- Zsince the debugger is not part of the executing program.
- ZExamples of this type of debugger include the
- Z.B adb
- Zand
- Z.B sdb
- Zdebuggers provided with the
- Z.B UNIX\*F
- Z.FS
- ZUNIX is a trademark of AT&T Bell Laboratories.
- Z.FE
- Zoperating system.
- Z
- Z.P
- ZOne of the problems associated with developing programs in an environment
- Zwith good external debuggers is that developed programs tend to have
- Zlittle or no internal instrumentation.
- ZThis is usually not a problem for the developer since he is,
- Zor at least should be, intimately familiar with the internal organization,
- Zdata structures, and control flow of the program being debugged.
- ZIt is a serious problem for maintenance programmers, who
- Zare unlikely to have such familiarity with the program being
- Zmaintained, modified, or ported to another environment.
- ZIt is also a problem, even for the developer, when the program is
- Zmoved to an environment with a primitive or unfamiliar debugger,
- Zor even no debugger.
- Z
- Z.P
- ZOn the other hand,
- Z.I dbug
- Zis an example of an internal debugger.
- ZBecause it requires internal instrumentation of a program,
- Zand its usage does not depend on any special capabilities of
- Zthe execution environment, it is always available and will
- Zexecute in any environment that the program itself will
- Zexecute in.
- ZIn addition, since it is a complete package with a specific
- Zuser interface, all programs which use it will be provided
- Zwith similar debugging capabilities.
- ZThis is in sharp contrast to other forms of internal instrumentation
- Zwhere each developer has their own, usually less capable, form
- Zof internal debugger.
- ZIn summary,
- Zbecause
- Z.I dbug
- Zis an internal debugger it provides consistency across operating
- Zenvironments,
- Zand because it is available to all developers it provides
- Zconsistency across all programs in the same environment.
- Z
- Z.P
- ZThe
- Z.I dbug
- Zpackage imposes only a slight speed penalty on executing
- Zprograms, typically much less than 10 percent, and a modest size
- Zpenalty, typically 10 to 20 percent.
- ZBy defining a specific C preprocessor symbol both of these
- Zcan be reduced to zero with no changes required to the
- Zsource code.
- Z
- Z.P
- ZThe following list is a quick summary of the capabilities
- Zof the
- Z.I dbug
- Zpackage.
- ZEach capability can be individually enabled or disabled
- Zat the time a program is invoked by specifying the appropriate
- Zcommand line arguments.
- Z.SP 1
- Z.ML o 1i
- Z.LI
- ZExecution trace showing function level control flow in a
- Zsemi-graphically manner using indentation to indicate nesting
- Zdepth.
- Z.LI
- ZOutput the values of all, or any subset of, key internal variables.
- Z.LI
- ZLimit actions to a specific set of named functions.
- Z.LI
- ZLimit function trace to a specified nesting depth.
- Z.LI
- ZLabel each output line with source file name and line number.
- Z.LI
- ZLabel each output line with name of current process.
- Z.LI
- ZPush or pop internal debugging state to allow execution with
- Zbuilt in debugging defaults.
- Z.LI
- ZRedirect the debug output stream to standard output (stdout)
- Zor a named file.
- ZThe default output stream is standard error (stderr).
- ZThe redirection mechanism is completely independent of
- Znormal command line redirection to avoid output conflicts.
- Z.LE
- Z
- Z.SK
- Z.B
- ZPRIMITIVE DEBUGGING TECHNIQUES
- Z.R
- Z
- Z.P
- ZInternal instrumentation is already a familiar concept
- Zto most programmers, since it is usually the first debugging
- Ztechnique learned.
- ZTypically, "print\ statements" are inserted in the source
- Zcode at interesting points, the code is recompiled and executed,
- Zand the resulting output is examined in an attempt to determine
- Zwhere the problem is.
- Z
- ZThe procedure is iterative, with each iteration yielding more
- Zand more output, and hopefully the source of the problem is
- Zdiscovered before the output becomes too large to deal with
- Zor previously inserted statements need to be removed.
- ZFigure 1 is an example of this type of primitive debugging
- Ztechnique.
- Z.DS I N
- Z.SP 2
- Z.so example1.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 1
- Z.ce
- ZPrimitive Debugging Technique
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZEventually, and usually after at least several iterations, the
- Zproblem will be found and corrected.
- ZAt this point, the newly inserted print statements must be
- Zdealt with.
- ZOne obvious solution is to simply delete them all.
- ZBeginners usually do this a few times until they have to
- Zrepeat the entire process every time a new bug pops up.
- ZThe second most obvious solution is to somehow disable
- Zthe output, either through the source code comment facility,
- Zcreation of a debug variable to be switched on or off, or by using the
- ZC preprocessor.
- ZFigure 2 is an example of all three techniques.
- Z.DS I N
- Z.SP 2
- Z.so example2.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 2
- Z.ce
- ZDebug Disable Techniques
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZEach technique has its advantages and disadvantages with respect
- Zto dynamic vs static activation, source code overhead, recompilation
- Zrequirements, ease of use, program readability, etc.
- ZOveruse of the preprocessor solution quickly leads to problems with
- Zsource code readability and maintainability when multiple
- Z.B #ifdef
- Zsymbols are to be defined or undefined based on specific types
- Zof debug desired.
- ZThe source code can be made slightly more readable by suitable indentation
- Zof the
- Z.B #ifdef
- Zarguments to match the indentation of the code, but
- Znot all C preprocessors allow this.
- ZThe only requirement for the standard
- Z.B UNIX
- ZC preprocessor is for the '#' character to appear
- Zin the first column, but even this seems
- Zlike an arbitrary and unreasonable restriction.
- ZFigure 3 is an example of this usage.
- Z.DS I N
- Z.SP 2
- Z.so example3.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 3
- Z.ce
- ZMore Readable Preprocessor Usage
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.SK
- Z.B
- ZFUNCTION TRACE EXAMPLE
- Z.R
- Z
- Z.P
- ZWe will start off learning about the capabilities of the
- Z.I dbug
- Zpackage by using a simple minded program which computes the
- Zfactorial of a number.
- ZIn order to better demonstrate the function trace mechanism, this
- Zprogram is implemented recursively.
- ZFigure 4 is the main function for this factorial program.
- Z.DS I N
- Z.SP 2
- Z.so main.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 4
- Z.ce
- ZFactorial Program Mainline
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZThe
- Z.B main
- Zfunction is responsible for processing any command line
- Zoption arguments and then computing and printing the factorial of
- Zeach non-option argument.
- Z.P
- ZFirst of all, notice that all of the debugger functions are implemented
- Zvia preprocessor macros.
- ZThis does not detract from the readability of the code and makes disabling
- Zall debug compilation trivial (a single preprocessor symbol,
- Z.B DBUG_OFF ,
- Zforces the macro expansions to be null).
- Z.P
- ZAlso notice the inclusion of the header file
- Z.B dbug.h
- Zfrom the local header file directory.
- Z(The version included here is the test version in the dbug source
- Zdistribution directory).
- ZThis file contains all the definitions for the debugger macros, which
- Zall have the form
- Z.B DBUG_XX...XX .
- Z
- Z.P
- ZThe
- Z.B DBUG_ENTER
- Zmacro informs that debugger that we have entered the
- Zfunction named
- Z.B main .
- ZIt must be the very first "executable" line in a function, after
- Zall declarations and before any other executable line.
- ZThe
- Z.B DBUG_PROCESS
- Zmacro is generally used only once per program to
- Zinform the debugger what name the program was invoked with.
- ZThe
- Z.B DBUG_PUSH
- Zmacro modifies the current debugger state by
- Zsaving the previous state and setting a new state based on the
- Zcontrol string passed as its argument.
- ZThe
- Z.B DBUG_PRINT
- Zmacro is used to print the values of each argument
- Zfor which a factorial is to be computed.
- ZThe
- Z.B DBUG_RETURN
- Zmacro tells the debugger that the end of the current
- Zfunction has been reached and returns a value to the calling
- Zfunction.
- ZAll of these macros will be fully explained in subsequent sections.
- Z.P
- ZTo use the debugger, the factorial program is invoked with a command
- Zline of the form:
- Z.DS CB N
- Zfactorial -#d:t 1 2 3
- Z.DE
- ZThe
- Z.B main
- Zfunction recognizes the "-#d:t" string as a debugger control
- Zstring, and passes the debugger arguments ("d:t") to the
- Z.I dbug
- Zruntime support routines via the
- Z.B DBUG_PUSH
- Zmacro.
- ZThis particular string enables output from the
- Z.B DBUG_PRINT
- Zmacro with the 'd' flag and enables function tracing with the 't' flag.
- ZThe factorial function is then called three times, with the arguments
- Z"1", "2", and "3".
- ZNote that the DBUG_PRINT takes exactly
- Z.B two
- Zarguments, with the second argument (a format string and list
- Zof printable values) enclosed in parenthesis.
- Z.P
- ZDebug control strings consist of a header, the "-#", followed
- Zby a colon separated list of debugger arguments.
- ZEach debugger argument is a single character flag followed
- Zby an optional comma separated list of arguments specific
- Zto the given flag.
- ZSome examples are:
- Z.DS CB N
- Z-#d:t:o
- Z-#d,in,out:f,main:F:L
- Z.DE
- ZNote that previously enabled debugger actions can be disabled by the
- Zcontrol string "-#".
- Z
- Z.P
- ZThe definition of the factorial function, symbolized as "N!", is
- Zgiven by:
- Z.DS CB N
- ZN! = N * N-1 * ... 2 * 1
- Z.DE
- ZFigure 5 is the factorial function which implements this algorithm
- Zrecursively.
- ZNote that this is not necessarily the best way to do factorials
- Zand error conditions are ignored completely.
- Z.DS I N
- Z.SP 2
- Z.so factorial.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 5
- Z.ce
- ZFactorial Function
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZOne advantage (some may not consider it so) to using the
- Z.I dbug
- Zpackage is that it strongly encourages fully structured coding
- Zwith only one entry and one exit point in each function.
- ZMultiple exit points, such as early returns to escape a loop,
- Zmay be used, but each such point requires the use of an
- Zappropriate
- Z.B DBUG_RETURN
- Zor
- Z.B DBUG_VOID_RETURN
- Zmacro.
- Z
- Z.P
- ZTo build the factorial program on a
- Z.B UNIX
- Zsystem, compile and
- Zlink with the command:
- Z.DS CB N
- Zcc -o factorial main.c factorial.c -ldbug
- Z.DE
- ZThe "-ldbug" argument tells the loader to link in the
- Zruntime support modules for the
- Z.I dbug
- Zpackage.
- ZExecuting the factorial program with a command of the form:
- Z.DS CB N
- Zfactorial 1 2 3 4 5
- Z.DE
- Zgenerates the output shown in figure 6.
- Z.DS I N
- Z.SP 2
- Z.so output1.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 6
- Z.ce
- Zfactorial 1 2 3 4 5
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZFunction level tracing is enabled by passing the debugger
- Zthe 't' flag in the debug control string.
- ZFigure 7 is the output resulting from the command
- Z"factorial\ -#t:o\ 3\ 2".
- Z.DS I N
- Z.SP 2
- Z.so output2.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 7
- Z.ce
- Zfactorial -#t:o 3 2
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZEach entry to or return from a function is indicated by '>' for the
- Zentry point and '<' for the exit point, connected by
- Zvertical bars to allow matching points to be easily found
- Zwhen separated by large distances.
- Z
- Z.P
- ZThis trace output indicates that there was an initial call
- Zto factorial from main (to compute 2!), followed by
- Za single recursive call to factorial to compute 1!.
- ZThe main program then output the result for 2! and called the
- Zfactorial function again with the second argument, 3.
- ZFactorial called itself recursively to compute 2! and 1!, then
- Zreturned control to main, which output the value for 3! and exited.
- Z
- Z.P
- ZNote that there is no matching entry point "main>" for the
- Zreturn point "<main" because at the time the
- Z.B DBUG_ENTER
- Zmacro was reached in main, tracing was not enabled yet.
- ZIt was only after the macro
- Z.B DBUG_PUSH
- Zwas executing that tracing became enabled.
- ZThis implies that the argument list should be processed as early as
- Zpossible since all code preceding the first call to
- Z.B DBUG_PUSH
- Zis
- Zessentially invisible to
- Z.B dbug
- Z(this can be worked around by
- Zinserting a temporary
- Z.B DBUG_PUSH(argv[1])
- Zimmediately after the
- Z.B DBUG_ENTER("main")
- Zmacro.
- Z
- Z.P
- ZOne last note,
- Zthe trace output normally comes out on the standard error.
- ZSince the factorial program prints its result on the standard
- Zoutput, there is the possibility of the output on the terminal
- Zbeing scrambled if the two streams are not synchronized.
- ZThus the debugger is told to write its output on the standard
- Zoutput instead, via the 'o' flag character.
- ZNote that no 'o' implies the default (standard error), a 'o'
- Zwith no arguments means standard output, and a 'o'
- Zwith an argument means used the named file.
- ZI.E, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
- Zoutput in "logfile".
- ZBecause of
- Z.B UNIX
- Zimplementation details, programs usually run
- Zfaster when writing to stdout rather than stderr, though this
- Zis not a prime consideration in this example.
- Z
- Z.SK
- Z.B
- ZUSE OF DBUG_PRINT MACRO
- Z.R
- Z
- Z.P
- ZThe mechanism used to produce "printf" style output is the
- Z.B DBUG_PRINT
- Zmacro.
- Z
- Z.P
- ZTo allow selection of output from specific macros, the first argument
- Zto every
- Z.B DBUG_PRINT
- Zmacro is a
- Z.I dbug
- Zkeyword.
- ZWhen this keyword appears in the argument list of the 'd' flag in
- Za debug control string, as in "-#d,keyword1,keyword2,...:t",
- Zoutput from the corresponding macro is enabled.
- ZThe default when there is no 'd' flag in the control string is to
- Zenable output from all
- Z.B DBUG_PRINT
- Zmacros.
- Z
- Z.P
- ZTypically, a program will be run once, with no keywords specified,
- Zto determine what keywords are significant for the current problem
- Z(the keywords are printed in the macro output line).
- ZThen the program will be run again, with the desired keywords,
- Zto examine only specific areas of interest.
- Z
- Z.P
- ZThe second argument to a
- Z.B DBUG_PRINT
- Zmacro is a standard printf style
- Zformat string and one or more arguments to print, all
- Zenclosed in parenthesis so that they collectively become a single macro
- Zargument.
- ZThis is how variable numbers of printf arguments are supported.
- ZAlso note that no explicit newline is required at the end of the format string.
- ZAs a matter of style, two or three small
- Z.B DBUG_PRINT
- Zmacros are preferable
- Zto a single macro with a huge format string.
- ZFigure 8 shows the output for default tracing and debug.
- Z.DS I N
- Z.SP 2
- Z.so output3.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 8
- Z.ce
- Zfactorial -#d:t:o 3
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZThe output from the
- Z.B DBUG_PRINT
- Zmacro is indented to match the trace output
- Zfor the function in which the macro occurs.
- ZWhen debugging is enabled, but not trace, the output starts at the left
- Zmargin, without indentation.
- Z
- Z.P
- ZTo demonstrate selection of specific macros for output, figure
- Z9 shows the result when the factorial program is invoked with
- Zthe debug control string "-#d,result:o".
- Z.DS I N
- Z.SP 2
- Z.so output4.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 9
- Z.ce
- Zfactorial -#d,result:o 4
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZIt is sometimes desirable to restrict debugging and trace actions
- Zto a specific function or list of functions.
- ZThis is accomplished with the 'f' flag character in the debug
- Zcontrol string.
- ZFigure 10 is the output of the factorial program when run with the
- Zcontrol string "-#d:f,factorial:F:L:o".
- ZThe 'F' flag enables printing of the source file name and the 'L'
- Zflag enables printing of the source file line number.
- Z.DS I N
- Z.SP 2
- Z.so output5.r
- Z.SP 2
- Z.ll -5
- Z.ce
- ZFigure 10
- Z.ce
- Zfactorial -#d:f,factorial:F:L:o 3
- Z.ll +5
- Z.SP 2
- Z.DE
- Z
- Z.P
- ZThe output in figure 10 shows that the "find" macro is in file
- Z"factorial.c" at source line 8 and the "result" macro is in the same
- Zfile at source line 12.
- Z
- Z.SK
- Z.B
- ZSUMMARY OF MACROS
- Z.R
- Z
- Z.P
- ZThis section summarizes the usage of all currently defined macros
- Zin the
- Z.I dbug
- Zpackage.
- ZThe macros definitions are found in the user include file
- Z.B dbug.h
- Zfrom the standard include directory.
- Z
- Z.SP 2
- Z.BL 20
- Z.LI DBUG_ENTER\
- ZUsed to tell the runtime support module the name of the function
- Zbeing entered.
- ZThe argument must be of type "pointer to character".
- ZThe
- ZDBUG_ENTER
- Zmacro must precede all executable lines in the
- Zfunction just entered, and must come after all local declarations.
- ZEach
- ZDBUG_ENTER
- Zmacro must have a matching
- ZDBUG_RETURN
- Zor
- ZDBUG_VOID_RETURN
- Zmacro
- Zat the function exit points.
- ZDBUG_ENTER
- Zmacros used without a matching
- ZDBUG_RETURN
- Zor
- ZDBUG_VOID_RETURN
- Zmacro
- Zwill cause warning messages from the
- Z.I dbug
- Zpackage runtime support module.
- Z.SP 1
- ZEX:\ DBUG_ENTER\ ("main");
- Z.SP 1
- Z.LI DBUG_RETURN\
- ZUsed at each exit point of a function containing a
- ZDBUG_ENTER
- Zmacro
- Zat the entry point.
- ZThe argument is the value to return.
- ZFunctions which return no value (void) should use the
- ZDBUG_VOID_RETURN
- Zmacro.
- ZIt
- Zis an error to have a
- ZDBUG_RETURN
- Zor
- ZDBUG_VOID_RETURN
- Zmacro in a function
- Zwhich has no matching
- ZDBUG_ENTER
- Zmacro, and the compiler will complain
- Zif the macros are actually used (expanded).
- Z.SP 1
- ZEX:\ DBUG_RETURN\ (value);
- Z.br
- ZEX:\ DBUG_VOID_RETURN;
- Z.SP 1
- Z.LI DBUG_PROCESS\
- ZUsed to name the current process being executed.
- ZA typical argument for this macro is "argv[0]", though
- Zit will be perfectly happy with any other string.
- Z.SP 1
- ZEX:\ DBUG_PROCESS\ (argv[0]);
- Z.SP 1
- Z.LI DBUG_PUSH\
- ZSets a new debugger state by pushing the current
- Z.B dbug
- Zstate onto an
- Zinternal stack and setting up the new state using the debug control
- Zstring passed as the macro argument.
- ZThe most common usage is to set the state specified by a debug
- Zcontrol string retrieved from the argument list.
- ZNote that the leading "-#" in a debug control string specified
- Zas a command line argument must
- Z.B not
- Zbe passed as part of the macro argument.
- ZThe proper usage is to pass a pointer to the first character
- Z.B after
- Zthe "-#" string.
- Z.SP 1
- ZEX:\ DBUG_PUSH\ (\&(argv[i][2]));
- Z.br
- ZEX:\ DBUG_PUSH\ ("d:t");
- Z.br
- ZEX:\ DBUG_PUSH\ ("");
- Z.SP 1
- Z.LI DBUG_POP\
- ZRestores the previous debugger state by popping the state stack.
- ZAttempting to pop more states than pushed will be ignored and no
- Zwarning will be given.
- ZThe
- ZDBUG_POP
- Zmacro has no arguments.
- Z.SP 1
- ZEX:\ DBUG_POP\ ();
- Z.SP 1
- Z.LI DBUG_FILE\
- ZThe
- ZDBUG_FILE
- Zmacro is used to do explicit I/O on the debug output
- Zstream.
- ZIt is used in the same manner as the symbols "stdout" and "stderr"
- Zin the standard I/O package.
- Z.SP 1
- ZEX:\ fprintf\ (DBUG_FILE,\ "Doing my own I/O!\n");
- Z.SP 1
- Z.LI DBUG_EXECUTE\
- ZThe DBUG_EXECUTE macro is used to execute any arbitrary C code.
- ZThe first argument is the debug keyword, used to trigger execution
- Zof the code specified as the second argument.
- ZThis macro must be used cautiously because, like the
- ZDBUG_PRINT
- Zmacro,
- Zit is automatically selected by default whenever the 'd' flag has
- Zno argument list (I.E., a "-#d:t" control string).
- Z.SP 1
- ZEX:\ DBUG_EXECUTE\ ("abort",\ abort\ ());
- Z.SP 1
- Z.LI DBUG_N\
- ZThese macros, where N is in the range 2-5, are currently obsolete
- Zand will be removed in a future release.
- ZUse the new DBUG_PRINT macro.
- Z.LI DBUG_PRINT\
- ZUsed to do printing via the "fprintf" library function on the
- Zcurrent debug stream,
- ZDBUG_FILE.
- ZThe first argument is a debug keyword, the second is a format string
- Zand the corresponding argument list.
- ZNote that the format string and argument list are all one macro argument
- Zand
- Z.B must
- Zbe enclosed in parenthesis.
- Z.SP 1
- ZEX:\ DBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));
- Z.br
- ZEX:\ DBUG_PRINT\ ("type",\ ("type\ is\ %x", type));
- Z.br
- ZEX:\ DBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));
- Z.LI DBUG_SETJMP\
- ZUsed in place of the setjmp() function to first save the current
- Zdebugger state and then execute the standard setjmp call.
- ZThis allows the debugger to restore its state when the
- ZDBUG_LONGJMP macro is used to invoke the standard longjmp() call.
- ZCurrently all instances of DBUG_SETJMP must occur within the
- Zsame function and at the same function nesting level.
- Z.SP 1
- ZEX:\ DBUG_SETJMP\ (env);
- Z.LI DBUG_LONGJMP\
- ZUsed in place of the longjmp() function to first restore the
- Zprevious debugger state at the time of the last DBUG_SETJMP
- Zand then execute the standard longjmp() call.
- ZNote that currently all DBUG_LONGJMP macros restore the state
- Zat the time of the last DBUG_SETJMP.
- ZIt would be possible to maintain separate DBUG_SETJMP and DBUG_LONGJMP
- Zpairs by having the debugger runtime support module use the first
- Zargument to differentiate the pairs.
- Z.SP 1
- ZEX:\ DBUG_LONGJMP\ (env,val);
- Z.LE
- Z
- Z.SK
- Z.B
- ZDEBUG CONTROL STRING
- Z.R
- Z
- Z.P
- ZThe debug control string is used to set the state of the debugger
- Zvia the
- Z.B DBUG_PUSH
- Zmacro.
- ZThis section summarizes the currently available debugger options
- Zand the flag characters which enable or disable them.
- ZArgument lists enclosed in '[' and ']' are optional.
- Z.SP 2
- Z.BL 22
- Z.LI d[,keywords]
- ZEnable output from macros with specified keywords.
- ZA null list of keywords implies that all keywords are selected.
- Z.LI D[,time]
- ZDelay for specified time after each output line, to let output drain.
- ZTime is given in tenths of a second (value of 10 is one second).
- ZDefault is zero.
- Z.LI f[,functions]
- ZLimit debugger actions to the specified list of functions.
- ZA null list of functions implies that all functions are selected.
- Z.LI F
- ZMark each debugger output line with the name of the source file
- Zcontaining the macro causing the output.
- Z.LI g
- ZTurn on machine independent profiling.
- ZA profiling data collection file, named dbugmon.out, will be written
- Zfor postprocessing by the "analyze" program.
- ZThe accuracy of this feature is relatively unknown at this time.
- Z.LI i
- ZIdentify the process emitting each line of debug or trace output
- Zwith the process id for that process.
- Z.LI L
- ZMark each debugger output line with the source file line number of
- Zthe macro causing the output.
- Z.LI n
- ZMark each debugger output line with the current function nesting depth.
- Z.LI N
- ZSequentially number each debugger output line starting at 1.
- ZThis is useful for reference purposes when debugger output is
- Zinterspersed with program output.
- Z.LI o[,file]
- ZRedirect the debugger output stream to the specified file.
- ZThe default output stream is stderr.
- ZA null argument list causes output to be redirected to stdout.
- Z.LI p[,processes]
- ZLimit debugger actions to the specified processes.
- ZA null list implies all processes.
- ZThis is useful for processes which run child processes.
- ZNote that each debugger output line can be marked with the name of
- Zthe current process via the 'P' flag.
- ZThe process name must match the argument passed to the
- Z.B DBUG_PROCESS
- Zmacro.
- Z.LI P
- ZMark each debugger output line with the name of the current process
- Zfrom argv[0].
- ZMost useful when used with a process which runs child processes that
- Zare also being debugged.
- ZNote that the parent process must arrange for the debugger control
- Zstring to be passed to the child processes.
- Z.LI r
- ZUsed in conjunction with the
- Z.B DBUG_PUSH
- Zmacro to reset the current
- Zindentation level back to zero.
- ZMost useful with
- Z.B DBUG_PUSH
- Zmacros used to temporarily alter the
- Zdebugger state.
- Z.LI t[,N]
- ZEnable function control flow tracing.
- ZThe maximum nesting depth is specified by N, and defaults to
- Z200.
- Z.LE
- Z.SK
- Z.B
- ZHINTS AND MISCELLANEOUS
- Z.R
- Z
- Z.P
- ZOne of the most useful capabilities of the
- Z.I dbug
- Zpackage is to compare the executions of a given program in two
- Zdifferent environments.
- ZThis is typically done by executing the program in the environment
- Zwhere it behaves properly and saving the debugger output in a
- Zreference file.
- ZThe program is then run with identical inputs in the environment where
- Zit misbehaves and the output is again captured in a reference file.
- ZThe two reference files can then be differentially compared to
- Zdetermine exactly where execution of the two processes diverges.
- Z
- Z.P
- ZA related usage is regression testing where the execution of a current
- Zversion is compared against executions of previous versions.
- ZThis is most useful when there are only minor changes.
- Z
- Z.P
- ZIt is not difficult to modify an existing compiler to implement
- Zsome of the functionality of the
- Z.I dbug
- Zpackage automatically, without source code changes to the
- Zprogram being debugged.
- ZIn fact, such changes were implemented in a version of the
- ZPortable C Compiler by the author in less than a day.
- ZHowever, it is strongly encouraged that all newly
- Zdeveloped code continue to use the debugger macros
- Zfor the portability reasons noted earlier.
- ZThe modified compiler should be used only for testing existing
- Zprograms.
- Z
- Z.SK
- Z.B
- ZCAVEATS
- Z.R
- Z
- Z.P
- ZThe
- Z.I dbug
- Zpackage works best with programs which have "line\ oriented"
- Zoutput, such as text processors, general purpose utilities, etc.
- ZIt can be interfaced with screen oriented programs such as
- Zvisual editors by redefining the appropriate macros to call
- Zspecial functions for displaying the debugger results.
- ZOf course, this caveat is not applicable if the debugger output
- Zis simply dumped into a file for post-execution examination.
- Z
- Z.P
- ZPrograms which use memory allocation functions other than
- Z.B malloc
- Zwill usually have problems using the standard
- Z.I dbug
- Zpackage.
- ZThe most common problem is multiply allocated memory.
- Z.SP 2
- Z.CS
- STUNKYFLUFF
- set `sum user.r`
- if test 9250 != $1
- then
- echo user.r: Checksum error. Is: $1, should be: 9250.
- fi
- #
- #
- echo Extracting vargs.h:
- sed 's/^Z//' >vargs.h <<\STUNKYFLUFF
- Z/******************************************************************************
- Z * *
- Z * N O T I C E *
- Z * *
- Z * Copyright Abandoned, 1987, Fred Fish *
- Z * *
- Z * *
- Z * This previously copyrighted work has been placed into the public *
- Z * domain by the author and may be freely used for any purpose, *
- Z * private or commercial. *
- Z * *
- Z * Because of the number of inquiries I was receiving about the use *
- Z * of this product in commercially developed works I have decided to *
- Z * simply make it public domain to further its unrestricted use. I *
- Z * specifically would be most happy to see this material become a *
- Z * part of the standard Unix distributions by AT&T and the Berkeley *
- Z * Computer Science Research Group, and a standard part of the GNU *
- Z * system from the Free Software Foundation. *
- Z * *
- Z * I would appreciate it, as a courtesy, if this notice is left in *
- Z * all copies and derivative works. Thank you. *
- Z * *
- Z * The author makes no warranty of any kind with respect to this *
- Z * product and explicitly disclaims any implied warranties of mer- *
- Z * chantability or fitness for any particular purpose. *
- Z * *
- Z ******************************************************************************
- Z */
- Z
- Z
- Z/*
- Z * FILE
- Z *
- Z * vargs.h include file for environments without varargs.h
- Z *
- Z * SCCS
- Z *
- Z * @(#)vargs.h 1.2 5/8/88
- Z *
- Z * SYNOPSIS
- Z *
- Z * #include "vargs.h"
- Z *
- Z * DESCRIPTION
- Z *
- Z * This file implements a varargs macro set for use in those
- Z * environments where there is no system supplied varargs. This
- Z * generally works because systems which don't supply a varargs
- Z * package are precisely those which don't strictly need a varargs
- Z * package. Using this one then allows us to minimize source
- Z * code changes. So in some sense, this is a "portable" varargs
- Z * since it is only used for convenience, when it is not strictly
- Z * needed.
- Z *
- Z */
- Z
- Z/*
- Z * These macros allow us to rebuild an argument list on the stack
- Z * given only a va_list. We can use these to fake a function like
- Z * vfprintf, which gets a fixed number of arguments, the last of
- Z * which is a va_list, by rebuilding a stack and calling the variable
- Z * argument form fprintf. Of course this only works when vfprintf
- Z * is not available in the host environment, and thus is not available
- Z * for fprintf to call (which would give us an infinite loop).
- Z *
- Z * Note that ARGS_TYPE is a long, which lets us get several bytes
- Z * at a time while also preventing lots of "possible pointer alignment
- Z * problem" messages from lint. The messages are valid, because this
- Z * IS nonportable, but then we should only be using it in very
- Z * nonrestrictive environments, and using the real varargs where it
- Z * really counts.
- Z *
- Z */
- Z
- Z#define ARG0 a0
- Z#define ARG1 a1
- Z#define ARG2 a2
- Z#define ARG3 a3
- Z#define ARG4 a4
- Z#define ARG5 a5
- Z#define ARG6 a6
- Z#define ARG7 a7
- Z#define ARG8 a8
- Z#define ARG9 a9
- Z
- Z#define ARGS_TYPE long
- Z#define ARGS_LIST ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8,ARG9
- Z#define ARGS_DCL auto ARGS_TYPE ARGS_LIST
- Z
- Z/*
- Z * A pointer of type "va_list" points to a section of memory
- Z * containing an array of variable sized arguments of unknown
- Z * number. This pointer is initialized by the va_start
- Z * macro to point to the first byte of the first argument.
- Z * We can then use it to walk through the argument list by
- Z * incrementing it by the size of the argument being referenced.
- Z */
- Z
- Ztypedef char *va_list;
- Z
- Z/*
- Z * The first variable argument overlays va_alist, which is
- Z * nothing more than a "handle" which allows us to get the
- Z * address of the first argument on the stack. Note that
- Z * by definition, the va_dcl macro includes the terminating
- Z * semicolon, which makes use of va_dcl in the source code
- Z * appear to be missing a semicolon.
- Z */
- Z
- Z#define va_dcl ARGS_TYPE va_alist;
- Z
- Z/*
- Z * The va_start macro takes a variable of type "va_list" and
- Z * initializes it. In our case, it initializes a local variable
- Z * of type "pointer to char" to point to the first argument on
- Z * the stack.
- Z */
- Z
- Z#define va_start(list) list = (char *) &va_alist
- Z
- Z/*
- Z * The va_end macro is a null operation for our use.
- Z */
- Z
- Z#define va_end(list)
- Z
- Z/*
- Z * The va_arg macro is the tricky one. This one takes
- Z * a va_list as the first argument, and a type as the second
- Z * argument, and returns a value of the appropriate type
- Z * while advancing the va_list to the following argument.
- Z * For our case, we first increment the va_list arg by the
- Z * size of the type being recovered, cast the result to
- Z * a pointer of the appropriate type, and then dereference
- Z * that pointer as an array to get the previous arg (which
- Z * is the one we wanted.
- Z */
- Z
- Z#define va_arg(list,type) ((type *) (list += sizeof (type)))[-1]
- Z
- STUNKYFLUFF
- set `sum vargs.h`
- if test 1668 != $1
- then
- echo vargs.h: Checksum error. Is: $1, should be: 1668.
- fi
- echo ALL DONE BUNKY!
- exit 0
-
-
-