summaryrefslogtreecommitdiff
path: root/dmake/dbug
diff options
context:
space:
mode:
Diffstat (limited to 'dmake/dbug')
-rw-r--r--dmake/dbug/dbug.mk66
-rw-r--r--dmake/dbug/dbug/dbug.c1845
-rw-r--r--dmake/dbug/dbug/dbug.h164
-rwxr-xr-xdmake/dbug/dbug/dbug.txt1452
-rw-r--r--dmake/dbug/dbug/dbug.uue368
-rwxr-xr-xdmake/dbug/dbug/example1.c12
-rwxr-xr-xdmake/dbug/dbug/example2.c17
-rwxr-xr-xdmake/dbug/dbug/example3.c16
-rwxr-xr-xdmake/dbug/dbug/factorial.c15
-rwxr-xr-xdmake/dbug/dbug/main.c27
-rwxr-xr-xdmake/dbug/dbug/makeman.sh18
-rw-r--r--dmake/dbug/dbug/readme52
-rwxr-xr-xdmake/dbug/dbug/user.r938
-rw-r--r--dmake/dbug/getwd.c6
-rw-r--r--dmake/dbug/malloc/_changes9
-rw-r--r--dmake/dbug/malloc/_readme133
-rw-r--r--dmake/dbug/malloc/calloc.c49
-rw-r--r--dmake/dbug/malloc/debug.h99
-rw-r--r--dmake/dbug/malloc/dump.c103
-rw-r--r--dmake/dbug/malloc/free.c150
-rw-r--r--dmake/dbug/malloc/m_init.c79
-rw-r--r--dmake/dbug/malloc/m_perror.c73
-rw-r--r--dmake/dbug/malloc/makefile77
-rw-r--r--dmake/dbug/malloc/malloc.3223
-rw-r--r--dmake/dbug/malloc/malloc.c627
-rw-r--r--dmake/dbug/malloc/malloc.h85
-rw-r--r--dmake/dbug/malloc/mallopt.c98
-rw-r--r--dmake/dbug/malloc/memory.c195
-rw-r--r--dmake/dbug/malloc/mlc_chk.c256
-rw-r--r--dmake/dbug/malloc/mlc_chn.c188
-rw-r--r--dmake/dbug/malloc/patchlev1
-rw-r--r--dmake/dbug/malloc/realloc.c180
-rw-r--r--dmake/dbug/malloc/string.c533
-rw-r--r--dmake/dbug/malloc/testmem.c646
-rw-r--r--dmake/dbug/malloc/testmlc.c176
-rw-r--r--dmake/dbug/malloc/tostring.c132
-rw-r--r--dmake/dbug/malloc/tostring.h13
-rw-r--r--dmake/dbug/readme13
38 files changed, 9134 insertions, 0 deletions
diff --git a/dmake/dbug/dbug.mk b/dmake/dbug/dbug.mk
new file mode 100644
index 000000000000..09aa82d7f37d
--- /dev/null
+++ b/dmake/dbug/dbug.mk
@@ -0,0 +1,66 @@
+# Set the proper macros based on whether we are making the debugging version
+# or not. The valid parameters to this file are:
+#
+# DEBUG=1 ==> enable the making of the DBUG version
+# DBMALLOC=1 ==> enable DBUG version with extensive MALLOC checking
+#
+# DB_CFLAGS ==> CFLAGS is set to this value at the end if DEBUG=1
+# DB_LDFLAGS ==> LDFLAGS is set to this at the end if DEBUG=1
+# DB_LDLIBS ==> LDLIBS is set to this at end if DEBUG=1
+#
+# The non debug versions of the above three macros are:
+#
+# NDB_CFLAGS
+# NDB_LDFLAGS
+# NDB_LDLIBS
+#
+# One of the set of three should have values set appropriately prior to
+# sourcing this file.
+
+.IF $(DEBUG)
+ DBUG_SRC += dbug.c
+ DB_CFLAGS += -Idbug/dbug
+
+ .SETDIR=dbug/dbug : $(DBUG_SRC)
+
+ # If DBMALLOC is requested (ie non-NULL) then include the sources for
+ # compilation. BSD 4.3 needs the getwd.c source compiled in due to a bug
+ # in the clib getwd routine.
+ .IF $(DBMALLOC)
+ # Serious bug in bsd43 getwd.c would free a string and then use its
+ # value. The DBMALLOC code clears a string when it is free'd so the
+ # value was no longer valid and the returned path for the current
+ # directory was now completely wrong.
+ .IF $(OSRELEASE) == bsd43
+ GETWD_SRC += getwd.c
+ .SETDIR=dbug : $(GETWD_SRC)
+ .END
+
+ MLC_SRC += malloc.c free.c realloc.c calloc.c string.c\
+ mlc_chk.c mlc_chn.c memory.c tostring.c m_perror.c\
+ m_init.c mallopt.c dump.c
+
+ .SETDIR=dbug/malloc : $(MLC_SRC)
+
+ DB_CFLAGS += -Idbug/malloc
+ .END
+
+ SRC += $(DBUG_SRC) $(MLC_SRC) $(GETWD_SRC)
+ HDR += db.h
+
+ LDFLAGS += $(DB_LDFLAGS)
+ LDLIBS += $(DB_LDLIBS)
+
+ __.SILENT !:= $(.SILENT)
+ .SILENT !:= yes
+ TARGET := db$(TARGET)
+ OBJDIR := $(OBJDIR).dbg
+ .SILENT !:= $(__.SILENT)
+
+ CFLAGS += $(DB_CFLAGS)
+ .KEEP_STATE := _dbstate.mk
+.ELSE
+ CFLAGS += $(NDB_CFLAGS)
+ LDFLAGS += $(NDB_LDFLAGS)
+ LDLIBS += $(NDB_LDLIBS)
+.END
diff --git a/dmake/dbug/dbug/dbug.c b/dmake/dbug/dbug/dbug.c
new file mode 100644
index 000000000000..e63a4750ed5b
--- /dev/null
+++ b/dmake/dbug/dbug/dbug.c
@@ -0,0 +1,1845 @@
+/******************************************************************************
+ * *
+ * N O T I C E *
+ * *
+ * Copyright Abandoned, 1987, Fred Fish *
+ * *
+ * *
+ * This previously copyrighted work has been placed into the public *
+ * domain by the author and may be freely used for any purpose, *
+ * private or commercial. *
+ * *
+ * Because of the number of inquiries I was receiving about the use *
+ * of this product in commercially developed works I have decided to *
+ * simply make it public domain to further its unrestricted use. I *
+ * specifically would be most happy to see this material become a *
+ * part of the standard Unix distributions by AT&T and the Berkeley *
+ * Computer Science Research Group, and a standard part of the GNU *
+ * system from the Free Software Foundation. *
+ * *
+ * I would appreciate it, as a courtesy, if this notice is left in *
+ * all copies and derivative works. Thank you. *
+ * *
+ * The author makes no warranty of any kind with respect to this *
+ * product and explicitly disclaims any implied warranties of mer- *
+ * chantability or fitness for any particular purpose. *
+ * *
+ ******************************************************************************
+ */
+
+
+/*
+ * FILE
+ *
+ * dbug.c runtime support routines for dbug package
+ *
+ * SCCS
+ *
+ * @(#)dbug.c 1.19 9/5/87
+ *
+ * DESCRIPTION
+ *
+ * These are the runtime support routines for the dbug package.
+ * The dbug package has two main components; the user include
+ * file containing various macro definitions, and the runtime
+ * support routines which are called from the macro expansions.
+ *
+ * Externally visible functions in the runtime support module
+ * use the naming convention pattern "_db_xx...xx_", thus
+ * they are unlikely to collide with user defined function names.
+ *
+ * AUTHOR(S)
+ *
+ * Fred Fish (base code)
+ * (Currently at Motorola Computer Division, Tempe, Az.)
+ * hao!noao!mcdsun!fnf
+ * (602) 438-3614
+ *
+ * Binayak Banerjee (profiling enhancements)
+ * seismo!bpa!sjuvax!bbanerje
+ */
+
+
+#include <stdio.h>
+#ifdef amiga
+#define AMIGA
+#endif
+
+#ifdef AMIGA
+#define HZ (50) /* Probably in some header somewhere */
+#endif
+
+/*
+ * Manifest constants that should not require any changes.
+ */
+
+#define FALSE 0 /* Boolean FALSE */
+#define TRUE 1 /* Boolean TRUE */
+#define EOS '\000' /* End Of String marker */
+
+/*
+ * Manifest constants which may be "tuned" if desired.
+ */
+
+#define PRINTBUF 1024 /* Print buffer size */
+#define INDENT 4 /* Indentation per trace level */
+#define MAXDEPTH 200 /* Maximum trace depth default */
+
+/*
+ * The following flags are used to determine which
+ * capabilities the user has enabled with the state
+ * push macro.
+ */
+
+#define TRACE_ON 000001 /* Trace enabled */
+#define DEBUG_ON 000002 /* Debug enabled */
+#define FILE_ON 000004 /* File name print enabled */
+#define LINE_ON 000010 /* Line number print enabled */
+#define DEPTH_ON 000020 /* Function nest level print enabled */
+#define PROCESS_ON 000040 /* Process name print enabled */
+#define NUMBER_ON 000100 /* Number each line of output */
+#define PROFILE_ON 000200 /* Print out profiling code */
+
+#define TRACING (stack -> flags & TRACE_ON)
+#define DEBUGGING (stack -> flags & DEBUG_ON)
+#define PROFILING (stack -> flags & PROFILE_ON)
+#define STREQ(a,b) (strcmp(a,b) == 0)
+
+/*
+ * Typedefs to make things more obvious.
+ */
+
+#define VOID void /* Can't use typedef for most compilers */
+typedef int BOOLEAN;
+
+/*
+ * Make it easy to change storage classes if necessary.
+ */
+
+#define LOCAL static /* Names not needed by outside world */
+#define IMPORT extern /* Names defined externally */
+#define EXPORT /* Allocated here, available globally */
+#define AUTO auto /* Names to be allocated on stack */
+#define REGISTER register /* Names to be placed in registers */
+
+/*
+ * The following define is for the variable arguments kluge, see
+ * the comments in _db_doprnt_().
+ *
+ * Also note that the longer this list, the less prone to failing
+ * on long argument lists, but the more stuff that must be moved
+ * around for each call to the runtime support routines. The
+ * length may really be critical if the machine convention is
+ * to pass arguments in registers.
+ *
+ * Note that the default define allows up to 16 integral arguments,
+ * or 8 floating point arguments (doubles), on most machines.
+ *
+ * Someday this may be replaced with true varargs support, when
+ * ANSI C has had time to take root.
+ */
+
+#define ARGLIST a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15
+
+/*
+ * The default file for profiling. Could also add another flag
+ * (G?) which allowed the user to specify this.
+ */
+
+#define PROF_FILE "dbugmon.out"
+
+/*
+ * Variables which are available externally but should only
+ * be accessed via the macro package facilities.
+ */
+
+EXPORT FILE *_db_fp_ = (FILE *)0; /* Output stream, default is set to
+ * stderr later */
+EXPORT FILE *_db_pfp_ = (FILE *)0; /* Profile stream, 'dbugmon.out' */
+EXPORT char *_db_process_ = "dbug"; /* Pointer to process name; argv[0] */
+EXPORT BOOLEAN _db_on_ = FALSE; /* TRUE if debugging currently on */
+EXPORT BOOLEAN _db_pon_ = FALSE; /* TRUE if debugging currently on */
+
+/*
+ * Externally supplied functions.
+ */
+
+/* Disable the manual definitions, if something is missing use #include's! */
+#if 0
+
+#ifdef unix /* Only needed for unix */
+IMPORT VOID perror (); /* Print system/library error */
+IMPORT int chown (); /* Change owner of a file */
+IMPORT int getgid (); /* Get real group id */
+IMPORT int getuid (); /* Get real user id */
+IMPORT int access (); /* Test file for access */
+#else
+#if !(AMIGA || LATTICE || __TURBOC__)
+LOCAL VOID perror (); /* Fake system/library error print routine */
+#endif
+#endif
+
+# if BSD4_3 || sun
+IMPORT int getrusage ();
+#endif
+
+IMPORT int atoi (); /* Convert ascii to integer */
+IMPORT VOID exit (); /* Terminate execution */
+IMPORT int fclose (); /* Close a stream */
+IMPORT FILE *fopen (); /* Open a stream */
+#if !defined(__BORLANDC__)
+IMPORT int fprintf (); /* Formatted print on file */
+#endif
+IMPORT VOID free ();
+IMPORT char *malloc (); /* Allocate memory */
+IMPORT int strcmp (); /* Compare strings */
+IMPORT char *strcpy (); /* Copy strings around */
+IMPORT int strlen (); /* Find length of string */
+
+#ifndef fflush /* This is sometimes a macro */
+IMPORT int fflush (); /* Flush output for stream */
+#endif
+
+#endif
+
+
+/*
+ * The user may specify a list of functions to trace or
+ * debug. These lists are kept in a linear linked list,
+ * a very simple implementation.
+ */
+
+struct link {
+ char *string; /* Pointer to link's contents */
+ struct link *next_link; /* Pointer to the next link */
+};
+
+
+/*
+ * Debugging states can be pushed or popped off of a
+ * stack which is implemented as a linked list. Note
+ * that the head of the list is the current state and the
+ * stack is pushed by adding a new state to the head of the
+ * list or popped by removing the first link.
+ */
+
+struct state {
+ int flags; /* Current state flags */
+ int maxdepth; /* Current maximum trace depth */
+ unsigned int delay; /* Delay after each output line */
+ int level; /* Current function nesting level */
+ FILE *out_file; /* Current output stream */
+ FILE *prof_file; /* Current profiling stream */
+ struct link *functions; /* List of functions */
+ struct link *p_functions; /* List of profiled functions */
+ struct link *keywords; /* List of debug keywords */
+ struct link *processes; /* List of process names */
+ struct state *next_state; /* Next state in the list */
+};
+
+LOCAL struct state *stack = NULL; /* Linked list of stacked states */
+
+/*
+ * Local variables not seen by user.
+ */
+
+LOCAL int lineno = 0; /* Current debugger output line number */
+LOCAL char *func = "?func"; /* Name of current user function */
+LOCAL char *file = "?file"; /* Name of current user file */
+LOCAL BOOLEAN init_done = FALSE;/* Set to TRUE when initialization done */
+
+/*#if unix || AMIGA || M_I86*/
+LOCAL int jmplevel; /* Remember nesting level at setjmp () */
+LOCAL char *jmpfunc; /* Remember current function for setjmp */
+LOCAL char *jmpfile; /* Remember current file for setjmp */
+/*#endif*/
+
+LOCAL struct link *ListParse ();/* Parse a debug command string */
+LOCAL char *StrDup (); /* Make a fresh copy of a string */
+LOCAL VOID OpenFile (); /* Open debug output stream */
+LOCAL VOID OpenProfile (); /* Open profile output stream */
+LOCAL VOID CloseFile (); /* Close debug output stream */
+LOCAL VOID PushState (); /* Push current debug state */
+LOCAL VOID ChangeOwner (); /* Change file owner and group */
+LOCAL BOOLEAN DoTrace (); /* Test for tracing enabled */
+LOCAL BOOLEAN Writable (); /* Test to see if file is writable */
+LOCAL unsigned long Clock (); /* Return current user time (ms) */
+LOCAL char *DbugMalloc (); /* Allocate memory for runtime support */
+LOCAL char *BaseName (); /* Remove leading pathname components */
+LOCAL VOID DoPrefix (); /* Print debugger line prefix */
+LOCAL VOID FreeList (); /* Free memory from linked list */
+LOCAL VOID Indent (); /* Indent line to specified indent */
+LOCAL int DelayArg (int value); /* Convert D flag argument */
+LOCAL BOOLEAN DoProfile (); /* Check if profiling is enabled */
+
+ /* Supplied in Sys V runtime environ */
+LOCAL char *strtok (); /* Break string into tokens */
+LOCAL char *strrchr (); /* Find last occurance of char */
+
+/*
+ * The following local variables are used to hold the state information
+ * between the call to _db_pargs_() and _db_doprnt_(), during
+ * expansion of the DBUG_PRINT macro. This is the only macro
+ * that currently uses these variables. The DBUG_PRINT macro
+ * and the new _db_doprnt_() routine replace the older DBUG_N macros
+ * and their corresponding runtime support routine _db_printf_().
+ *
+ * These variables are currently used only by _db_pargs_() and
+ * _db_doprnt_().
+ */
+
+LOCAL int u_line = 0; /* User source code line number */
+LOCAL char *u_keyword = "?"; /* Keyword for current macro */
+
+/*
+ * Miscellaneous printf format strings.
+ */
+
+#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
+#define ERR_OPEN "%s: can't open debug output stream \"%s\": "
+#define ERR_CLOSE "%s: can't close debug file: "
+#define ERR_ABORT "%s: debugger aborting because %s\n"
+#define ERR_CHOWN "%s: can't change owner/group of \"%s\": "
+#define ERR_PRINTF "%s: obsolete object file for '%s', please recompile!\n"
+
+/*
+ * Macros and defines for testing file accessibility under UNIX.
+ */
+
+#ifdef unix
+# define A_EXISTS 00 /* Test for file existance */
+# define A_EXECUTE 01 /* Test for execute permission */
+# define A_WRITE 02 /* Test for write access */
+# define A_READ 03 /* Test for read access */
+# define EXISTS(pathname) (access (pathname, A_EXISTS) == 0)
+# define WRITABLE(pathname) (access (pathname, A_WRITE) == 0)
+#else
+# define EXISTS(pathname) (FALSE) /* Assume no existance */
+#endif
+
+/*
+ * Translate some calls among different systems.
+ */
+
+#ifdef unix
+# define XDelay sleep
+IMPORT unsigned int sleep (); /* Pause for given number of seconds */
+#endif
+
+#ifdef AMIGA
+IMPORT int XDelay (); /* Pause for given number of ticks */
+#endif
+
+
+/*
+ * FUNCTION
+ *
+ * _db_push_ push current debugger state and set up new one
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_push_ (control)
+ * char *control;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a debug control string in "control", pushes
+ * the current debug state, parses the control string, and sets
+ * up a new debug state.
+ *
+ * The only attribute of the new state inherited from the previous
+ * state is the current function nesting level. This can be
+ * overridden by using the "r" flag in the control string.
+ *
+ * The debug control string is a sequence of colon separated fields
+ * as follows:
+ *
+ * <field_1>:<field_2>:...:<field_N>
+ *
+ * Each field consists of a mandatory flag character followed by
+ * an optional "," and comma separated list of modifiers:
+ *
+ * flag[,modifier,modifier,...,modifier]
+ *
+ * The currently recognized flag characters are:
+ *
+ * d Enable output from DBUG_<N> macros for
+ * for the current state. May be followed
+ * by a list of keywords which selects output
+ * only for the DBUG macros with that keyword.
+ * A null list of keywords implies output for
+ * all macros.
+ *
+ * D Delay after each debugger output line.
+ * The argument is the number of tenths of seconds
+ * to delay, subject to machine capabilities.
+ * I.E. -#D,20 is delay two seconds.
+ *
+ * f Limit debugging and/or tracing, and profiling to the
+ * list of named functions. Note that a null list will
+ * disable all functions. The appropriate "d" or "t"
+ * flags must still be given, this flag only limits their
+ * actions if they are enabled.
+ *
+ * F Identify the source file name for each
+ * line of debug or trace output.
+ *
+ * g Enable profiling. Create a file called 'dbugmon.out'
+ * containing information that can be used to profile
+ * the program. May be followed by a list of keywords
+ * that select profiling only for the functions in that
+ * list. A null list implies that all functions are
+ * considered.
+ *
+ * L Identify the source file line number for
+ * each line of debug or trace output.
+ *
+ * n Print the current function nesting depth for
+ * each line of debug or trace output.
+ *
+ * N Number each line of dbug output.
+ *
+ * p Limit debugger actions to specified processes.
+ * A process must be identified with the
+ * DBUG_PROCESS macro and match one in the list
+ * for debugger actions to occur.
+ *
+ * P Print the current process name for each
+ * line of debug or trace output.
+ *
+ * r When pushing a new state, do not inherit
+ * the previous state's function nesting level.
+ * Useful when the output is to start at the
+ * left margin.
+ *
+ * t Enable function call/exit trace lines.
+ * May be followed by a list (containing only
+ * one modifier) giving a numeric maximum
+ * trace level, beyond which no output will
+ * occur for either debugging or tracing
+ * macros. The default is a compile time
+ * option.
+ *
+ * Some examples of debug control strings which might appear
+ * on a shell command line (the "-#" is typically used to
+ * introduce a control string to an application program) are:
+ *
+ * -#d:t
+ * -#d:f,main,subr1:F:L:t,20
+ * -#d,input,output,files:n
+ *
+ * For convenience, any leading "-#" is stripped off.
+ *
+ */
+
+
+VOID _db_push_ (control)
+char *control;
+{
+ REGISTER char *scan;
+ REGISTER struct link *temp;
+
+ if (!_db_fp_)
+ _db_fp_ = stderr; /* Output stream, default stderr */
+
+ if (control && *control == '-') {
+ if (*++control == '#') {
+ control++;
+ }
+ }
+ control = StrDup (control);
+ PushState ();
+ scan = strtok (control, ":");
+ for (; scan != NULL; scan = strtok ((char *)NULL, ":")) {
+ switch (*scan++) {
+ case 'd':
+ _db_on_ = TRUE;
+ stack -> flags |= DEBUG_ON;
+ if (*scan++ == ',') {
+ stack -> keywords = ListParse (scan);
+ }
+ break;
+ case 'D':
+ stack -> delay = 0;
+ if (*scan++ == ',') {
+ temp = ListParse (scan);
+ stack -> delay = DelayArg (atoi (temp -> string));
+ FreeList (temp);
+ }
+ break;
+ case 'f':
+ if (*scan++ == ',') {
+ stack -> functions = ListParse (scan);
+ }
+ break;
+ case 'F':
+ stack -> flags |= FILE_ON;
+ break;
+ case 'g':
+ _db_pon_ = TRUE;
+ OpenProfile(PROF_FILE);
+ stack -> flags |= PROFILE_ON;
+ if (*scan++ == ',') {
+ stack -> p_functions = ListParse (scan);
+ }
+ break;
+ case 'L':
+ stack -> flags |= LINE_ON;
+ break;
+ case 'n':
+ stack -> flags |= DEPTH_ON;
+ break;
+ case 'N':
+ stack -> flags |= NUMBER_ON;
+ break;
+ case 'o':
+ if (*scan++ == ',') {
+ temp = ListParse (scan);
+ OpenFile (temp -> string);
+ FreeList (temp);
+ } else {
+ OpenFile ("-");
+ }
+ break;
+ case 'p':
+ if (*scan++ == ',') {
+ stack -> processes = ListParse (scan);
+ }
+ break;
+ case 'P':
+ stack -> flags |= PROCESS_ON;
+ break;
+ case 'r':
+ stack -> level = 0;
+ break;
+ case 't':
+ stack -> flags |= TRACE_ON;
+ if (*scan++ == ',') {
+ temp = ListParse (scan);
+ stack -> maxdepth = atoi (temp -> string);
+ FreeList (temp);
+ }
+ break;
+ }
+ }
+ free (control);
+}
+
+
+
+/*
+ * FUNCTION
+ *
+ * _db_pop_ pop the debug stack
+ *
+ * DESCRIPTION
+ *
+ * Pops the debug stack, returning the debug state to its
+ * condition prior to the most recent _db_push_ invocation.
+ * Note that the pop will fail if it would remove the last
+ * valid state from the stack. This prevents user errors
+ * in the push/pop sequence from screwing up the debugger.
+ * Maybe there should be some kind of warning printed if the
+ * user tries to pop too many states.
+ *
+ */
+
+VOID _db_pop_ ()
+{
+ REGISTER struct state *discard;
+
+ discard = stack;
+ if (discard != NULL && discard -> next_state != NULL) {
+ stack = discard -> next_state;
+ _db_fp_ = stack -> out_file;
+ _db_pfp_ = stack -> prof_file;
+ if (discard -> keywords != NULL) {
+ FreeList (discard -> keywords);
+ }
+ if (discard -> functions != NULL) {
+ FreeList (discard -> functions);
+ }
+ if (discard -> processes != NULL) {
+ FreeList (discard -> processes);
+ }
+ if (discard -> p_functions != NULL) {
+ FreeList (discard -> p_functions);
+ }
+ CloseFile (discard -> out_file);
+ CloseFile (discard -> prof_file);
+ free ((char *) discard);
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_enter_ process entry point to user function
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_)
+ * char *_func_; points to current function name
+ * char *_file_; points to current file name
+ * int _line_; called from source line number
+ * char **_sfunc_; save previous _func_
+ * char **_sfile_; save previous _file_
+ * int *_slevel_; save previous nesting level
+ *
+ * DESCRIPTION
+ *
+ * Called at the beginning of each user function to tell
+ * the debugger that a new function has been entered.
+ * Note that the pointers to the previous user function
+ * name and previous user file name are stored on the
+ * caller's stack (this is why the ENTER macro must be
+ * the first "executable" code in a function, since it
+ * allocates these storage locations). The previous nesting
+ * level is also stored on the callers stack for internal
+ * self consistency checks.
+ *
+ * Also prints a trace line if tracing is enabled and
+ * increments the current function nesting depth.
+ *
+ * Note that this mechanism allows the debugger to know
+ * what the current user function is at all times, without
+ * maintaining an internal stack for the function names.
+ *
+ */
+
+VOID _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_)
+char *_func_;
+char *_file_;
+int _line_;
+char **_sfunc_;
+char **_sfile_;
+int *_slevel_;
+{
+ if (!init_done) {
+ _db_push_ ("");
+ }
+ *_sfunc_ = func;
+ *_sfile_ = file;
+ func = _func_;
+ file = BaseName (_file_);
+ stack -> level++;
+ *_slevel_ = stack -> level;
+ if (DoProfile ()) {
+ (VOID) fprintf (_db_pfp_, "%s\tE\t%ld\n",func, Clock());
+ (VOID) fflush (_db_pfp_);
+ }
+ if (DoTrace ()) {
+ DoPrefix (_line_);
+ Indent (stack -> level);
+ (VOID) fprintf (_db_fp_, ">%s\n", func);
+ (VOID) fflush (_db_fp_);
+ (VOID) XDelay (stack -> delay);
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_return_ process exit from user function
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
+ * int _line_; current source line number
+ * char **_sfunc_; where previous _func_ is to be retrieved
+ * char **_sfile_; where previous _file_ is to be retrieved
+ * int *_slevel_; where previous level was stashed
+ *
+ * DESCRIPTION
+ *
+ * Called just before user function executes an explicit or implicit
+ * return. Prints a trace line if trace is enabled, decrements
+ * the current nesting level, and restores the current function and
+ * file names from the defunct function's stack.
+ *
+ */
+
+VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
+int _line_;
+char **_sfunc_;
+char **_sfile_;
+int *_slevel_;
+{
+ if (!init_done) {
+ _db_push_ ("");
+ }
+ if (stack -> level != *_slevel_ && (TRACING || DEBUGGING || PROFILING)) {
+ (VOID) fprintf (_db_fp_, ERR_MISSING_RETURN, _db_process_, func);
+ (VOID) XDelay (stack -> delay);
+ } else if (DoProfile ()) {
+ (VOID) fprintf (_db_pfp_, "%s\tX\t%ld\n", func, Clock());
+ (VOID) XDelay (stack -> delay);
+ } else if (DoTrace ()) {
+ DoPrefix (_line_);
+ Indent (stack -> level);
+ (VOID) fprintf (_db_fp_, "<%s\n", func);
+ (VOID) XDelay (stack -> delay);
+ }
+ (VOID) fflush (_db_fp_);
+ stack -> level = *_slevel_ - 1;
+ func = *_sfunc_;
+ file = *_sfile_;
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_pargs_ log arguments for subsequent use by _db_doprnt_()
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_pargs_ (_line_, keyword)
+ * int _line_;
+ * char *keyword;
+ *
+ * DESCRIPTION
+ *
+ * The new universal printing macro DBUG_PRINT, which replaces
+ * all forms of the DBUG_N macros, needs two calls to runtime
+ * support routines. The first, this function, remembers arguments
+ * that are used by the subsequent call to _db_doprnt_().
+*
+ */
+
+VOID _db_pargs_ (_line_, keyword)
+int _line_;
+char *keyword;
+{
+ u_line = _line_;
+ u_keyword = keyword;
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_doprnt_ handle print of debug lines
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_doprnt_ (format, ARGLIST)
+ * char *format;
+ * long ARGLIST;
+ *
+ * DESCRIPTION
+ *
+ * When invoked via one of the DBUG macros, tests the current keyword
+ * set by calling _db_pargs_() to see if that macro has been selected
+ * for processing via the debugger control string, and if so, handles
+ * printing of the arguments via the format string. The line number
+ * of the DBUG macro in the source is found in u_line.
+ *
+ * Note that the format string SHOULD NOT include a terminating
+ * newline, this is supplied automatically.
+ *
+ * NOTES
+ *
+ * This runtime support routine replaces the older _db_printf_()
+ * routine which is temporarily kept around for compatibility.
+ *
+ * The rather ugly argument declaration is to handle some
+ * magic with respect to the number of arguments passed
+ * via the DBUG macros. The current maximum is 3 arguments
+ * (not including the keyword and format strings).
+ *
+ * The new <varargs.h> facility is not yet common enough to
+ * convert to it quite yet...
+ *
+ */
+
+/*VARARGS1*/
+VOID _db_doprnt_ (format, ARGLIST)
+char *format;
+long ARGLIST;
+{
+ if (_db_keyword_ (u_keyword)) {
+ DoPrefix (u_line);
+ if (TRACING) {
+ Indent (stack -> level + 1);
+ } else {
+ (VOID) fprintf (_db_fp_, "%s: ", func);
+ }
+ (VOID) fprintf (_db_fp_, "%s: ", u_keyword);
+ (VOID) fprintf (_db_fp_, format, ARGLIST);
+ (VOID) fprintf (_db_fp_, "\n");
+ (VOID) fflush (_db_fp_);
+ (VOID) XDelay (stack -> delay);
+ }
+}
+
+/*
+ * The following routine is kept around temporarily for compatibility
+ * with older objects that were compiled with the DBUG_N macro form
+ * of the print routine. It will print a warning message on first
+ * usage. It will go away in subsequent releases...
+ */
+
+/*VARARGS3*/
+VOID _db_printf_ (_line_, keyword, format, ARGLIST)
+int _line_;
+char *keyword, *format;
+long ARGLIST;
+{
+ static BOOLEAN firsttime = TRUE;
+
+ if (firsttime) {
+ (VOID) fprintf (stderr, ERR_PRINTF, _db_process_, file);
+ firsttime = FALSE;
+ }
+ _db_pargs_ (_line_, keyword);
+ _db_doprnt_ (format, ARGLIST);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * ListParse parse list of modifiers in debug control string
+ *
+ * SYNOPSIS
+ *
+ * LOCAL struct link *ListParse (ctlp)
+ * char *ctlp;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a comma separated list of strings in "cltp",
+ * parses the list, building a list and returning a pointer to it.
+ * The original comma separated list is destroyed in the process of
+ * building the linked list, thus it had better be a duplicate
+ * if it is important.
+ *
+ * Note that since each link is added at the head of the list,
+ * the final list will be in "reverse order", which is not
+ * significant for our usage here.
+ *
+ */
+
+LOCAL struct link *ListParse (ctlp)
+char *ctlp;
+{
+ REGISTER char *start;
+ REGISTER struct link *new;
+ REGISTER struct link *head;
+
+ head = NULL;
+ while (*ctlp != EOS) {
+ start = ctlp;
+ while (*ctlp != EOS && *ctlp != ',') {
+ ctlp++;
+ }
+ if (*ctlp == ',') {
+ *ctlp++ = EOS;
+ }
+ new = (struct link *) DbugMalloc (sizeof (struct link));
+ new -> string = StrDup (start);
+ new -> next_link = head;
+ head = new;
+ }
+ return (head);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * InList test a given string for member of a given list
+ *
+ * SYNOPSIS
+ *
+ * LOCAL BOOLEAN InList (linkp, cp)
+ * struct link *linkp;
+ * char *cp;
+ *
+ * DESCRIPTION
+ *
+ * Tests the string pointed to by "cp" to determine if it is in
+ * the list pointed to by "linkp". Linkp points to the first
+ * link in the list. If linkp is NULL then the string is treated
+ * as if it is in the list (I.E all strings are in the null list).
+ * This may seem rather strange at first but leads to the desired
+ * operation if no list is given. The net effect is that all
+ * strings will be accepted when there is no list, and when there
+ * is a list, only those strings in the list will be accepted.
+ *
+ */
+
+LOCAL BOOLEAN InList (linkp, cp)
+struct link *linkp;
+char *cp;
+{
+ REGISTER struct link *scan;
+ REGISTER BOOLEAN accept;
+
+ if (linkp == NULL) {
+ accept = TRUE;
+ } else {
+ accept = FALSE;
+ for (scan = linkp; scan != NULL; scan = scan -> next_link) {
+ if (STREQ (scan -> string, cp)) {
+ accept = TRUE;
+ break;
+ }
+ }
+ }
+ return (accept);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * PushState push current state onto stack and set up new one
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID PushState ()
+ *
+ * DESCRIPTION
+ *
+ * Pushes the current state on the state stack, and initializes
+ * a new state. The only parameter inherited from the previous
+ * state is the function nesting level. This action can be
+ * inhibited if desired, via the "r" flag.
+ *
+ * The state stack is a linked list of states, with the new
+ * state added at the head. This allows the stack to grow
+ * to the limits of memory if necessary.
+ *
+ */
+
+LOCAL VOID PushState ()
+{
+ REGISTER struct state *new;
+
+ new = (struct state *) DbugMalloc (sizeof (struct state));
+ new -> flags = 0;
+ new -> delay = 0;
+ new -> maxdepth = MAXDEPTH;
+ if (stack != NULL) {
+ new -> level = stack -> level;
+ } else {
+ new -> level = 0;
+ }
+ new -> out_file = stderr;
+ new -> functions = NULL;
+ new -> p_functions = NULL;
+ new -> keywords = NULL;
+ new -> processes = NULL;
+ new -> next_state = stack;
+ stack = new;
+ init_done = TRUE;
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DoTrace check to see if tracing is current enabled
+ *
+ * SYNOPSIS
+ *
+ * LOCAL BOOLEAN DoTrace ()
+ *
+ * DESCRIPTION
+ *
+ * Checks to see if tracing is enabled based on whether the
+ * user has specified tracing, the maximum trace depth has
+ * not yet been reached, the current function is selected,
+ * and the current process is selected. Returns TRUE if
+ * tracing is enabled, FALSE otherwise.
+ *
+ */
+
+LOCAL BOOLEAN DoTrace ()
+{
+ REGISTER BOOLEAN trace;
+
+ trace = FALSE;
+ if (TRACING) {
+ if (stack -> level <= stack -> maxdepth) {
+ if (InList (stack -> functions, func)) {
+ if (InList (stack -> processes, _db_process_)) {
+ trace = TRUE;
+ }
+ }
+ }
+ }
+ return (trace);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DoProfile check to see if profiling is current enabled
+ *
+ * SYNOPSIS
+ *
+ * LOCAL BOOLEAN DoProfile ()
+ *
+ * DESCRIPTION
+ *
+ * Checks to see if profiling is enabled based on whether the
+ * user has specified profiling, the maximum trace depth has
+ * not yet been reached, the current function is selected,
+ * and the current process is selected. Returns TRUE if
+ * profiling is enabled, FALSE otherwise.
+ *
+ */
+
+LOCAL BOOLEAN DoProfile ()
+{
+ REGISTER BOOLEAN profile;
+
+ profile = FALSE;
+ if (PROFILING) {
+ if (stack -> level <= stack -> maxdepth) {
+ if (InList (stack -> p_functions, func)) {
+ if (InList (stack -> processes, _db_process_)) {
+ profile = TRUE;
+ }
+ }
+ }
+ }
+ return (profile);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_keyword_ test keyword for member of keyword list
+ *
+ * SYNOPSIS
+ *
+ * BOOLEAN _db_keyword_ (keyword)
+ * char *keyword;
+ *
+ * DESCRIPTION
+ *
+ * Test a keyword to determine if it is in the currently active
+ * keyword list. As with the function list, a keyword is accepted
+ * if the list is null, otherwise it must match one of the list
+ * members. When debugging is not on, no keywords are accepted.
+ * After the maximum trace level is exceeded, no keywords are
+ * accepted (this behavior subject to change). Additionally,
+ * the current function and process must be accepted based on
+ * their respective lists.
+ *
+ * Returns TRUE if keyword accepted, FALSE otherwise.
+ *
+ */
+
+BOOLEAN _db_keyword_ (keyword)
+char *keyword;
+{
+ REGISTER BOOLEAN accept;
+
+ if (!init_done) {
+ _db_push_ ("");
+ }
+ accept = FALSE;
+ if (DEBUGGING) {
+ if (stack -> level <= stack -> maxdepth) {
+ if (InList (stack -> functions, func)) {
+ if (InList (stack -> keywords, keyword)) {
+ if (InList (stack -> processes, _db_process_)) {
+ accept = TRUE;
+ }
+ }
+ }
+ }
+ }
+ return (accept);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * Indent indent a line to the given indentation level
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID Indent (indent)
+ * int indent;
+ *
+ * DESCRIPTION
+ *
+ * Indent a line to the given level. Note that this is
+ * a simple minded but portable implementation.
+ * There are better ways.
+ *
+ * Also, the indent must be scaled by the compile time option
+ * of character positions per nesting level.
+ *
+ */
+
+LOCAL VOID Indent (indent)
+int indent;
+{
+ REGISTER int count;
+ AUTO char buffer[PRINTBUF];
+
+ indent *= INDENT;
+ for (count = 0; (count < (indent - INDENT)) && (count < (PRINTBUF - 1)); count++) {
+ if ((count % INDENT) == 0) {
+ buffer[count] = '|';
+ } else {
+ buffer[count] = ' ';
+ }
+ }
+ buffer[count] = EOS;
+ (VOID) fprintf (_db_fp_, buffer);
+ (VOID) fflush (_db_fp_);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * FreeList free all memory associated with a linked list
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID FreeList (linkp)
+ * struct link *linkp;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to the head of a linked list, frees all
+ * memory held by the list and the members of the list.
+ *
+ */
+
+LOCAL VOID FreeList (linkp)
+struct link *linkp;
+{
+ REGISTER struct link *old;
+
+ while (linkp != NULL) {
+ old = linkp;
+ linkp = linkp -> next_link;
+ if (old -> string != NULL) {
+ free (old -> string);
+ }
+ free ((char *) old);
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * StrDup make a duplicate of a string in new memory
+ *
+ * SYNOPSIS
+ *
+ * LOCAL char *StrDup (string)
+ * char *string;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a string, allocates sufficient memory to make
+ * a duplicate copy, and copies the string to the newly allocated
+ * memory. Failure to allocated sufficient memory is immediately
+ * fatal.
+ *
+ */
+
+
+LOCAL char *StrDup (string)
+char *string;
+{
+ REGISTER char *new;
+
+ new = DbugMalloc (strlen (string) + 1);
+ (VOID) strcpy (new, string);
+ return (new);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DoPrefix print debugger line prefix prior to indentation
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID DoPrefix (_line_)
+ * int _line_;
+ *
+ * DESCRIPTION
+ *
+ * Print prefix common to all debugger output lines, prior to
+ * doing indentation if necessary. Print such information as
+ * current process name, current source file name and line number,
+ * and current function nesting depth.
+ *
+ */
+
+
+LOCAL VOID DoPrefix (_line_)
+int _line_;
+{
+ lineno++;
+ if (stack -> flags & NUMBER_ON) {
+ (VOID) fprintf (_db_fp_, "%5d: ", lineno);
+ }
+ if (stack -> flags & PROCESS_ON) {
+ (VOID) fprintf (_db_fp_, "%s: ", _db_process_);
+ }
+ if (stack -> flags & FILE_ON) {
+ (VOID) fprintf (_db_fp_, "%14s: ", file);
+ }
+ if (stack -> flags & LINE_ON) {
+ (VOID) fprintf (_db_fp_, "%5d: ", _line_);
+ }
+ if (stack -> flags & DEPTH_ON) {
+ (VOID) fprintf (_db_fp_, "%4d: ", stack -> level);
+ }
+ (VOID) fflush (_db_fp_);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * OpenFile open new output stream for debugger output
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID OpenFile (name)
+ * char *name;
+ *
+ * DESCRIPTION
+ *
+ * Given name of a new file (or "-" for stdout) opens the file
+ * and sets the output stream to the new file.
+ *
+ */
+
+LOCAL VOID OpenFile (name)
+char *name;
+{
+ REGISTER FILE *fp;
+ REGISTER BOOLEAN newfile;
+
+ if (name != NULL) {
+ if (strcmp (name, "-") == 0) {
+ _db_fp_ = stdout;
+ stack -> out_file = _db_fp_;
+ } else {
+ if (!Writable (name)) {
+ (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+ perror ("");
+ (VOID) fflush (_db_fp_);
+ (VOID) XDelay (stack -> delay);
+ } else {
+ if (EXISTS (name)) {
+ newfile = FALSE;
+ } else {
+ newfile = TRUE;
+ }
+ fp = fopen (name, "a");
+ if (fp == NULL) {
+ (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+ perror ("");
+ (VOID) fflush (_db_fp_);
+ (VOID) XDelay (stack -> delay);
+ } else {
+ _db_fp_ = fp;
+ stack -> out_file = fp;
+ if (newfile) {
+ ChangeOwner (name);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * OpenProfile open new output stream for profiler output
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID OpenProfile (name)
+ * char *name;
+ *
+ * DESCRIPTION
+ *
+ * Given name of a new file, opens the file
+ * and sets the profiler output stream to the new file.
+ *
+ * It is currently unclear whether the prefered behavior is
+ * to truncate any existing file, or simply append to it.
+ * The latter behavior would be desirable for collecting
+ * accumulated runtime history over a number of separate
+ * runs. It might take some changes to the analyzer program
+ * though, and the notes that Binayak sent with the profiling
+ * diffs indicated that append was the normal mode, but this
+ * does not appear to agree with the actual code. I haven't
+ * investigated at this time [fnf; 24-Jul-87].
+ */
+
+LOCAL VOID OpenProfile (name)
+char *name;
+{
+ REGISTER FILE *fp;
+ REGISTER BOOLEAN newfile;
+
+ if (name != NULL) {
+ if (!Writable (name)) {
+ (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+ perror ("");
+ (VOID) fflush (_db_fp_);
+ (VOID) XDelay (stack -> delay);
+ } else {
+ if (EXISTS (name)) {
+ newfile = FALSE;
+ } else {
+ newfile = TRUE;
+ }
+ fp = fopen (name, "w");
+ if (fp == NULL) {
+ (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+ perror ("");
+ (VOID) fflush (_db_fp_);
+ (VOID) XDelay (stack -> delay);
+ } else {
+ _db_pfp_ = fp;
+ stack -> prof_file = fp;
+ if (newfile) {
+ ChangeOwner (name);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * CloseFile close the debug output stream
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID CloseFile (fp)
+ * FILE *fp;
+ *
+ * DESCRIPTION
+ *
+ * Closes the debug output stream unless it is standard output
+ * or standard error.
+ *
+ */
+
+LOCAL VOID CloseFile (fp)
+FILE *fp;
+{
+ if (fp != stderr && fp != stdout) {
+ if (fclose (fp) == EOF) {
+ (VOID) fprintf (stderr, ERR_CLOSE, _db_process_);
+ perror ("");
+ (VOID) fflush (stderr);
+ (VOID) XDelay (stack -> delay);
+ }
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DbugExit print error message and exit
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID DbugExit (why)
+ * char *why;
+ *
+ * DESCRIPTION
+ *
+ * Prints error message using current process name, the reason for
+ * aborting (typically out of memory), and exits with status 1.
+ * This should probably be changed to use a status code
+ * defined in the user's debugger include file.
+ *
+ */
+
+LOCAL VOID DbugExit (why)
+char *why;
+{
+ (VOID) fprintf (stderr, ERR_ABORT, _db_process_, why);
+ (VOID) fflush (stderr);
+ (VOID) XDelay (stack -> delay);
+ exit (1);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DbugMalloc allocate memory for debugger runtime support
+ *
+ * SYNOPSIS
+ *
+ * LOCAL char *DbugMalloc (size)
+ * int size;
+ *
+ * DESCRIPTION
+ *
+ * Allocate more memory for debugger runtime support functions.
+ * Failure to to allocate the requested number of bytes is
+ * immediately fatal to the current process. This may be
+ * rather unfriendly behavior. It might be better to simply
+ * print a warning message, freeze the current debugger state,
+ * and continue execution.
+ *
+ */
+
+LOCAL char *DbugMalloc (size)
+int size;
+{
+ register char *new;
+
+ new = malloc ( size );
+ if (new == NULL) {
+ DbugExit ("out of memory");
+ }
+ return (new);
+}
+
+
+/*
+ * This function may be eliminated when strtok is available
+ * in the runtime environment (missing from BSD4.1).
+ */
+
+LOCAL char *strtok (s1, s2)
+char *s1, *s2;
+{
+ static char *end = NULL;
+ REGISTER char *rtnval;
+
+ rtnval = NULL;
+ if (s2 != NULL) {
+ if (s1 != NULL) {
+ end = s1;
+ rtnval = strtok ((char *) NULL, s2);
+ } else if (end != NULL) {
+ if (*end != EOS) {
+ rtnval = end;
+ while (*end != *s2 && *end != EOS) {end++;}
+ if (*end != EOS) {
+ *end++ = EOS;
+ }
+ }
+ }
+ }
+ return (rtnval);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * BaseName strip leading pathname components from name
+ *
+ * SYNOPSIS
+ *
+ * LOCAL char *BaseName (pathname)
+ * char *pathname;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a complete pathname, locates the base file
+ * name at the end of the pathname and returns a pointer to
+ * it.
+ *
+ */
+
+LOCAL char *BaseName (pathname)
+char *pathname;
+{
+ register char *base;
+
+ base = strrchr (pathname, '/');
+ if (base++ == NULL) {
+ base = pathname;
+ }
+ return (base);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * Writable test to see if a pathname is writable/creatable
+ *
+ * SYNOPSIS
+ *
+ * LOCAL BOOLEAN Writable (pathname)
+ * char *pathname;
+ *
+ * DESCRIPTION
+ *
+ * Because the debugger might be linked in with a program that
+ * runs with the set-uid-bit (suid) set, we have to be careful
+ * about opening a user named file for debug output. This consists
+ * of checking the file for write access with the real user id,
+ * or checking the directory where the file will be created.
+ *
+ * Returns TRUE if the user would normally be allowed write or
+ * create access to the named file. Returns FALSE otherwise.
+ *
+ */
+
+LOCAL BOOLEAN Writable (pathname)
+char *pathname;
+{
+ REGISTER BOOLEAN granted;
+#ifdef unix
+ REGISTER char *lastslash;
+#endif
+
+#ifndef unix
+ granted = TRUE;
+#else
+ granted = FALSE;
+ if (EXISTS (pathname)) {
+ if (WRITABLE (pathname)) {
+ granted = TRUE;
+ }
+ } else {
+ lastslash = strrchr (pathname, '/');
+ if (lastslash != NULL) {
+ *lastslash = EOS;
+ } else {
+ pathname = ".";
+ }
+ if (WRITABLE (pathname)) {
+ granted = TRUE;
+ }
+ if (lastslash != NULL) {
+ *lastslash = '/';
+ }
+ }
+#endif
+ return (granted);
+}
+
+
+/*
+ * This function may be eliminated when strrchr is available
+ * in the runtime environment (missing from BSD4.1).
+ * Alternately, you can use rindex() on BSD systems.
+ */
+
+LOCAL char *strrchr (s, c)
+char *s;
+char c;
+{
+ REGISTER char *scan;
+
+ for (scan = s; *scan != EOS; scan++) {;}
+ while (scan > s && *--scan != c) {;}
+ if (*scan != c) {
+ scan = NULL;
+ }
+ return (scan);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * ChangeOwner change owner to real user for suid programs
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID ChangeOwner (pathname)
+ *
+ * DESCRIPTION
+ *
+ * For unix systems, change the owner of the newly created debug
+ * file to the real owner. This is strictly for the benefit of
+ * programs that are running with the set-user-id bit set.
+ *
+ * Note that at this point, the fact that pathname represents
+ * a newly created file has already been established. If the
+ * program that the debugger is linked to is not running with
+ * the suid bit set, then this operation is redundant (but
+ * harmless).
+ *
+ */
+
+LOCAL VOID ChangeOwner (pathname)
+char *pathname;
+{
+#ifdef unix
+ if (chown (pathname, getuid (), getgid ()) == -1) {
+ (VOID) fprintf (stderr, ERR_CHOWN, _db_process_, pathname);
+ perror ("");
+ (VOID) fflush (stderr);
+ (VOID) XDelay (stack -> delay);
+ }
+#endif
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_setjmp_ save debugger environment
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_setjmp_ ()
+ *
+ * DESCRIPTION
+ *
+ * Invoked as part of the user's DBUG_SETJMP macro to save
+ * the debugger environment in parallel with saving the user's
+ * environment.
+ *
+ */
+
+VOID _db_setjmp_ ()
+{
+ jmplevel = stack -> level;
+ jmpfunc = func;
+ jmpfile = file;
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_longjmp_ restore previously saved debugger environment
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_longjmp_ ()
+ *
+ * DESCRIPTION
+ *
+ * Invoked as part of the user's DBUG_LONGJMP macro to restore
+ * the debugger environment in parallel with restoring the user's
+ * previously saved environment.
+ *
+ */
+
+VOID _db_longjmp_ ()
+{
+ stack -> level = jmplevel;
+ if (jmpfunc) {
+ func = jmpfunc;
+ }
+ if (jmpfile) {
+ file = jmpfile;
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DelayArg convert D flag argument to appropriate value
+ *
+ * SYNOPSIS
+ *
+ * LOCAL int DelayArg (value)
+ * int value;
+ *
+ * DESCRIPTION
+ *
+ * Converts delay argument, given in tenths of a second, to the
+ * appropriate numerical argument used by the system to delay
+ * that that many tenths of a second. For example, on the
+ * AMIGA, there is a system call "Delay()" which takes an
+ * argument in ticks (50 per second). On unix, the sleep
+ * command takes seconds. Thus a value of "10", for one
+ * second of delay, gets converted to 50 on the amiga, and 1
+ * on unix. Other systems will need to use a timing loop.
+ *
+ */
+
+LOCAL int DelayArg (value)
+int value;
+{
+ int delayarg = 0;
+
+#ifdef unix
+ delayarg = value / 10; /* Delay is in seconds for sleep () */
+#endif
+#ifdef AMIGA
+ delayarg = (HZ * value) / 10; /* Delay in ticks for XDelay () */
+#endif
+ return (delayarg);
+}
+
+
+/*
+ * A dummy delay stub for systems that do not support delays.
+ * With a little work, this can be turned into a timing loop.
+ */
+
+#ifndef unix
+#ifndef AMIGA
+XDelay ()
+{
+}
+#endif
+#endif
+
+
+/*
+ * FUNCTION
+ *
+ * perror perror simulation for systems that don't have it
+ *
+ * SYNOPSIS
+ *
+ * LOCAL VOID perror (s)
+ * char *s;
+ *
+ * DESCRIPTION
+ *
+ * Perror produces a message on the standard error stream which
+ * provides more information about the library or system error
+ * just encountered. The argument string s is printed, followed
+ * by a ':', a blank, and then a message and a newline.
+ *
+ * An undocumented feature of the unix perror is that if the string
+ * 's' is a null string (NOT a NULL pointer!), then the ':' and
+ * blank are not printed.
+ *
+ * This version just complains about an "unknown system error".
+ *
+ */
+
+#if !unix && !(AMIGA || LATTICE || __TURBOC__ )
+LOCAL VOID perror (s)
+#if __STDC__
+const char *s;
+#else
+char *s;
+#endif
+{
+ if (s && *s != EOS) {
+ (VOID) fprintf (stderr, "%s: ", s);
+ }
+ (VOID) fprintf (stderr, "<unknown system error>\n");
+}
+#endif /* !unix && !(AMIGA && LATTICE) */
+
+/*
+ * Here we need the definitions of the clock routine. Add your
+ * own for whatever system that you have.
+ */
+
+#if unix
+
+# include <sys/param.h>
+# if !defined(Solaris) && (BSD4_3 || sun)
+
+/*
+ * Definition of the Clock() routine for 4.3 BSD.
+ */
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+
+/*
+ * Returns the user time in milliseconds used by this process so
+ * far.
+ */
+
+LOCAL unsigned long Clock ()
+{
+ struct rusage ru;
+
+ (VOID) getrusage (RUSAGE_SELF, &ru);
+ return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000));
+}
+
+#else
+
+LOCAL unsigned long Clock ()
+{
+ return (0);
+}
+
+# endif
+
+#else
+
+#if AMIGA
+
+struct DateStamp { /* Yes, this is a hack, but doing it right */
+ long ds_Days; /* is incredibly ugly without splitting this */
+ long ds_Minute; /* off into a separate file */
+ long ds_Tick;
+};
+
+static int first_clock = TRUE;
+static struct DateStamp begin;
+static struct DateStamp elapsed;
+
+LOCAL unsigned long Clock ()
+{
+ register struct DateStamp *now;
+ register unsigned long millisec = 0;
+ extern VOID *AllocMem ();
+
+ now = (struct DateStamp *) AllocMem ((long) sizeof (struct DateStamp), 0L);
+ if (now != NULL) {
+ if (first_clock == TRUE) {
+ first_clock = FALSE;
+ (VOID) DateStamp (now);
+ begin = *now;
+ }
+ (VOID) DateStamp (now);
+ millisec = 24 * 3600 * (1000 / HZ) * (now -> ds_Days - begin.ds_Days);
+ millisec += 60 * (1000 / HZ) * (now -> ds_Minute - begin.ds_Minute);
+ millisec += (1000 / HZ) * (now -> ds_Tick - begin.ds_Tick);
+ (VOID) FreeMem (now, (long) sizeof (struct DateStamp));
+ }
+ return (millisec);
+}
+
+#else
+
+LOCAL unsigned long Clock ()
+{
+ return (0);
+}
+
+#endif /* AMIGA */
+
+#endif /* unix */
+
+#ifdef AMIGA
+XDelay(x)
+int x;
+{
+ if (x) Delay(x); /* fix Delay bug in AmigaDOS */
+}
+#endif
+
diff --git a/dmake/dbug/dbug/dbug.h b/dmake/dbug/dbug/dbug.h
new file mode 100644
index 000000000000..0f171e0d349f
--- /dev/null
+++ b/dmake/dbug/dbug/dbug.h
@@ -0,0 +1,164 @@
+/******************************************************************************
+ * *
+ * N O T I C E *
+ * *
+ * Copyright Abandoned, 1987, Fred Fish *
+ * *
+ * *
+ * This previously copyrighted work has been placed into the public *
+ * domain by the author and may be freely used for any purpose, *
+ * private or commercial. *
+ * *
+ * Because of the number of inquiries I was receiving about the use *
+ * of this product in commercially developed works I have decided to *
+ * simply make it public domain to further its unrestricted use. I *
+ * specifically would be most happy to see this material become a *
+ * part of the standard Unix distributions by AT&T and the Berkeley *
+ * Computer Science Research Group, and a standard part of the GNU *
+ * system from the Free Software Foundation. *
+ * *
+ * I would appreciate it, as a courtesy, if this notice is left in *
+ * all copies and derivative works. Thank you. *
+ * *
+ * The author makes no warranty of any kind with respect to this *
+ * product and explicitly disclaims any implied warranties of mer- *
+ * chantability or fitness for any particular purpose. *
+ * *
+ ******************************************************************************
+ */
+
+
+/*
+ * FILE
+ *
+ * dbug.h user include file for programs using the dbug package
+ *
+ * SYNOPSIS
+ *
+ * #include <local/dbug.h>
+ *
+ * SCCS ID
+ *
+ * @(#)dbug.h 1.11 9/5/87
+ *
+ * DESCRIPTION
+ *
+ * Programs which use the dbug package must include this file.
+ * It contains the appropriate macros to call support routines
+ * in the dbug runtime library.
+ *
+ * To disable compilation of the macro expansions define the
+ * preprocessor symbol "DBUG_OFF". This will result in null
+ * macros expansions so that the resulting code will be smaller
+ * and faster. (The difference may be smaller than you think
+ * so this step is recommended only when absolutely necessary).
+ * In general, tradeoffs between space and efficiency are
+ * decided in favor of efficiency since space is seldom a
+ * problem on the new machines).
+ *
+ * All externally visible symbol names follow the pattern
+ * "_db_xxx..xx_" to minimize the possibility of a dbug package
+ * symbol colliding with a user defined symbol.
+ *
+ * The DBUG_<N> style macros are obsolete and should not be used
+ * in new code. Macros to map them to instances of DBUG_PRINT
+ * are provided for compatibility with older code. They may go
+ * away completely in subsequent releases.
+ *
+ * AUTHOR
+ *
+ * Fred Fish
+ * (Currently employed by Motorola Computer Division, Tempe, Az.)
+ * hao!noao!mcdsun!fnf
+ * (602) 438-3614
+ *
+ */
+
+
+/*
+ * Internally used dbug variables which must be global.
+ */
+
+#ifndef DBUG_OFF
+ extern int _db_on_; /* TRUE if debug currently enabled */
+ extern FILE *_db_fp_; /* Current debug output stream */
+ extern char *_db_process_; /* Name of current process */
+ extern int _db_keyword_ (); /* Accept/reject keyword */
+ extern void _db_push_ (); /* Push state, set up new state */
+ extern void _db_pop_ (); /* Pop previous debug state */
+ extern void _db_enter_ (); /* New user function entered */
+ extern void _db_return_ (); /* User function return */
+ extern void _db_pargs_ (); /* Remember args for line */
+ extern void _db_doprnt_ (); /* Print debug output */
+ extern void _db_setjmp_ (); /* Save debugger environment */
+ extern void _db_longjmp_ (); /* Restore debugger environment */
+# endif
+
+
+/*
+ * These macros provide a user interface into functions in the
+ * dbug runtime support library. They isolate users from changes
+ * in the MACROS and/or runtime support.
+ *
+ * The symbols "__LINE__" and "__FILE__" are expanded by the
+ * preprocessor to the current source file line number and file
+ * name respectively.
+ *
+ * WARNING --- Because the DBUG_ENTER macro allocates space on
+ * the user function's stack, it must precede any executable
+ * statements in the user function.
+ *
+ */
+
+# ifdef DBUG_OFF
+# define DBUG_ENTER(a1)
+# define DBUG_MALLOC(a1)
+# define DBUG_RETURN(a1) return(a1)
+# define DBUG_VOID_RETURN return
+# define DBUG_EXECUTE(keyword,a1)
+# define DBUG_PRINT(keyword,arglist)
+# define DBUG_2(keyword,format) /* Obsolete */
+# define DBUG_3(keyword,format,a1) /* Obsolete */
+# define DBUG_4(keyword,format,a1,a2) /* Obsolete */
+# define DBUG_5(keyword,format,a1,a2,a3) /* Obsolete */
+# define DBUG_PUSH(a1)
+# define DBUG_POP()
+# define DBUG_PROCESS(a1)
+# define DBUG_FILE (stderr)
+# define DBUG_SETJMP setjmp
+# define DBUG_LONGJMP longjmp
+# else
+# define DBUG_ENTER(a) \
+ auto char *_db_func_, *_db_file_; \
+ int _db_level_; \
+ _db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_)
+# define DBUG_MALLOC(a) \
+ auto char *_db_func_, *_db_file_; \
+ int _db_level_; \
+ malloc_init();\
+ _db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_)
+# define DBUG_LEAVE \
+ (_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_))
+# define DBUG_RETURN(a1) return (DBUG_LEAVE, (a1))
+/* define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);} Alternate form */
+# define DBUG_VOID_RETURN DBUG_LEAVE; return
+# define DBUG_EXECUTE(keyword,a1) \
+ {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
+# define DBUG_PRINT(keyword,arglist) \
+ {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}}
+# define DBUG_2(keyword,format) \
+ DBUG_PRINT(keyword,(format)) /* Obsolete */
+# define DBUG_3(keyword,format,a1) \
+ DBUG_PRINT(keyword,(format,a1)) /* Obsolete */
+# define DBUG_4(keyword,format,a1,a2) \
+ DBUG_PRINT(keyword,(format,a1,a2)) /* Obsolete */
+# define DBUG_5(keyword,format,a1,a2,a3) \
+ DBUG_PRINT(keyword,(format,a1,a2,a3)) /* Obsolete */
+# define DBUG_PUSH(a1) _db_push_ (a1)
+# define DBUG_POP() _db_pop_ ()
+# define DBUG_PROCESS(a1) (_db_process_ = a1)
+# define DBUG_FILE (_db_fp_)
+# define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
+# define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
+# endif
+
diff --git a/dmake/dbug/dbug/dbug.txt b/dmake/dbug/dbug/dbug.txt
new file mode 100755
index 000000000000..ec032f61ebff
--- /dev/null
+++ b/dmake/dbug/dbug/dbug.txt
@@ -0,0 +1,1452 @@
+
+
+
+
+
+
+ D B U G
+
+ C Program Debugging Package
+
+ by
+ Fred Fish
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 1 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ INTRODUCTION
+
+
+ Almost every program development environment worthy of
+ the name provides some sort of debugging facility. Usually
+ this takes the form of a program which is capable of
+ controlling execution of other programs and examining the
+ internal state of other executing programs. These types of
+ programs will be referred to as external debuggers since the
+ debugger is not part of the executing program. Examples of
+ this type of debugger include the adb and sdb debuggers
+ provided with the UNIX1 operating system.
+
+
+ One of the problems associated with developing programs
+ in an environment with good external debuggers is that
+ developed programs tend to have little or no internal
+ instrumentation. This is usually not a problem for the
+ developer since he is, or at least should be, intimately
+ familiar with the internal organization, data structures,
+ and control flow of the program being debugged. It is a
+ serious problem for maintenance programmers, who are
+ unlikely to have such familiarity with the program being
+ maintained, modified, or ported to another environment. It
+ is also a problem, even for the developer, when the program
+ is moved to an environment with a primitive or unfamiliar
+ debugger, or even no debugger.
+
+
+ On the other hand, dbug is an example of an internal
+ debugger. Because it requires internal instrumentation of a
+ program, and its usage does not depend on any special
+ capabilities of the execution environment, it is always
+ available and will execute in any environment that the
+ program itself will execute in. In addition, since it is a
+ complete package with a specific user interface, all
+ programs which use it will be provided with similar
+ debugging capabilities. This is in sharp contrast to other
+ forms of internal instrumentation where each developer has
+ their own, usually less capable, form of internal debugger.
+ In summary, because dbug is an internal debugger it provides
+ consistency across operating environments, and because it is
+ available to all developers it provides consistency across
+ all programs in the same environment.
+
+
+ The dbug package imposes only a slight speed penalty on
+ executing programs, typically much less than 10 percent, and
+ a modest size penalty, typically 10 to 20 percent. By
+ defining a specific C preprocessor symbol both of these can
+ be reduced to zero with no changes required to the source
+
+ ____________________
+
+ 1. UNIX is a trademark of AT&T Bell Laboratories.
+
+ - 2 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ code.
+
+
+ The following list is a quick summary of the
+ capabilities of the dbug package. Each capability can be
+ individually enabled or disabled at the time a program is
+ invoked by specifying the appropriate command line
+ arguments.
+
+ o Execution trace showing function level control
+ flow in a semi-graphically manner using
+ indentation to indicate nesting depth.
+
+ o Output the values of all, or any subset of, key
+ internal variables.
+
+ o Limit actions to a specific set of named
+ functions.
+
+ o Limit function trace to a specified nesting depth.
+
+ o Label each output line with source file name and
+ line number.
+
+ o Label each output line with name of current
+ process.
+
+ o Push or pop internal debugging state to allow
+ execution with built in debugging defaults.
+
+ o Redirect the debug output stream to standard
+ output (stdout) or a named file. The default
+ output stream is standard error (stderr). The
+ redirection mechanism is completely independent of
+ normal command line redirection to avoid output
+ conflicts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 3 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ PRIMITIVE DEBUGGING TECHNIQUES
+
+
+ Internal instrumentation is already a familiar concept
+ to most programmers, since it is usually the first debugging
+ technique learned. Typically, "print statements" are
+ inserted in the source code at interesting points, the code
+ is recompiled and executed, and the resulting output is
+ examined in an attempt to determine where the problem is.
+
+ The procedure is iterative, with each iteration yielding
+ more and more output, and hopefully the source of the
+ problem is discovered before the output becomes too large to
+ deal with or previously inserted statements need to be
+ removed. Figure 1 is an example of this type of primitive
+ debugging technique.
+
+
+
+ #include <stdio.h>
+
+ main (argc, argv)
+ int argc;
+ char *argv[];
+ {
+ printf ("argv[0] = %d\n", argv[0]);
+ /*
+ * Rest of program
+ */
+ printf ("== done ==\n");
+ }
+
+
+ Figure 1
+ Primitive Debugging Technique
+
+
+
+
+
+ Eventually, and usually after at least several
+ iterations, the problem will be found and corrected. At
+ this point, the newly inserted print statements must be
+ dealt with. One obvious solution is to simply delete them
+ all. Beginners usually do this a few times until they have
+ to repeat the entire process every time a new bug pops up.
+ The second most obvious solution is to somehow disable the
+ output, either through the source code comment facility,
+ creation of a debug variable to be switched on or off, or by
+ using the C preprocessor. Figure 2 is an example of all
+ three techniques.
+
+
+
+
+
+ - 4 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ #include <stdio.h>
+
+ int debug = 0;
+
+ main (argc, argv)
+ int argc;
+ char *argv[];
+ {
+ /* printf ("argv = %x\n", argv) */
+ if (debug) printf ("argv[0] = %d\n", argv[0]);
+ /*
+ * Rest of program
+ */
+ #ifdef DEBUG
+ printf ("== done ==\n");
+ #endif
+ }
+
+
+ Figure 2
+ Debug Disable Techniques
+
+
+
+
+
+ Each technique has its advantages and disadvantages
+ with respect to dynamic vs static activation, source code
+ overhead, recompilation requirements, ease of use, program
+ readability, etc. Overuse of the preprocessor solution
+ quickly leads to problems with source code readability and
+ maintainability when multiple #ifdef symbols are to be
+ defined or undefined based on specific types of debug
+ desired. The source code can be made slightly more readable
+ by suitable indentation of the #ifdef arguments to match the
+ indentation of the code, but not all C preprocessors allow
+ this. The only requirement for the standard UNIX C
+ preprocessor is for the '#' character to appear in the first
+ column, but even this seems like an arbitrary and
+ unreasonable restriction. Figure 3 is an example of this
+ usage.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 5 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ #include <stdio.h>
+
+ main (argc, argv)
+ int argc;
+ char *argv[];
+ {
+ # ifdef DEBUG
+ printf ("argv[0] = %d\n", argv[0]);
+ # endif
+ /*
+ * Rest of program
+ */
+ # ifdef DEBUG
+ printf ("== done ==\n");
+ # endif
+ }
+
+
+ Figure 3
+ More Readable Preprocessor Usage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 6 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ FUNCTION TRACE EXAMPLE
+
+
+ We will start off learning about the capabilities of
+ the dbug package by using a simple minded program which
+ computes the factorial of a number. In order to better
+ demonstrate the function trace mechanism, this program is
+ implemented recursively. Figure 4 is the main function for
+ this factorial program.
+
+
+
+ #include <stdio.h>
+ /* User programs should use <local/dbug.h> */
+ #include "dbug.h"
+
+ int main (argc, argv)
+ int argc;
+ char *argv[];
+ {
+ register int result, ix;
+ extern int factorial (), atoi ();
+
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
+ switch (argv[ix][1]) {
+ case '#':
+ DBUG_PUSH (&(argv[ix][2]));
+ break;
+ }
+ }
+ for (; ix < argc; ix++) {
+ DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
+ result = factorial (atoi (argv[ix]));
+ printf ("%d\n", result);
+ }
+ DBUG_RETURN (0);
+ }
+
+
+ Figure 4
+ Factorial Program Mainline
+
+
+
+
+
+ The main function is responsible for processing any
+ command line option arguments and then computing and
+ printing the factorial of each non-option argument.
+
+ First of all, notice that all of the debugger functions
+ are implemented via preprocessor macros. This does not
+
+
+ - 7 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ detract from the readability of the code and makes disabling
+ all debug compilation trivial (a single preprocessor symbol,
+ DBUG_OFF, forces the macro expansions to be null).
+
+ Also notice the inclusion of the header file dbug.h
+ from the local header file directory. (The version included
+ here is the test version in the dbug source distribution
+ directory). This file contains all the definitions for the
+ debugger macros, which all have the form DBUG_XX...XX.
+
+
+ The DBUG_ENTER macro informs that debugger that we have
+ entered the function named main. It must be the very first
+ "executable" line in a function, after all declarations and
+ before any other executable line. The DBUG_PROCESS macro is
+ generally used only once per program to inform the debugger
+ what name the program was invoked with. The DBUG_PUSH macro
+ modifies the current debugger state by saving the previous
+ state and setting a new state based on the control string
+ passed as its argument. The DBUG_PRINT macro is used to
+ print the values of each argument for which a factorial is
+ to be computed. The DBUG_RETURN macro tells the debugger
+ that the end of the current function has been reached and
+ returns a value to the calling function. All of these
+ macros will be fully explained in subsequent sections.
+
+ To use the debugger, the factorial program is invoked
+ with a command line of the form:
+
+ factorial -#d:t 1 2 3
+
+ The main function recognizes the "-#d:t" string as a
+ debugger control string, and passes the debugger arguments
+ ("d:t") to the dbug runtime support routines via the
+ DBUG_PUSH macro. This particular string enables output from
+ the DBUG_PRINT macro with the 'd' flag and enables function
+ tracing with the 't' flag. The factorial function is then
+ called three times, with the arguments "1", "2", and "3".
+ Note that the DBUG_PRINT takes exactly two arguments, with
+ the second argument (a format string and list of printable
+ values) enclosed in parenthesis.
+
+ Debug control strings consist of a header, the "-#",
+ followed by a colon separated list of debugger arguments.
+ Each debugger argument is a single character flag followed
+ by an optional comma separated list of arguments specific to
+ the given flag. Some examples are:
+
+ -#d:t:o
+ -#d,in,out:f,main:F:L
+
+ Note that previously enabled debugger actions can be
+ disabled by the control string "-#".
+
+
+
+ - 8 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ The definition of the factorial function, symbolized as
+ "N!", is given by:
+
+ N! = N * N-1 * ... 2 * 1
+
+ Figure 5 is the factorial function which implements this
+ algorithm recursively. Note that this is not necessarily
+ the best way to do factorials and error conditions are
+ ignored completely.
+
+
+
+ #include <stdio.h>
+ /* User programs should use <local/dbug.h> */
+ #include "dbug.h"
+
+ int factorial (value)
+ register int value;
+ {
+ DBUG_ENTER ("factorial");
+ DBUG_PRINT ("find", ("find %d factorial", value));
+ if (value > 1) {
+ value *= factorial (value - 1);
+ }
+ DBUG_PRINT ("result", ("result is %d", value));
+ DBUG_RETURN (value);
+ }
+
+
+ Figure 5
+ Factorial Function
+
+
+
+
+
+ One advantage (some may not consider it so) to using
+ the dbug package is that it strongly encourages fully
+ structured coding with only one entry and one exit point in
+ each function. Multiple exit points, such as early returns
+ to escape a loop, may be used, but each such point requires
+ the use of an appropriate DBUG_RETURN or DBUG_VOID_RETURN
+ macro.
+
+
+ To build the factorial program on a UNIX system,
+ compile and link with the command:
+
+ cc -o factorial main.c factorial.c -ldbug
+
+ The "-ldbug" argument tells the loader to link in the
+ runtime support modules for the dbug package. Executing the
+ factorial program with a command of the form:
+
+
+
+ - 9 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ factorial 1 2 3 4 5
+
+ generates the output shown in figure 6.
+
+
+
+ 1
+ 2
+ 6
+ 24
+ 120
+ Figure 6
+ factorial 1 2 3 4 5
+
+
+
+
+
+ Function level tracing is enabled by passing the
+ debugger the 't' flag in the debug control string. Figure 7
+ is the output resulting from the command
+ "factorial -#t:o 3 2".
+
+
+
+ | >factorial
+ | | >factorial
+ | | <factorial
+ | <factorial
+ 2
+ | >factorial
+ | | >factorial
+ | | | >factorial
+ | | | <factorial
+ | | <factorial
+ | <factorial
+ 6
+ <main
+
+
+ Figure 7
+ factorial -#t:o 3 2
+
+
+
+
+
+ Each entry to or return from a function is indicated by
+ '>' for the entry point and '<' for the exit point,
+ connected by vertical bars to allow matching points to be
+ easily found when separated by large distances.
+
+
+ This trace output indicates that there was an initial
+
+
+ - 10 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ call to factorial from main (to compute 2!), followed by a
+ single recursive call to factorial to compute 1!. The main
+ program then output the result for 2! and called the
+ factorial function again with the second argument, 3.
+ Factorial called itself recursively to compute 2! and 1!,
+ then returned control to main, which output the value for 3!
+ and exited.
+
+
+ Note that there is no matching entry point "main>" for
+ the return point "<main" because at the time the DBUG_ENTER
+ macro was reached in main, tracing was not enabled yet. It
+ was only after the macro DBUG_PUSH was executing that
+ tracing became enabled. This implies that the argument list
+ should be processed as early as possible since all code
+ preceding the first call to DBUG_PUSH is essentially
+ invisible to dbug (this can be worked around by inserting a
+ temporary DBUG_PUSH(argv[1]) immediately after the
+ DBUG_ENTER("main") macro.
+
+
+ One last note, the trace output normally comes out on
+ the standard error. Since the factorial program prints its
+ result on the standard output, there is the possibility of
+ the output on the terminal being scrambled if the two
+ streams are not synchronized. Thus the debugger is told to
+ write its output on the standard output instead, via the 'o'
+ flag character. Note that no 'o' implies the default
+ (standard error), a 'o' with no arguments means standard
+ output, and a 'o' with an argument means used the named
+ file. I.E, "factorial -#t:o,logfile 3 2" would write the
+ trace output in "logfile". Because of UNIX implementation
+ details, programs usually run faster when writing to stdout
+ rather than stderr, though this is not a prime consideration
+ in this example.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 11 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ USE OF DBUG_PRINT MACRO
+
+
+ The mechanism used to produce "printf" style output is
+ the DBUG_PRINT macro.
+
+
+ To allow selection of output from specific macros, the
+ first argument to every DBUG_PRINT macro is a dbug keyword.
+ When this keyword appears in the argument list of the 'd'
+ flag in a debug control string, as in
+ "-#d,keyword1,keyword2,...:t", output from the corresponding
+ macro is enabled. The default when there is no 'd' flag in
+ the control string is to enable output from all DBUG_PRINT
+ macros.
+
+
+ Typically, a program will be run once, with no keywords
+ specified, to determine what keywords are significant for
+ the current problem (the keywords are printed in the macro
+ output line). Then the program will be run again, with the
+ desired keywords, to examine only specific areas of
+ interest.
+
+
+ The second argument to a DBUG_PRINT macro is a standard
+ printf style format string and one or more arguments to
+ print, all enclosed in parenthesis so that they collectively
+ become a single macro argument. This is how variable
+ numbers of printf arguments are supported. Also note that
+ no explicit newline is required at the end of the format
+ string. As a matter of style, two or three small DBUG_PRINT
+ macros are preferable to a single macro with a huge format
+ string. Figure 8 shows the output for default tracing and
+ debug.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 12 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ | args: argv[2] = 3
+ | >factorial
+ | | find: find 3 factorial
+ | | >factorial
+ | | | find: find 2 factorial
+ | | | >factorial
+ | | | | find: find 1 factorial
+ | | | | result: result is 1
+ | | | <factorial
+ | | | result: result is 2
+ | | <factorial
+ | | result: result is 6
+ | <factorial
+ 6
+ <main
+
+
+ Figure 8
+ factorial -#d:t:o 3
+
+
+
+
+
+ The output from the DBUG_PRINT macro is indented to
+ match the trace output for the function in which the macro
+ occurs. When debugging is enabled, but not trace, the
+ output starts at the left margin, without indentation.
+
+
+ To demonstrate selection of specific macros for output,
+ figure 9 shows the result when the factorial program is
+ invoked with the debug control string "-#d,result:o".
+
+
+
+ factorial: result: result is 1
+ factorial: result: result is 2
+ factorial: result: result is 6
+ factorial: result: result is 24
+ 24
+ Figure 9
+ factorial -#d,result:o 4
+
+
+
+
+
+ It is sometimes desirable to restrict debugging and
+ trace actions to a specific function or list of functions.
+ This is accomplished with the 'f' flag character in the
+ debug control string. Figure 10 is the output of the
+ factorial program when run with the control string
+ "-#d:f,factorial:F:L:o". The 'F' flag enables printing of
+
+
+ - 13 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ the source file name and the 'L' flag enables printing of
+ the source file line number.
+
+
+
+ factorial.c: 9: factorial: find: find 3 factorial
+ factorial.c: 9: factorial: find: find 2 factorial
+ factorial.c: 9: factorial: find: find 1 factorial
+ factorial.c: 13: factorial: result: result is 1
+ factorial.c: 13: factorial: result: result is 2
+ factorial.c: 13: factorial: result: result is 6
+ 6
+
+
+ Figure 10
+ factorial -#d:f,factorial:F:L:o 3
+
+
+
+
+
+ The output in figure 10 shows that the "find" macro is
+ in file "factorial.c" at source line 8 and the "result"
+ macro is in the same file at source line 12.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 14 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ SUMMARY OF MACROS
+
+
+ This section summarizes the usage of all currently
+ defined macros in the dbug package. The macros definitions
+ are found in the user include file dbug.h from the standard
+ include directory.
+
+
+
+ DBUG_ENTER Used to tell the runtime support module
+ the name of the function being entered.
+ The argument must be of type "pointer to
+ character". The DBUG_ENTER macro must
+ precede all executable lines in the
+ function just entered, and must come
+ after all local declarations. Each
+ DBUG_ENTER macro must have a matching
+ DBUG_RETURN or DBUG_VOID_RETURN macro at
+ the function exit points. DBUG_ENTER
+ macros used without a matching
+ DBUG_RETURN or DBUG_VOID_RETURN macro
+ will cause warning messages from the
+ dbug package runtime support module.
+
+ EX: DBUG_ENTER ("main");
+
+ DBUG_RETURN Used at each exit point of a function
+ containing a DBUG_ENTER macro at the
+ entry point. The argument is the value
+ to return. Functions which return no
+ value (void) should use the
+ DBUG_VOID_RETURN macro. It is an error
+ to have a DBUG_RETURN or
+ DBUG_VOID_RETURN macro in a function
+ which has no matching DBUG_ENTER macro,
+ and the compiler will complain if the
+ macros are actually used (expanded).
+
+ EX: DBUG_RETURN (value);
+ EX: DBUG_VOID_RETURN;
+
+ DBUG_PROCESS Used to name the current process being
+ executed. A typical argument for this
+ macro is "argv[0]", though it will be
+ perfectly happy with any other string.
+
+ EX: DBUG_PROCESS (argv[0]);
+
+ DBUG_PUSH Sets a new debugger state by pushing the
+ current dbug state onto an internal
+ stack and setting up the new state using
+ the debug control string passed as the
+ macro argument. The most common usage
+
+
+ - 15 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ is to set the state specified by a debug
+ control string retrieved from the
+ argument list. Note that the leading
+ "-#" in a debug control string specified
+ as a command line argument must not be
+ passed as part of the macro argument.
+ The proper usage is to pass a pointer to
+ the first character after the "-#"
+ string.
+
+ EX: DBUG_PUSH ((argv[i][2]));
+ EX: DBUG_PUSH ("d:t");
+ EX: DBUG_PUSH ("");
+
+ DBUG_POP Restores the previous debugger state by
+ popping the state stack. Attempting to
+ pop more states than pushed will be
+ ignored and no warning will be given.
+ The DBUG_POP macro has no arguments.
+
+ EX: DBUG_POP ();
+
+ DBUG_FILE The DBUG_FILE macro is used to do
+ explicit I/O on the debug output stream.
+ It is used in the same manner as the
+ symbols "stdout" and "stderr" in the
+ standard I/O package.
+
+ EX: fprintf (DBUG_FILE, "Doing my own
+ I/O!\n");
+
+ DBUG_EXECUTE The DBUG_EXECUTE macro is used to
+ execute any arbitrary C code. The first
+ argument is the debug keyword, used to
+ trigger execution of the code specified
+ as the second argument. This macro must
+ be used cautiously because, like the
+ DBUG_PRINT macro, it is automatically
+ selected by default whenever the 'd'
+ flag has no argument list (I.E., a
+ "-#d:t" control string).
+
+ EX: DBUG_EXECUTE ("abort", abort ());
+
+ DBUG_N These macros, where N is in the range
+ 2-5, are currently obsolete and will be
+ removed in a future release. Use the
+ new DBUG_PRINT macro.
+
+ DBUG_PRINT Used to do printing via the "fprintf"
+ library function on the current debug
+ stream, DBUG_FILE. The first argument
+ is a debug keyword, the second is a
+ format string and the corresponding
+
+
+ - 16 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ argument list. Note that the format
+ string and argument list are all one
+ macro argument and must be enclosed in
+ parenthesis.
+
+ EX: DBUG_PRINT ("eof", ("end of file found"));
+ EX: DBUG_PRINT ("type", ("type is %x",
+ type));
+ EX: DBUG_PRINT ("stp", ("%x -> %s", stp,
+ stp -> name));
+
+ DBUG_SETJMP Used in place of the setjmp() function
+ to first save the current debugger state
+ and then execute the standard setjmp
+ call. This allows to the debugger to
+ restore it's state when the DBUG_LONGJMP
+ macro is used to invoke the standard
+ longjmp() call. Currently all instances
+ of DBUG_SETJMP must occur within the
+ same function and at the same function
+ nesting level.
+
+ EX: DBUG_SETJMP (env);
+
+ DBUG_LONGJMP Used in place of the longjmp() function
+ to first restore the previous debugger
+ state at the time of the last
+ DBUG_SETJMP and then execute the
+ standard longjmp() call. Note that
+ currently all DBUG_LONGJMP macros
+ restore the state at the time of the
+ last DBUG_SETJMP. It would be possible
+ to maintain separate DBUG_SETJMP and
+ DBUG_LONGJMP pairs by having the
+ debugger runtime support module use the
+ first argument to differentiate the
+ pairs.
+
+ EX: DBUG_LONGJMP (env,val);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 17 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ DEBUG CONTROL STRING
+
+
+ The debug control string is used to set the state of
+ the debugger via the DBUG_PUSH macro. This section
+ summarizes the currently available debugger options and the
+ flag characters which enable or disable them. Argument
+ lists enclosed in '[' and ']' are optional.
+
+
+ d[,keywords] Enable output from macros with
+ specified keywords. A null list of
+ keywords implies that all keywords are
+ selected.
+
+ D[,time] Delay for specified time after each
+ output line, to let output drain.
+ Time is given in tenths of a second
+ (value of 10 is one second). Default
+ is zero.
+
+ f[,functions] Limit debugger actions to the
+ specified list of functions. A null
+ list of functions implies that all
+ functions are selected.
+
+ F Mark each debugger output line with
+ the name of the source file containing
+ the macro causing the output.
+
+ L Mark each debugger output line with
+ the source file line number of the
+ macro causing the output.
+
+ n Mark each debugger output line with
+ the current function nesting depth.
+
+ N Sequentially number each debugger
+ output line starting at 1. This is
+ useful for reference purposes when
+ debugger output is interspersed with
+ program output.
+
+ o[,file] Redirect the debugger output stream to
+ the specified file. The default
+ output stream is stderr. A null
+ argument list causes output to be
+ redirected to stdout.
+
+ p[,processes] Limit debugger actions to the
+ specified processes. A null list
+ implies all processes. This is useful
+ for processes which run child
+ processes. Note that each debugger
+
+
+ - 18 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ output line can be marked with the
+ name of the current process via the
+ 'P' flag. The process name must match
+ the argument passed to the
+ DBUG_PROCESS macro.
+
+ P Mark each debugger output line with
+ the name of the current process. Most
+ useful when used with a process which
+ runs child processes that are also
+ being debugged. Note that the parent
+ process must arrange for the debugger
+ control string to be passed to the
+ child processes.
+
+ r Used in conjunction with the DBUG_PUSH
+ macro to reset the current indentation
+ level back to zero. Most useful with
+ DBUG_PUSH macros used to temporarily
+ alter the debugger state.
+
+ t[,N] Enable function control flow tracing.
+ The maximum nesting depth is specified
+ by N, and defaults to 200.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 19 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ HINTS AND MISCELLANEOUS
+
+
+ One of the most useful capabilities of the dbug package
+ is to compare the executions of a given program in two
+ different environments. This is typically done by executing
+ the program in the environment where it behaves properly and
+ saving the debugger output in a reference file. The program
+ is then run with identical inputs in the environment where
+ it misbehaves and the output is again captured in a
+ reference file. The two reference files can then be
+ differentially compared to determine exactly where execution
+ of the two processes diverges.
+
+
+ A related usage is regression testing where the
+ execution of a current version is compared against
+ executions of previous versions. This is most useful when
+ there are only minor changes.
+
+
+ It is not difficult to modify an existing compiler to
+ implement some of the functionality of the dbug package
+ automatically, without source code changes to the program
+ being debugged. In fact, such changes were implemented in a
+ version of the Portable C Compiler by the author in less
+ than a day. However, it is strongly encouraged that all
+ newly developed code continue to use the debugger macros for
+ the portability reasons noted earlier. The modified
+ compiler should be used only for testing existing programs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 20 -
+
+
+
+
+
+ DBUG User Manual October 29, 1986
+
+
+
+ CAVEATS
+
+
+ The dbug package works best with programs which have
+ "line oriented" output, such as text processors, general
+ purpose utilities, etc. It can be interfaced with screen
+ oriented programs such as visual editors by redefining the
+ appropriate macros to call special functions for displaying
+ the debugger results. Of course, this caveat is not
+ applicable if the debugger output is simply dumped into a
+ file for post-execution examination.
+
+
+ Programs which use memory allocation functions other
+ than malloc will usually have problems using the standard
+ dbug package. The most common problem is multiply allocated
+ memory.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 21 -
+
+
+
+
+
+
+
+
+ D B U G
+ C Program Debugging Package
+
+ by
+ Fred Fish
+
+
+
+ ABSTRACT
+
+
+ This document introduces dbug, a macro based C debugging
+ package which 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.
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 22 -
+
+
diff --git a/dmake/dbug/dbug/dbug.uue b/dmake/dbug/dbug/dbug.uue
new file mode 100644
index 000000000000..da8743b7e128
--- /dev/null
+++ b/dmake/dbug/dbug/dbug.uue
@@ -0,0 +1,368 @@
+begin 650 dbug.Z
+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
+M!P4((( $6!54016O@A1-@ +V( )F 1G$14/: 4(0($66 0(@($:^!%<T8%$
+MH($9F(%"@ C6(*J$A9'@ IN((KJ((J^("MPA0MN((M@A91 8(:6!9D019(
+M@ ]^(,QZ$]KD111@ !%>(0G"!8XF(%3@ !-^(3O9Q"@A#$=(E0><T2FAD<\
+M(4J%13O8M#6UUC-P<'JC821W\4YJ$CJ0=4HZ='>ND57&9AW,\REZD7<GH3$:
+M4AX-YD/P\1ZFHRR(@UMYX"W[M1S#) (!=!EKIR'K,@<B0!"F4V4&441^<2U\
+M EM+@W,B)B^E431")%\H\GV/Q5T_0Q^',3\GAGR_42I/A%W.$UF%1S>F5SB3
+M]W2#=A IE#6 ^%KF92V,.(;P=!A+HHLU-R)6DAH9(3- 8W0$(606AF))54Y+
+M$C)],3I3YW)>$QR*Q7V.EAC*<X<(<1=)!8OPI1EW@GA0\T0*(S"NQE^%=W.H
+MQ"Q7PD0Q4SFJA&?TT1<WYB,T<XQ-IWIZ\5:Q02-%8B391$M%LD!CTRY>0WL4
+M)AE+,P<LLS&/8XD>0C6-:!K0121&XB,:PQ/UTQ,L A2>EE0==4+[H4(2(X_[
+M,H@LY#D9!V>26!!VB!)YB 9[6 >AMU,Y,0)4\B>!P@.7%R N@ 8^P&\Q,3RU
+M9SIG, 9.U&EVD *]ER%'TFECL /CMS 'H@),:0=;T 58Z5)[T'M<ER'<@0(B
+MT)5; -= (] (E0 9<X 8B\)1GX)5LF0)AB7\@\ (J0)8%H0(#$7CO9!MJ
+M I@$H0(O@)@(8I:U)P(]\)96I"QNV0-S*0)ZV7M]$(5\B1 D.3>E$0.,61 8
+M$9,- Q);0B%4,'PY^1(@)1-%T!>/(6?I>#!PZ(Y'8@9+ HD+YX=(]AJ(P1$Q
+MA"'32''YQ3N44RQ25TB#<SFIXQ-/1!]8UQ_7PB)!0(8'P1G/47890HJEH2QW
+M,)&4N!FETIB7<9&,V#_TDS+LXI$(<1C3)77;1A#)LBQB )&2 QM_(FW[8B37
+M!"> <1BO=(QM8#?*44-EH!O)]H8JXXY65"'?PQME\#=^]H:/\1M?XQD+TQ=X
+MF# \,2.15"87FE3/B%C!"1A^)C[@21,C 3UP\(9P4$$((60PDC<^<8:U<9^1
+M(R5[<R("TI^ST1BK]C>&$12:164:4XMT #6$8R"[DQ$CX34ZEHFH9(J;"#J/
+M%$QIE <LP$I;*&U*9'CX5BW/ D\F-@?94AZEDD0' AIFD&Z)ACH\HQ]M9!$(
+M4F%=1QVP470$\9E))0-WE9*NM"SG5DS-P1,QPIIIP(<5AY2=>1 ;-0/MYWX:
+M,U(E=5+TMU(+^:@% 5-%LG\T95/_YWXNY9-] I2E(92W1Y1&Z:@30943Y)8@
+M -8V7M*B0),Z915>9=2Z6R7D:M[F1,QMI5J"9:]-Y:=Z9?F20=GF990*:LE
+M@ >7:9=1"0**R9C+4WL3I'F)R*R/J99L":UR29?4NI9=D)G)^I>/*IB )U\A
+M<ICKNIBENCRD]Q%%$'^,V:W-&IF&41^E$9F7B:X9-0+.MSR:R9F<VJ=I4)*E
+M(0.CJ1 ,]!%&6J:KJ8>+JI.@\IHQ401F=I.M"57-)">BY$?$,V/E,B]X-K(-
+M$ATSIC&V1#=BQ"[X0P9YT'F[! )V("4?<K,J04!&94I4NHFGB!"KX1<6(DI"
+M WRQX2V )&TU!D2-6#Y(0JB]!"-0 Z\'L85LDV:XPZ1T, 8D\P3ZR$Q3UD84
+M5J)[.AO[*3(:LV0KL55'0P;5823)N2 ,.1L\)K3PH;58ACLG*SS%0SPFT;?4
+ME4SO U^SN$(#,0((P+B.FP8( +F2:P8(0+F6>RF*4@8(H+F<:[F56[E.E@<;
+MMC<B.XZNXYX'07K&8V<4\YP+MKJ_,[7SXD4'%V&"XI)R@B<,M$!3,B2B]S/P
+MJ+=G9BXF-C6!(I$+VUPL(XX_$K>:I3$UH5;!<:3,%VVF)H^EX;B-V[B2&[F1
+MZ[F7BRF9N[GDNV"?:[F[^FE1!$]3\[6H,H\'4;T[ZT5L5(J<Z%;B]B5ZT5D3
+M]J%YBF'YXG9W@(<FLWN\@UR>\;0@^4B70S$Z%AV/%WO%L2IA$80/."NR(BL$
+M,03&A*=OX'68\QSH8QTG, (GD!Y:V;-[,CV2=C1=TG$_,X=Y 5A_T@97]3M/
+M!T$0*B<P BT.DP;3 8EQ5)5H-%!_(<21=Q"ILX6P<1IE>F(=8WXB0S)^"A^2
+MBI*YJ+@LN5H&,45D1JD:F[ )L5$T,*FD>A"6*G\H57_W)\8#X:DR=2"AZG\Y
+M=<8]^9. DJI#^09%>92V&KA+:974VJL9197 FI6F8ZW%&JPX@:P#.RYF4*\?
+MB*^=J:_?"I7F*J[3NJMX>:Z,/!,C$'=O%GWXYY>CR:Z$"7V!=LKR^LCG$<D+
+M9J^4S)>6C);\.IG_:IET*; ]*<K*0\HXL9FNZL95# (S\+!-8([M*DI'BA$>
+M#,('8AQ4!,;47,UV[,8&L5$U8,9A7!!IC*D'PL:;*L9P#*K]=U-U_'Y&@ #K
+MW,Y)V$]QT10Z:!8VF!9#R!9ND15!6(,1:(!5$00( - "/<]DL81% (&C<&S
+M(M !'= -R( ,2( #.(!,@ 5?=$&C; #<04UQR,7.29N*FLNW&"[$5%/UT9>
+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
+MF/P\/M$$^,Y/Z(1.^(,^Z(,H@ H@ H@ "XNNB&(@<(( <(( <(T&E:_UMV
+M@ !V@ !V@ !>B0!;@ !;@ .CBNX@BM=@ !=@ !=@ #GB@ I@ I@ ":=QY8
+MJCQ4,Y'=H9M/A:0BU?$CM?HAW_HEY8(KF/S3'8(:R/SU;-TAJ('0+P4H@ H
+M@ H@ !HB0 B@ B@ B</Z)ONCK[[V._OZ1+@((( ((( ((@)D(D ((D ((
+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
+M@ !O@ !@@@!T@ !T@ !.9.<RA[2PHJN(2:J##^?7SJ=IKXRZL;.F!&^<M/#
+M!:3L@5@ )(J[F9#8O-75SB[#JL(4H_Z% KZ52P<(0 <(0 <(H"'EN[ER@ !R
+M@ !R@ .S#L@( (M, *EC<U1?!+,^*A%@ 4ZH..P#P4<[N$H$.+YO=\D[N1=
+M[E)%@ 4ZH..P#P4<[N%H208Z0 ?;3><(C04ZH..P#P4<[N%HN=U KQ#QQ^-/
+M 6#*5_F6-3(R!<["N[H6=/TQJEE)VF%8QV+&#O1L1+62=5ODET)B<UEIT[,
+MZV0?@D7\$D?A)A3E^4QMALT+.WWEJ8X6@QE_2"'/9&(E(9LRZL;"'W\\_@10
+M(/TVOS"N83&_KI[,^*A%@ 4ZH..P#P5/ 7/#?3>'']?8 1)P 0'73+P(=U&
+MD 1,<-#2;_-)ED/WDS#]2N<W#QS4HA=)\ )/4%WI$ZM*ZB%;:"S8K#BJE$,^
+M02XZ5G7(]E1(@J38K&$:+R<B<'DP]XCD* *7)R2/^%HV@\VO!WD@D 0O\ 0S
+M347,^*A%@ 4ZP!NU+-U&D 1,4 1"(P)$((KZT0925E4DYL9)\ )/$ )P#MTR
+M(=U%@ 5%, 158-WQ#A_270184 1#4 76G3FI=1[(E$.(EI#8[(I?1,3!P1%'
+M;!%6^KNED?]TGK[KHO<_$ZOSEAFQ!S4Y=#]O0.>GMK!\Y49G<KW<81T 7[O-
+MD\1BC"2PU1_U 9V=IKZ_^QR?;X;L2>?->=/E"5=(E#(3.5DY!#6K<XQTKN.P
+MW^,__OEO8$>+([+_$1LA4XCT=N")09WE:=.DQW?.9"'*HH]<=@)D< )TSAN
+MA!(+XQH6\^N/=&3L@@))X )%X +I.! B\%'8/ )DH -T\(B1?Q\> CDG\?-T
+MCM!8H ,Z#OM%@ 5%, 158-W?RF&;49='PF%C@@).#MWJ)]UN7C(A)OV@;[A)
+MY>;HT6MMQ!$G,9.<*@,M4 /IF%17EW41 Q@QHY]E "*#Y-&H*\8@6;0^02[>
+MX6IR,XX\X9NA1Q#SAZ38O*+>+04^SE"?S\?'+NP;%0/%_E&4*E+Q!\[+WL9N
+M_.QR'.WI#/3('G\\+@4^SE"8RI']NJR%D^Z%)P)FH*^EC<W (08<<<23/G&Q
+MYD76<7595X>[B\VLUQ%"(]U&D 1,4 2_"Q_YWQV=IKYTGF2 %JL@,&^9$7O'
+M"1\U6A\^\3UTWL#MZV0._^KJV$;K-)UA5!_?> 9TGK[K\L-Y03). ";PP2\R
+M&\/9T2_8',4E'2F_SL!'QBZ1V!W,Z:]T+OTVG[[K<K+PA?Z(7O557_4I4RF4
+MDA<(0 <(0 <($)"EX1A^8EP^81)T'DM91QJ"Q8R/6@18H ,Z#OL]_N-H60:@
+M49>/Z7PAPO;8\9R8&>?X5P18H ,Z#OL]_N-H:2=U^9AVHDK16I=T#ATNZ>1=
+M[E)%@ 4ZH..PW^,_CI9Y 0=U^9C1ZE$^ )=*GA=PT*78G!?JU (^P'-EX.30
+M/1/2/05JK@1- 7% 2,^02YPHA)4JV-E0 =J\"8HH'F3/G%LB\VND_^O 3OI
+M<W595X>=OR>+.).<^D2K;DAO!!\/?#>0IW!J\"9T?F8'ZOB,HQQ553!&8OF=
+MO\)O0.=07.5M> (Z6VGN \.E(=U,\ 1.< 1*T 100.?2;_-)ED/WDS FX7U!
+M;!VO!WET+FOU<09J\"8HH'F%R")#,#=9%S&%54A"U2 71N=3)MU3H.9*T 10
+MD#GL.2!C<'7RZ1PP/),'+EOC#XM%HV-5-_YT7C&@N!NSEAC,^*A%@ 4ZH..P
+M/P5JK@1- 6U%QF9^7/2S01/X 1'H 1- 7% 2,^02YPHA)4:QV*<1)J\"8H
+MH'F3/G%LB\WXD_\#03=5[H\/N:/@3N?H^6<+UT;0(4#PP7!M)&M(0^<Z#OM3
+MH.9*T 10@,0M;2%#[(HM#;]B_'J0YS#U<09J\"8HH'EG=J $X01@ A_EI?\)
+M>W59%S%2-OH#(=U,\ 1.< 1*T 10<&SO3N=07.7^N(B=*+.\DZ)E"[]B#$A(
+M)MU3H.9*T 10$/^8L31-TYQE)RV9_AYT#F##(_EQ!"-BPG;2/05JK@1- 5_
+MB\W2S01/X 1'H 1- 634SSY\CM2MJ&/9C/8G/T'XC$7*AO'(6FT48YDP#2E
+M0;8V@\WY#XF=IKY2_<M!DG4 PG8V@\WL4>W,^*A%@ 4ZH..PSP1/X 1'H 1-
+M 6U%QDL0&Z96<W"GLT<=0/&_G[)OL::VE)N_.QR'.WIC)3#SQ4&7?PAW_HE
+MY8(T2-!#D/)O$<],T?Q4 /W@G<]8<=$6;=$@\(1.Z(3-3P70+P4P&,\RZ((K
+M..VC%[&1?Q\> CF[\1PYQ)' *;.\LX@L1,#P >X$D>Z%-_RJ7_PB[X(KF/P\
+M/M$$^,Y/Z(1.^(,^Z(.9DUH&C!XUBO@(\61L15]%+6)SDW414UA^]!M'FOUM
+M.H8Z3XXV$W& I!_#JL+Y\M-,1V<[1WL%+S&DL28#$02=IKX:<V3KZQA^8EP^
+M02XGL 4G_$0GT 4G'(FE+C+) ?PX009;P +SEAFQ-P=M601.O'/_2'G78?:9
+M\^X$T35T3A"UVSSS,F^9$7OP'O2FP30=<F301^<$,6^9$7NN(4!PHF7\LK^%
+M-&^9$7L,<CK";DG4*9) GQ!$L 4LX&=M"1* A/\9!F'-<S\"]&>Z^52X3N<$
+MH:0_K"SYE3"O%'Y/1P8<81(R>N)4($ ZY!HE(9NO93"<D;LM!&@U6A])C,TH
+M0&XZN67^I4K^"IPVVO@?L7>F1^?CXAHLEA',2!%FL 4L,/YST);_-D $D?W*
+MUK,ZW]()@Z3"7KO-,R]'!F_<,?[P'@1"9Z@G?F2J/.D3I_/GX4I:5E[LLC)T
+M3A#CSR!)94G4*9) GQ-& .AR<%"X#N[A]W1!QY!TWM(_4_X@AK>:Z/02$_F!
+M>_#8;!V?;R1PA=/6H:3,^*A, .AR<%"X#N[A]W1!QY!TWM*\,_A.OW-!M]3[
+MA[UT?FRI=6;,MAO6H:3,^*CFHE)R<%"X#N[A]W1!QY!TWM*E.#=9IW&4;FHE
+MIW=CB') GQ-N/@5EP(<7:FQ+O7_G8F;_TOE5+>Q*^L.DOG:;X6!ZL4_Q7DY<
+M[,8YU(Y#1C% XA>.D6KA)@=E!R-RXCXD=N+93U6(=QZN(43/]2FETC5T/CEG
+MK:3,*&I;P *@UY:!]WO4F3[9WZ:(YR%;J.]O0.<MS3LAQVC-@VB@9\!5M'>F
+M1^<$H:1.IGB%X7JW)R0D$P0$T?/#>>*_SL!'QBYP!2.YBWA2C;K8K'UNKV(>
+M@GD&!O23LP4L@+;4T9;_-D $D?W*UK,ZW]()@Z3"7KO-@VAH2QTD$P2FP30M
+M=62G-^V/NE$Q@ /&_G[)OL::VE)N_.QR'.WI#/3.YDI:UEKL3AV_6TX,NF!,
+M0^<$L>F>8_'2@D4_S70\E#H$41Z_D<38C+;4P2). ";PP2_L@NO_TOE5+>Q*
+M^L.DSF;-Z>YR<&AW:S/"7OX@EAYSDW7L@K8#D>Y(*NPG 4GW#<M\;O(:/&(
+M5?Z(^T[M6QYTWM*\TQV=IKZB@B0P@F@ AJ3"/ORJ7_PB[X(KF/P\/M$%>(!6
+MD<]80=#B'8(:^(1.Z(1/Z(1.*/T9P8R/"@6 +@<'A>O@'GY/%W0,2><M_3/E
+M#V+I,3=9%R;LSB+)/,/"GD/M:+CFDD/8,G4 Q.ZUI$QT3A >PS&6YAQ-XSD6
+M+RU8Q"_L$HG$!!MT3A# LQO9'X@@X 1@PNU\AIR1J'7"CK:9PYY5R1$G41HC
+M_#/9KTW"'OGWX2&0LQOX8V*Q)"WEB3\V(^SE\1L^@;;4P8R/&LTPXA/DDC=J
+M0.ES-W76,?RJ7_PB[X(KF/P\/M$$^,Y/Z(1.^(,^Z(-T?FRI!4]T4P9\5HIS
+MDW5WYR!%A?C"/FLM)P:R!$\LEA$LDLSOE$/M*)]!?>+#K_K%+_(NN(+)S^,3
+M38#O_(1.Z(0_Z(,^F#GO7K4J!AW%4G8< 3G+0>>0>%_:7QK9OS,?LI,/2P=;
+MP ).T)9%X,02,_[KI#=\XS>"@FKY(:,G7NAA@ <"]#$5 XJ[<7*J5+O-D\38
+M'+U.T%X^07I\M[ZN(V P@'[6;,U _Z@;=5/&_G[)OL::VE)N_.QR'.WIC)0_
+MZ(,^"(/QS!3-3P5/Z(1.&/0-+=!!./Q<D5(0[8#WG 1/Z(1.2-#B'8(:>-$6
+M;=$7;=$6S= "'80&G?)8\<Y/Z(1...WU"6+E^$XYU(YG=D8J[5/<81TO#6;
+M)4O3C"$%DS#(%XF%)W<$-V7>41*RZ=/D0@>9D?AF$"19!QG8,T>-^+OE5!V#
+MZ%T.ZJ^)YD9G<O &T2QG32XBNC]T=!E(U8:#LZ$T,FE^D5SNA1"Q)1F[8?F=
+MOR=*RHLG%B19EW.K^+O(Z.<=@8I?$T<><U13-TW]XUU5Z 8RYQKD(J+[0T>7
+M@50S.2[LDC5SX",;BD7JV$9*>AXB6S:]9D9R$_Z]MD19NV!^X1BI!GH&#!]T
+MD!D# 21^X1BI!GIRPF9?$T>HFR7+$R19!R#&AGR1R)&W,8Q1ET)QPS)(51IR
+M5Q])RAU]EAF<KJ<THCSZ.&/ 3Q%!,! \T;3EZ<5@8^D)2C=T+RB@^.I(!1^;
+MCXN'Y*-#3""WE!YSDW7LTO=>A![(%XGSTA*!.\,((7<$9Y@\@9^NT?>!];OE
+MY!HX6K4+QC2U9"$DEIUY'XG5M;PF@3EA/6/ 3Q&*HTKZ6Z1F$&&FQ[[RLCR%
+MA4)X4/B%L_!/E9 88N[G"1L]5[_P,?[)X;<@!@(O#6; )4O3C! X5"3MZUW\
+MU3ZG G-XJXGK%"AA;;( 9K:? [V$LQO9'X@@D%94;DKBA<(R1B-WX!<Z9.YD
+MY1/DLD0'T?=)GSY00!M':A%#L+2K>" VW48XQ!FTUVM<1<#F=4ML _<@@ 15
+M%9QVY(8>0AEGP#*.01]S0T5$LOV4KS'@R3)-)3!XPXGK=*'VMUDW[8_9?R"?
+MCQ<-3,#P 3V;0;A2QL0$ET7EZ<+ T=3Q#A_),W));! +OR>1W33-F4-VICKX
+MCSD:@FV,A0>%_RU^GB/H9\W5+.S9'&#H]5&4*E+Q!\[+WL9N_.QR'.WIC)0$
+M/00,+= 66($5:- ,+=#-3P5/Z(1...U"]M)@!ERR-%R9(0=KX!H^\DZVY%H_
+MS70;.I,$(0)!1U'G3@:/^(\R!S6RXS5((BA*PND7+SKOXAB*-9P'$6YR4':5
+M=2)91AWE\[7Q/[S-^4)R$$SE:4TU#UTD=A 4=>[SXEIJ-3M(@K-!<7^"5^6N
+M$;U#\KHD;9/P:Q#K,6GY!B*?CQ?P5(@A-T9\0^DZK_E%&D: Y&C@F)V\D_T4
+M$^7P#@)/T$+TX=9E<)SHH1Y]$4GH4>\(L1YPXEUEFJV6W_E[HJ2JI-.>008?
+M,R/SDB&E0_9/CSYEEQ<M('<"DHN#"T? 3Q%]'AXZ(OK,U!CBB%K*\<%&=1V4
+MKO/Q-"($;%[PA?Z)ONB&P@8(P 8(P 8(H!P(P 8(P 8(H!@(\ 8(\ 8(\,$(
+M, 8(, 8(D'#/=--R1OK(6(\^S&R[81VO!WD:\])@!ERR1$6_^]5XH1>7)B!U
+6JTKA=5]I *"4_\%4D\0&T1CB.!Q$ 1VO
+
+end
diff --git a/dmake/dbug/dbug/example1.c b/dmake/dbug/dbug/example1.c
new file mode 100755
index 000000000000..805b0a202872
--- /dev/null
+++ b/dmake/dbug/dbug/example1.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ printf ("argv[0] = %d\n", argv[0]);
+ /*
+ * Rest of program
+ */
+ printf ("== done ==\n");
+}
diff --git a/dmake/dbug/dbug/example2.c b/dmake/dbug/dbug/example2.c
new file mode 100755
index 000000000000..66ee43c0ec84
--- /dev/null
+++ b/dmake/dbug/dbug/example2.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+int debug = 0;
+
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ /* printf ("argv = %x\n", argv) */
+ if (debug) printf ("argv[0] = %d\n", argv[0]);
+ /*
+ * Rest of program
+ */
+#ifdef DEBUG
+ printf ("== done ==\n");
+#endif
+}
diff --git a/dmake/dbug/dbug/example3.c b/dmake/dbug/dbug/example3.c
new file mode 100755
index 000000000000..0eeb75e7f377
--- /dev/null
+++ b/dmake/dbug/dbug/example3.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+main (argc, argv)
+int argc;
+char *argv[];
+{
+# ifdef DEBUG
+ printf ("argv[0] = %d\n", argv[0]);
+# endif
+ /*
+ * Rest of program
+ */
+# ifdef DEBUG
+ printf ("== done ==\n");
+# endif
+}
diff --git a/dmake/dbug/dbug/factorial.c b/dmake/dbug/dbug/factorial.c
new file mode 100755
index 000000000000..42a4d848014e
--- /dev/null
+++ b/dmake/dbug/dbug/factorial.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+/* User programs should use <local/dbug.h> */
+#include "dbug.h"
+
+int factorial (value)
+ register int value;
+{
+ DBUG_ENTER ("factorial");
+ DBUG_PRINT ("find", ("find %d factorial", value));
+ if (value > 1) {
+ value *= factorial (value - 1);
+ }
+ DBUG_PRINT ("result", ("result is %d", value));
+ DBUG_RETURN (value);
+}
diff --git a/dmake/dbug/dbug/main.c b/dmake/dbug/dbug/main.c
new file mode 100755
index 000000000000..d7c4267d4767
--- /dev/null
+++ b/dmake/dbug/dbug/main.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+/* User programs should use <local/dbug.h> */
+#include "dbug.h"
+
+int main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int result, ix;
+ extern int factorial (), atoi ();
+
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
+ switch (argv[ix][1]) {
+ case '#':
+ DBUG_PUSH (&(argv[ix][2]));
+ break;
+ }
+ }
+ for (; ix < argc; ix++) {
+ DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
+ result = factorial (atoi (argv[ix]));
+ printf ("%d\n", result);
+ }
+ DBUG_RETURN (0);
+}
diff --git a/dmake/dbug/dbug/makeman.sh b/dmake/dbug/dbug/makeman.sh
new file mode 100755
index 000000000000..b2aca44b8f9f
--- /dev/null
+++ b/dmake/dbug/dbug/makeman.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+gcc -o factorial main.c factorial.c dbug.c
+
+for i in example?.c main.c factorial.c ;
+do
+ sed -e 's!\\!\\\\!g' $i > ${i/\.c/\.r}
+done
+
+./factorial 1 2 3 4 5 | cat > output1.r
+./factorial -\#t:o 2 3 | cat > output2.r
+./factorial -\#d:t:o 3 | cat > output3.r
+./factorial -\#d,result:o 4 | cat > output4.r
+./factorial -\#d:f,factorial:F:L:o 3 | cat >output5.r
+
+#nroff -mm user.r > user.t
+#groff -mm user.r > user.ps
+groff -mm -rcR=0 -Tlatin1 -P -bcu user.r > dbug.txt
diff --git a/dmake/dbug/dbug/readme b/dmake/dbug/dbug/readme
new file mode 100644
index 000000000000..8d7c2ed6ab13
--- /dev/null
+++ b/dmake/dbug/dbug/readme
@@ -0,0 +1,52 @@
+This directory contains DBUG the "C Program Debugging Package" by Fred Fish.
+
+/******************************************************************************
+ * *
+ * N O T I C E *
+ * *
+ * Copyright Abandoned, 1987, Fred Fish *
+ * *
+ * *
+ * This previously copyrighted work has been placed into the public *
+ * domain by the author and may be freely used for any purpose, *
+ * private or commercial. *
+ * *
+ * Because of the number of inquiries I was receiving about the use *
+ * of this product in commercially developed works I have decided to *
+ * simply make it public domain to further its unrestricted use. I *
+ * specifically would be most happy to see this material become a *
+ * part of the standard Unix distributions by AT&T and the Berkeley *
+ * Computer Science Research Group, and a standard part of the GNU *
+ * system from the Free Software Foundation. *
+ * *
+ * I would appreciate it, as a courtesy, if this notice is left in *
+ * all copies and derivative works. Thank you. *
+ * *
+ * The author makes no warranty of any kind with respect to this *
+ * product and explicitly disclaims any implied warranties of mer- *
+ * chantability or fitness for any particular purpose. *
+ * *
+ ******************************************************************************
+ */
+
+The original package is no longer mainained, but copies can found here
+ <http://sourceforge.net/projects/dbug/>
+or in the dbug directory of the MySQL 4.0 (and older)
+ <http://dev.mysql.com/downloads/>
+sources.
+
+The files found here are:
+
+ dbug.c - runtime support routines for dbug package
+ dbug.h - user include file for programs using the dbug package
+ user.r - nroff source for the manual page.
+ dbug.txt - a typeset version of the manual page containing no control
+ characters. Generated with makeman.sh:
+ Copy it as dbug.1 into a directory in your search path for
+ man pages to be able to view it with the man command.
+ makeman.sh - helper script to generate the documentation
+ example1.c - Additional/demo sources for the documentation.
+ example2.c
+ example3.c
+ main.c
+ factorial.c
diff --git a/dmake/dbug/dbug/user.r b/dmake/dbug/dbug/user.r
new file mode 100755
index 000000000000..1d58d28a8800
--- /dev/null
+++ b/dmake/dbug/dbug/user.r
@@ -0,0 +1,938 @@
+.\" @(#)user.r 1.13 10/29/86
+.\"
+.\" DBUG (Macro Debugger Package) nroff source
+.\"
+.\" nroff -mm user.r >user.t
+.\"
+.\" ===================================================
+.\"
+.\" === Some sort of black magic, but I forget...
+.tr ~
+.\" === Hyphenation control (1 = on)
+.\".nr Hy 1
+.\" === Force all first level headings to start on new page
+.nr Ej 1
+.\" === Set for breaks after headings for levels 1-3
+.nr Hb 3
+.\" === Set for space after headings for levels 1-3
+.nr Hs 3
+.\" === Set standard indent for one/half inch
+.nr Si 10
+.\" === Set page header - set date to source date
+.\".PH "/DBUG User Manual//\*(DT/"
+.PH "/DBUG User Manual//October 29, 1986"
+.\" === Set page footer
+.PF "// - % - //"
+.\" === Set page offset
+.\".po 0.60i
+.\" === Set line length
+.\".ll 6.5i
+.TL
+D B U G
+.P 0
+C Program Debugging Package
+.P 0
+by
+.AU "Fred Fish"
+.AF ""
+.SA 1
+.\" === All paragraphs indented.
+.nr Pt 1
+.AS 1
+This document introduces
+.I dbug ,
+a macro based C debugging
+package which has proven to be a very flexible and useful tool
+for debugging, testing, and porting C programs.
+
+.P
+All of the features of the
+.I 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.
+
+.P
+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
+.I dbug
+package should
+.I not
+be thought of as a replacement or substitute for
+other debugging tools, but simply as a useful
+.I addition
+to the
+program development and maintenance environment.
+
+.AE
+.MT 4
+.SK
+.B
+INTRODUCTION
+.R
+
+.P
+Almost every program development environment worthy of the name
+provides some sort of debugging facility.
+Usually this takes the form of a program which is capable of
+controlling execution of other programs and examining the internal
+state of other executing programs.
+These types of programs will be referred to as external debuggers
+since the debugger is not part of the executing program.
+Examples of this type of debugger include the
+.B adb
+and
+.B sdb
+debuggers provided with the
+.B UNIX\*F
+.FS
+UNIX is a trademark of AT&T Bell Laboratories.
+.FE
+operating system.
+
+.P
+One of the problems associated with developing programs in an environment
+with good external debuggers is that developed programs tend to have
+little or no internal instrumentation.
+This is usually not a problem for the developer since he is,
+or at least should be, intimately familiar with the internal organization,
+data structures, and control flow of the program being debugged.
+It is a serious problem for maintenance programmers, who
+are unlikely to have such familiarity with the program being
+maintained, modified, or ported to another environment.
+It is also a problem, even for the developer, when the program is
+moved to an environment with a primitive or unfamiliar debugger,
+or even no debugger.
+
+.P
+On the other hand,
+.I dbug
+is an example of an internal debugger.
+Because it requires internal instrumentation of a program,
+and its usage does not depend on any special capabilities of
+the execution environment, it is always available and will
+execute in any environment that the program itself will
+execute in.
+In addition, since it is a complete package with a specific
+user interface, all programs which use it will be provided
+with similar debugging capabilities.
+This is in sharp contrast to other forms of internal instrumentation
+where each developer has their own, usually less capable, form
+of internal debugger.
+In summary,
+because
+.I dbug
+is an internal debugger it provides consistency across operating
+environments,
+and because it is available to all developers it provides
+consistency across all programs in the same environment.
+
+.P
+The
+.I dbug
+package imposes only a slight speed penalty on executing
+programs, typically much less than 10 percent, and a modest size
+penalty, typically 10 to 20 percent.
+By defining a specific C preprocessor symbol both of these
+can be reduced to zero with no changes required to the
+source code.
+
+.P
+The following list is a quick summary of the capabilities
+of the
+.I dbug
+package.
+Each capability can be individually enabled or disabled
+at the time a program is invoked by specifying the appropriate
+command line arguments.
+.SP 1
+.ML o 1i
+.LI
+Execution trace showing function level control flow in a
+semi-graphically manner using indentation to indicate nesting
+depth.
+.LI
+Output the values of all, or any subset of, key internal variables.
+.LI
+Limit actions to a specific set of named functions.
+.LI
+Limit function trace to a specified nesting depth.
+.LI
+Label each output line with source file name and line number.
+.LI
+Label each output line with name of current process.
+.LI
+Push or pop internal debugging state to allow execution with
+built in debugging defaults.
+.LI
+Redirect the debug output stream to standard output (stdout)
+or a named file.
+The default output stream is standard error (stderr).
+The redirection mechanism is completely independent of
+normal command line redirection to avoid output conflicts.
+.LE
+
+.SK
+.B
+PRIMITIVE DEBUGGING TECHNIQUES
+.R
+
+.P
+Internal instrumentation is already a familiar concept
+to most programmers, since it is usually the first debugging
+technique learned.
+Typically, "print\ statements" are inserted in the source
+code at interesting points, the code is recompiled and executed,
+and the resulting output is examined in an attempt to determine
+where the problem is.
+
+The procedure is iterative, with each iteration yielding more
+and more output, and hopefully the source of the problem is
+discovered before the output becomes too large to deal with
+or previously inserted statements need to be removed.
+Figure 1 is an example of this type of primitive debugging
+technique.
+.DS I N
+.SP 2
+.so example1.r
+.SP 2
+.ll -5
+.ce
+Figure 1
+.ce
+Primitive Debugging Technique
+.ll +5
+.SP 2
+.DE
+
+.P
+Eventually, and usually after at least several iterations, the
+problem will be found and corrected.
+At this point, the newly inserted print statements must be
+dealt with.
+One obvious solution is to simply delete them all.
+Beginners usually do this a few times until they have to
+repeat the entire process every time a new bug pops up.
+The second most obvious solution is to somehow disable
+the output, either through the source code comment facility,
+creation of a debug variable to be switched on or off, or by using the
+C preprocessor.
+Figure 2 is an example of all three techniques.
+.DS I N
+.SP 2
+.so example2.r
+.SP 2
+.ll -5
+.ce
+Figure 2
+.ce
+Debug Disable Techniques
+.ll +5
+.SP 2
+.DE
+
+.P
+Each technique has its advantages and disadvantages with respect
+to dynamic vs static activation, source code overhead, recompilation
+requirements, ease of use, program readability, etc.
+Overuse of the preprocessor solution quickly leads to problems with
+source code readability and maintainability when multiple
+.B #ifdef
+symbols are to be defined or undefined based on specific types
+of debug desired.
+The source code can be made slightly more readable by suitable indentation
+of the
+.B #ifdef
+arguments to match the indentation of the code, but
+not all C preprocessors allow this.
+The only requirement for the standard
+.B UNIX
+C preprocessor is for the '#' character to appear
+in the first column, but even this seems
+like an arbitrary and unreasonable restriction.
+Figure 3 is an example of this usage.
+.DS I N
+.SP 2
+.so example3.r
+.SP 2
+.ll -5
+.ce
+Figure 3
+.ce
+More Readable Preprocessor Usage
+.ll +5
+.SP 2
+.DE
+
+.SK
+.B
+FUNCTION TRACE EXAMPLE
+.R
+
+.P
+We will start off learning about the capabilities of the
+.I dbug
+package by using a simple minded program which computes the
+factorial of a number.
+In order to better demonstrate the function trace mechanism, this
+program is implemented recursively.
+Figure 4 is the main function for this factorial program.
+.DS I N
+.SP 2
+.so main.r
+.SP 2
+.ll -5
+.ce
+Figure 4
+.ce
+Factorial Program Mainline
+.ll +5
+.SP 2
+.DE
+
+.P
+The
+.B main
+function is responsible for processing any command line
+option arguments and then computing and printing the factorial of
+each non-option argument.
+.P
+First of all, notice that all of the debugger functions are implemented
+via preprocessor macros.
+This does not detract from the readability of the code and makes disabling
+all debug compilation trivial (a single preprocessor symbol,
+.B DBUG_OFF ,
+forces the macro expansions to be null).
+.P
+Also notice the inclusion of the header file
+.B dbug.h
+from the local header file directory.
+(The version included here is the test version in the dbug source
+distribution directory).
+This file contains all the definitions for the debugger macros, which
+all have the form
+.B DBUG_XX...XX .
+
+.P
+The
+.B DBUG_ENTER
+macro informs that debugger that we have entered the
+function named
+.B main .
+It must be the very first "executable" line in a function, after
+all declarations and before any other executable line.
+The
+.B DBUG_PROCESS
+macro is generally used only once per program to
+inform the debugger what name the program was invoked with.
+The
+.B DBUG_PUSH
+macro modifies the current debugger state by
+saving the previous state and setting a new state based on the
+control string passed as its argument.
+The
+.B DBUG_PRINT
+macro is used to print the values of each argument
+for which a factorial is to be computed.
+The
+.B DBUG_RETURN
+macro tells the debugger that the end of the current
+function has been reached and returns a value to the calling
+function.
+All of these macros will be fully explained in subsequent sections.
+.P
+To use the debugger, the factorial program is invoked with a command
+line of the form:
+.DS CB N
+factorial -#d:t 1 2 3
+.DE
+The
+.B main
+function recognizes the "-#d:t" string as a debugger control
+string, and passes the debugger arguments ("d:t") to the
+.I dbug
+runtime support routines via the
+.B DBUG_PUSH
+macro.
+This particular string enables output from the
+.B DBUG_PRINT
+macro with the 'd' flag and enables function tracing with the 't' flag.
+The factorial function is then called three times, with the arguments
+"1", "2", and "3".
+Note that the DBUG_PRINT takes exactly
+.B two
+arguments, with the second argument (a format string and list
+of printable values) enclosed in parenthesis.
+.P
+Debug control strings consist of a header, the "-#", followed
+by a colon separated list of debugger arguments.
+Each debugger argument is a single character flag followed
+by an optional comma separated list of arguments specific
+to the given flag.
+Some examples are:
+.DS CB N
+-#d:t:o
+-#d,in,out:f,main:F:L
+.DE
+Note that previously enabled debugger actions can be disabled by the
+control string "-#".
+
+.P
+The definition of the factorial function, symbolized as "N!", is
+given by:
+.DS CB N
+N! = N * N-1 * ... 2 * 1
+.DE
+Figure 5 is the factorial function which implements this algorithm
+recursively.
+Note that this is not necessarily the best way to do factorials
+and error conditions are ignored completely.
+.DS I N
+.SP 2
+.so factorial.r
+.SP 2
+.ll -5
+.ce
+Figure 5
+.ce
+Factorial Function
+.ll +5
+.SP 2
+.DE
+
+.P
+One advantage (some may not consider it so) to using the
+.I dbug
+package is that it strongly encourages fully structured coding
+with only one entry and one exit point in each function.
+Multiple exit points, such as early returns to escape a loop,
+may be used, but each such point requires the use of an
+appropriate
+.B DBUG_RETURN
+or
+.B DBUG_VOID_RETURN
+macro.
+
+.P
+To build the factorial program on a
+.B UNIX
+system, compile and
+link with the command:
+.DS CB N
+cc -o factorial main.c factorial.c -ldbug
+.DE
+The "-ldbug" argument tells the loader to link in the
+runtime support modules for the
+.I dbug
+package.
+Executing the factorial program with a command of the form:
+.DS CB N
+factorial 1 2 3 4 5
+.DE
+generates the output shown in figure 6.
+.DS I N
+.SP 2
+.so output1.r
+.SP 2
+.ll -5
+.ce
+Figure 6
+.ce
+factorial 1 2 3 4 5
+.ll +5
+.SP 2
+.DE
+
+.P
+Function level tracing is enabled by passing the debugger
+the 't' flag in the debug control string.
+Figure 7 is the output resulting from the command
+"factorial\ -#t:o\ 3\ 2".
+.DS I N
+.SP 2
+.so output2.r
+.SP 2
+.ll -5
+.ce
+Figure 7
+.ce
+factorial -#t:o 3 2
+.ll +5
+.SP 2
+.DE
+
+.P
+Each entry to or return from a function is indicated by '>' for the
+entry point and '<' for the exit point, connected by
+vertical bars to allow matching points to be easily found
+when separated by large distances.
+
+.P
+This trace output indicates that there was an initial call
+to factorial from main (to compute 2!), followed by
+a single recursive call to factorial to compute 1!.
+The main program then output the result for 2! and called the
+factorial function again with the second argument, 3.
+Factorial called itself recursively to compute 2! and 1!, then
+returned control to main, which output the value for 3! and exited.
+
+.P
+Note that there is no matching entry point "main>" for the
+return point "<main" because at the time the
+.B DBUG_ENTER
+macro was reached in main, tracing was not enabled yet.
+It was only after the macro
+.B DBUG_PUSH
+was executing that tracing became enabled.
+This implies that the argument list should be processed as early as
+possible since all code preceding the first call to
+.B DBUG_PUSH
+is
+essentially invisible to
+.B dbug
+(this can be worked around by
+inserting a temporary
+.B DBUG_PUSH(argv[1])
+immediately after the
+.B DBUG_ENTER("main")
+macro.
+
+.P
+One last note,
+the trace output normally comes out on the standard error.
+Since the factorial program prints its result on the standard
+output, there is the possibility of the output on the terminal
+being scrambled if the two streams are not synchronized.
+Thus the debugger is told to write its output on the standard
+output instead, via the 'o' flag character.
+Note that no 'o' implies the default (standard error), a 'o'
+with no arguments means standard output, and a 'o'
+with an argument means used the named file.
+I.E, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
+output in "logfile".
+Because of
+.B UNIX
+implementation details, programs usually run
+faster when writing to stdout rather than stderr, though this
+is not a prime consideration in this example.
+
+.SK
+.B
+USE OF DBUG_PRINT MACRO
+.R
+
+.P
+The mechanism used to produce "printf" style output is the
+.B DBUG_PRINT
+macro.
+
+.P
+To allow selection of output from specific macros, the first argument
+to every
+.B DBUG_PRINT
+macro is a
+.I dbug
+keyword.
+When this keyword appears in the argument list of the 'd' flag in
+a debug control string, as in "-#d,keyword1,keyword2,...:t",
+output from the corresponding macro is enabled.
+The default when there is no 'd' flag in the control string is to
+enable output from all
+.B DBUG_PRINT
+macros.
+
+.P
+Typically, a program will be run once, with no keywords specified,
+to determine what keywords are significant for the current problem
+(the keywords are printed in the macro output line).
+Then the program will be run again, with the desired keywords,
+to examine only specific areas of interest.
+
+.P
+The second argument to a
+.B DBUG_PRINT
+macro is a standard printf style
+format string and one or more arguments to print, all
+enclosed in parenthesis so that they collectively become a single macro
+argument.
+This is how variable numbers of printf arguments are supported.
+Also note that no explicit newline is required at the end of the format string.
+As a matter of style, two or three small
+.B DBUG_PRINT
+macros are preferable
+to a single macro with a huge format string.
+Figure 8 shows the output for default tracing and debug.
+.DS I N
+.SP 2
+.so output3.r
+.SP 2
+.ll -5
+.ce
+Figure 8
+.ce
+factorial -#d:t:o 3
+.ll +5
+.SP 2
+.DE
+
+.P
+The output from the
+.B DBUG_PRINT
+macro is indented to match the trace output
+for the function in which the macro occurs.
+When debugging is enabled, but not trace, the output starts at the left
+margin, without indentation.
+
+.P
+To demonstrate selection of specific macros for output, figure
+9 shows the result when the factorial program is invoked with
+the debug control string "-#d,result:o".
+.DS I N
+.SP 2
+.so output4.r
+.SP 2
+.ll -5
+.ce
+Figure 9
+.ce
+factorial -#d,result:o 4
+.ll +5
+.SP 2
+.DE
+
+.P
+It is sometimes desirable to restrict debugging and trace actions
+to a specific function or list of functions.
+This is accomplished with the 'f' flag character in the debug
+control string.
+Figure 10 is the output of the factorial program when run with the
+control string "-#d:f,factorial:F:L:o".
+The 'F' flag enables printing of the source file name and the 'L'
+flag enables printing of the source file line number.
+.DS I N
+.SP 2
+.so output5.r
+.SP 2
+.ll -5
+.ce
+Figure 10
+.ce
+factorial -#d:f,factorial:F:L:o 3
+.ll +5
+.SP 2
+.DE
+
+.P
+The output in figure 10 shows that the "find" macro is in file
+"factorial.c" at source line 8 and the "result" macro is in the same
+file at source line 12.
+
+.SK
+.B
+SUMMARY OF MACROS
+.R
+
+.P
+This section summarizes the usage of all currently defined macros
+in the
+.I dbug
+package.
+The macros definitions are found in the user include file
+.B dbug.h
+from the standard include directory.
+
+.SP 2
+.BL 20
+.LI DBUG_ENTER\
+Used to tell the runtime support module the name of the function
+being entered.
+The argument must be of type "pointer to character".
+The
+DBUG_ENTER
+macro must precede all executable lines in the
+function just entered, and must come after all local declarations.
+Each
+DBUG_ENTER
+macro must have a matching
+DBUG_RETURN
+or
+DBUG_VOID_RETURN
+macro
+at the function exit points.
+DBUG_ENTER
+macros used without a matching
+DBUG_RETURN
+or
+DBUG_VOID_RETURN
+macro
+will cause warning messages from the
+.I dbug
+package runtime support module.
+.SP 1
+EX:\ DBUG_ENTER\ ("main");
+.SP 1
+.LI DBUG_RETURN\
+Used at each exit point of a function containing a
+DBUG_ENTER
+macro
+at the entry point.
+The argument is the value to return.
+Functions which return no value (void) should use the
+DBUG_VOID_RETURN
+macro.
+It
+is an error to have a
+DBUG_RETURN
+or
+DBUG_VOID_RETURN
+macro in a function
+which has no matching
+DBUG_ENTER
+macro, and the compiler will complain
+if the macros are actually used (expanded).
+.SP 1
+EX:\ DBUG_RETURN\ (value);
+.br
+EX:\ DBUG_VOID_RETURN;
+.SP 1
+.LI DBUG_PROCESS\
+Used to name the current process being executed.
+A typical argument for this macro is "argv[0]", though
+it will be perfectly happy with any other string.
+.SP 1
+EX:\ DBUG_PROCESS\ (argv[0]);
+.SP 1
+.LI DBUG_PUSH\
+Sets a new debugger state by pushing the current
+.B dbug
+state onto an
+internal stack and setting up the new state using the debug control
+string passed as the macro argument.
+The most common usage is to set the state specified by a debug
+control string retrieved from the argument list.
+Note that the leading "-#" in a debug control string specified
+as a command line argument must
+.B not
+be passed as part of the macro argument.
+The proper usage is to pass a pointer to the first character
+.B after
+the "-#" string.
+.SP 1
+EX:\ DBUG_PUSH\ (\&(argv[i][2]));
+.br
+EX:\ DBUG_PUSH\ ("d:t");
+.br
+EX:\ DBUG_PUSH\ ("");
+.SP 1
+.LI DBUG_POP\
+Restores the previous debugger state by popping the state stack.
+Attempting to pop more states than pushed will be ignored and no
+warning will be given.
+The
+DBUG_POP
+macro has no arguments.
+.SP 1
+EX:\ DBUG_POP\ ();
+.SP 1
+.LI DBUG_FILE\
+The
+DBUG_FILE
+macro is used to do explicit I/O on the debug output
+stream.
+It is used in the same manner as the symbols "stdout" and "stderr"
+in the standard I/O package.
+.SP 1
+EX:\ fprintf\ (DBUG_FILE,\ "Doing my own I/O!\\n");
+.SP 1
+.LI DBUG_EXECUTE\
+The DBUG_EXECUTE macro is used to execute any arbitrary C code.
+The first argument is the debug keyword, used to trigger execution
+of the code specified as the second argument.
+This macro must be used cautiously because, like the
+DBUG_PRINT
+macro,
+it is automatically selected by default whenever the 'd' flag has
+no argument list (I.E., a "-#d:t" control string).
+.SP 1
+EX:\ DBUG_EXECUTE\ ("abort",\ abort\ ());
+.SP 1
+.LI DBUG_N\
+These macros, where N is in the range 2-5, are currently obsolete
+and will be removed in a future release.
+Use the new DBUG_PRINT macro.
+.LI DBUG_PRINT\
+Used to do printing via the "fprintf" library function on the
+current debug stream,
+DBUG_FILE.
+The first argument is a debug keyword, the second is a format string
+and the corresponding argument list.
+Note that the format string and argument list are all one macro argument
+and
+.B must
+be enclosed in parenthesis.
+.SP 1
+EX:\ DBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));
+.br
+EX:\ DBUG_PRINT\ ("type",\ ("type\ is\ %x", type));
+.br
+EX:\ DBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));
+.LI DBUG_SETJMP\
+Used in place of the setjmp() function to first save the current
+debugger state and then execute the standard setjmp call.
+This allows to the debugger to restore it's state when the
+DBUG_LONGJMP macro is used to invoke the standard longjmp() call.
+Currently all instances of DBUG_SETJMP must occur within the
+same function and at the same function nesting level.
+.SP 1
+EX:\ DBUG_SETJMP\ (env);
+.LI DBUG_LONGJMP\
+Used in place of the longjmp() function to first restore the
+previous debugger state at the time of the last DBUG_SETJMP
+and then execute the standard longjmp() call.
+Note that currently all DBUG_LONGJMP macros restore the state
+at the time of the last DBUG_SETJMP.
+It would be possible to maintain separate DBUG_SETJMP and DBUG_LONGJMP
+pairs by having the debugger runtime support module use the first
+argument to differentiate the pairs.
+.SP 1
+EX:\ DBUG_LONGJMP\ (env,val);
+.LE
+
+.SK
+.B
+DEBUG CONTROL STRING
+.R
+
+.P
+The debug control string is used to set the state of the debugger
+via the
+.B DBUG_PUSH
+macro.
+This section summarizes the currently available debugger options
+and the flag characters which enable or disable them.
+Argument lists enclosed in '[' and ']' are optional.
+.SP 2
+.BL 22
+.LI d[,keywords]
+Enable output from macros with specified keywords.
+A null list of keywords implies that all keywords are selected.
+.LI D[,time]
+Delay for specified time after each output line, to let output drain.
+Time is given in tenths of a second (value of 10 is one second).
+Default is zero.
+.LI f[,functions]
+Limit debugger actions to the specified list of functions.
+A null list of functions implies that all functions are selected.
+.LI F
+Mark each debugger output line with the name of the source file
+containing the macro causing the output.
+.LI L
+Mark each debugger output line with the source file line number of
+the macro causing the output.
+.LI n
+Mark each debugger output line with the current function nesting depth.
+.LI N
+Sequentially number each debugger output line starting at 1.
+This is useful for reference purposes when debugger output is
+interspersed with program output.
+.LI o[,file]
+Redirect the debugger output stream to the specified file.
+The default output stream is stderr.
+A null argument list causes output to be redirected to stdout.
+.LI p[,processes]
+Limit debugger actions to the specified processes.
+A null list implies all processes.
+This is useful for processes which run child processes.
+Note that each debugger output line can be marked with the name of
+the current process via the 'P' flag.
+The process name must match the argument passed to the
+.B DBUG_PROCESS
+macro.
+.LI P
+Mark each debugger output line with the name of the current process.
+Most useful when used with a process which runs child processes that
+are also being debugged.
+Note that the parent process must arrange for the debugger control
+string to be passed to the child processes.
+.LI r
+Used in conjunction with the
+.B DBUG_PUSH
+macro to reset the current
+indentation level back to zero.
+Most useful with
+.B DBUG_PUSH
+macros used to temporarily alter the
+debugger state.
+.LI t[,N]
+Enable function control flow tracing.
+The maximum nesting depth is specified by N, and defaults to
+200.
+.LE
+.SK
+.B
+HINTS AND MISCELLANEOUS
+.R
+
+.P
+One of the most useful capabilities of the
+.I dbug
+package is to compare the executions of a given program in two
+different environments.
+This is typically done by executing the program in the environment
+where it behaves properly and saving the debugger output in a
+reference file.
+The program is then run with identical inputs in the environment where
+it misbehaves and the output is again captured in a reference file.
+The two reference files can then be differentially compared to
+determine exactly where execution of the two processes diverges.
+
+.P
+A related usage is regression testing where the execution of a current
+version is compared against executions of previous versions.
+This is most useful when there are only minor changes.
+
+.P
+It is not difficult to modify an existing compiler to implement
+some of the functionality of the
+.I dbug
+package automatically, without source code changes to the
+program being debugged.
+In fact, such changes were implemented in a version of the
+Portable C Compiler by the author in less than a day.
+However, it is strongly encouraged that all newly
+developed code continue to use the debugger macros
+for the portability reasons noted earlier.
+The modified compiler should be used only for testing existing
+programs.
+
+.SK
+.B
+CAVEATS
+.R
+
+.P
+The
+.I dbug
+package works best with programs which have "line\ oriented"
+output, such as text processors, general purpose utilities, etc.
+It can be interfaced with screen oriented programs such as
+visual editors by redefining the appropriate macros to call
+special functions for displaying the debugger results.
+Of course, this caveat is not applicable if the debugger output
+is simply dumped into a file for post-execution examination.
+
+.P
+Programs which use memory allocation functions other than
+.B malloc
+will usually have problems using the standard
+.I dbug
+package.
+The most common problem is multiply allocated memory.
+.SP 2
+.\" .DE nroff dident like this. davida 900108
+.CS
+
+
diff --git a/dmake/dbug/getwd.c b/dmake/dbug/getwd.c
new file mode 100644
index 000000000000..56e1a03ab7ca
--- /dev/null
+++ b/dmake/dbug/getwd.c
@@ -0,0 +1,6 @@
+char *
+getwd(pathname)
+char *pathname;
+{
+ return("delete this code if your getwd.c works correctly");
+}
diff --git a/dmake/dbug/malloc/_changes b/dmake/dbug/malloc/_changes
new file mode 100644
index 000000000000..888a47a8dfb5
--- /dev/null
+++ b/dmake/dbug/malloc/_changes
@@ -0,0 +1,9 @@
+I made the following changes to the malloc package as found in
+comp.sources.unix:
+
+ 1. created this file _changes.
+ 2. moved README to _readme (facilitates transfer to DOS and back to
+ unix)
+ 3. renamed testmalloc.c, malloc_chk.c, and malloc_chn.c to testmlc.c,
+ mlc_chk.c, and mlc_chn.c respectively. Again DOS has trouble with
+ long basenames in filenames.
diff --git a/dmake/dbug/malloc/_readme b/dmake/dbug/malloc/_readme
new file mode 100644
index 000000000000..b78b1fd6bbcd
--- /dev/null
+++ b/dmake/dbug/malloc/_readme
@@ -0,0 +1,133 @@
+# (c) Copyright 1990 Conor P. Cahill. (uunet!virtech!cpcahil)
+# You may copy, distribute, and use this software as long as this
+# copyright statement is not removed.
+
+This package is a collection of routines which are a drop-in replacement
+for the malloc(3), memory(3), string(3), and bstring(3) library functions.
+
+The purpose of these programs is to aid the development and/or debugging
+of programs using these functions by providing a high level of consistancy
+checking whenever a malloc pointer is used. Due to this increased
+level of consistancy checking, these functions have a considerably larger
+overhead than the standard functions, but the extra checking should be
+well worth it in a development environment.
+
+To use these functions all you need to do is compile the library and
+include it on your loader command line. You do not need to recompile
+your code, only a relink is necessary.
+
+Features of this library:
+
+ 1. The malloced area returned from each call to malloc is filled with
+ non-null bytes. This should catch any use of uninitialized malloc
+ area. The fill pattern for malloced area is 0x01.
+
+ 2. When free is called numerous validity checks are made on the
+ pointer it is passed. In addition, the data in the malloc block
+ beyound the size requested on the initial malloc is checked to
+ verify that it is still filled with the original fill characters.
+
+ This is usefull for catching things like:
+
+ ptr = malloc(5);
+ ptr[5] = '\0';
+
+ /*
+ * You should not that this will be caught when it is
+ * freed not when it is done
+ */
+
+ And finally, the freed block is filled with a different fill pattern
+ so that you can easily determine if you are still using free'd space.
+ The fill pattern for free'd areas is 0x02.
+
+ This is usefull for catching things like:
+
+ ptr = malloc(20);
+
+ bptr = ptr+10;
+
+ /* do something usefule with bptr */
+
+ free(ptr);
+
+ /*
+ * now try to do something useful with bptr, it should
+ * be trashed enough that it would cause real problems
+ * and when you went to debug the problem it would be
+ * filled with 0x02's and you would then know to look
+ * for something free'ing what bptr points to.
+ */
+
+
+ 3. Whenever a bstring(3)/string(3)/memory(3) function is called, it's
+ parameters are checked as follows:
+
+ If they point somewhere in the malloc arena
+ If the operation goes beyond requested malloc space
+ call malloc_warning()
+
+ This is usefull for catching things like:
+
+ ptr = malloc(5);
+ strcpy(ptr,"abcde");
+
+
+ 4. Malloc_warning() and malloc_fatal() are used when an error condition
+ is detected. If the error is severe, malloc_fatal is called.
+ Malloc_warning is used otherwise. The decision about what is fatal
+ and what is a warning was made somewhat arbitrarily.
+
+ Warning messages include:
+
+ Calling free with a bad pointer
+ Calling a bstring/string/memory (3) function which will go beyond
+ the end of a malloc block (Note that the library function is
+ not modified to refuse the operation. If malloc warnings are
+ in the default IGNORE case, the operation will continue and
+ at some point cause a real problem).
+
+ Fatal errors are:
+
+ Detectable corruption to the malloc chain.
+
+
+ 5. The operations to perform when an error is detected are specified at
+ run time by the use of environment variables.
+
+ MALLOC_WARN - specifies the warning error message handling
+ MALLOC_FATAL - specifies the fatal error handling
+
+
+ When one of these error conditions occur you will get an error
+ message and the handler will execute based upon what setting
+ is in the environment variables. Currently understood settings
+ are as follows:
+
+ 0 - continue operations
+ 1 - drop core and exit
+ 2 - just exit
+ 3 - drop core, but continue executing. Core files will
+ be placed into core.[PID].[counter] i.e: core.00123.001
+ 128 - dump malloc chain and continue
+ 129 - dump malloc chain, dump core, and exit
+ 130 - dump malloc chain, exit
+ 131 - dump malloc chain, dump core, continue processing
+
+
+ There is an additional environment variable MALLOC_ERRFILE which
+ is used to indicate the name of the file for error message output.
+
+ For example, to set up the session to generate a core file for
+ every malloc warning, to drop core and exit on a malloc fatal, and
+ to log all messages to the file "malloc_log" do the following:
+
+ MALLOC_WARN=131
+ MALLOC_FATAL=1
+ MALLOC_ERRFILE=malloc_log
+
+ export MALLOC_WARN MALLOC_FATAL MALLOC_ERRFILE
+
+ 6. The function malloc_dump() is available to dump the malloc chain whenever
+ you might want. It's only argument is a file descriptor to use to write
+ the data. Review the code if you need to know what data is printed.
diff --git a/dmake/dbug/malloc/calloc.c b/dmake/dbug/malloc/calloc.c
new file mode 100644
index 000000000000..1469b200cbf2
--- /dev/null
+++ b/dmake/dbug/malloc/calloc.c
@@ -0,0 +1,49 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+
+/*
+ * Function: calloc()
+ *
+ * Purpose: to allocate and nullify a data area
+ *
+ * Arguments: nelem - number of elements
+ * elsize - size of each element
+ *
+ * Returns: NULL - if malloc fails
+ * or pointer to allocated space
+ *
+ * Narrative: determine size of area to malloc
+ * malloc area.
+ * if malloc succeeds
+ * fill area with nulls
+ * return ptr to malloc'd region
+ */
+#ifndef lint
+static char rcs_header[] = "$Id: calloc.c,v 1.2 2006-07-25 10:07:11 rt Exp $";
+#endif
+
+char *
+calloc(nelem,elsize)
+ unsigned int nelem;
+ unsigned int elsize;
+{
+ char * malloc();
+ char * memset();
+ char * ptr;
+ unsigned int size;
+
+ size = elsize * nelem;
+
+ if( (ptr = malloc(size)) != NULL)
+ {
+ (void) memset(ptr,'\0',(int)size);
+ }
+
+ return(ptr);
+}
+
+
diff --git a/dmake/dbug/malloc/debug.h b/dmake/dbug/malloc/debug.h
new file mode 100644
index 000000000000..069d1dc77639
--- /dev/null
+++ b/dmake/dbug/malloc/debug.h
@@ -0,0 +1,99 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+/************************************************************************/
+/* */
+/* this include sets up some macro functions which can be used while */
+/* debugging the program, and then left in the code, but turned of by */
+/* just not defining "DEBUG". This way your production version of */
+/* the program will not be filled with bunches of debugging junk */
+/* */
+/************************************************************************/
+/*
+ * $Id: debug.h,v 1.2 2006-07-25 10:07:24 rt Exp $
+ */
+
+#ifdef DEBUG
+
+#if DEBUG == 1 /* if default level */
+#undef DEBUG
+#define DEBUG 100 /* use level 100 */
+#endif
+
+#include <stdio.h>
+
+#define DEBUG0(val,str)\
+ {\
+ if( DEBUG > val ) \
+ fprintf(stderr,"%s(%d): %s\n",\
+ __FILE__,__LINE__,str);\
+ }
+#define DEBUG1(val,str,a1)\
+ {\
+ char _debugbuf[100];\
+ if( DEBUG > val )\
+ {\
+ sprintf(_debugbuf,str,a1);\
+ fprintf(stderr,"%s(%d): %s\n",\
+ __FILE__,__LINE__,_debugbuf);\
+ }\
+ }
+
+#define DEBUG2(val,str,a1,a2)\
+ {\
+ char _debugbuf[100];\
+ if( DEBUG > val )\
+ {\
+ sprintf(_debugbuf,str,a1,a2);\
+ fprintf(stderr,"%s(%d): %s\n",\
+ __FILE__,__LINE__,_debugbuf);\
+ }\
+ }
+
+#define DEBUG3(val,str,a1,a2,a3)\
+ {\
+ char _debugbuf[100];\
+ if( DEBUG > val )\
+ {\
+ sprintf(_debugbuf,str,a1,a2,a3);\
+ fprintf(stderr,"%s(%d): %s\n",\
+ __FILE__,__LINE__,_debugbuf);\
+ }\
+ }
+
+#define DEBUG4(val,str,a1,a2,a3,a4)\
+ {\
+ char _debugbuf[100];\
+ if( DEBUG > val )\
+ {\
+ sprintf(_debugbuf,str,a1,a2,a3,a4);\
+ fprintf(stderr,"%s(%d): %s\n",\
+ __FILE__,__LINE__,_debugbuf);\
+ }\
+ }
+
+#define DEBUG5(val,str,a1,a2,a3,a4,a5)\
+ {\
+ char _debugbuf[100];\
+ if( DEBUG > val )\
+ {\
+ sprintf(_debugbuf,str,a1,a2,a3,a4,a5);\
+ fprintf(stderr,"%s(%d): %s\n",\
+ __FILE__,__LINE__,_debugbuf);\
+ }\
+ }
+
+#else
+
+#define DEBUG0(val,s)
+#define DEBUG1(val,s,a1)
+#define DEBUG2(val,s,a1,a2)
+#define DEBUG3(val,s,a1,a2,a3)
+#define DEBUG4(val,s,a1,a2,a3,a4)
+#define DEBUG5(val,s,a1,a2,a3,a4,a5)
+
+#endif /* DEBUG */
+
+
diff --git a/dmake/dbug/malloc/dump.c b/dmake/dbug/malloc/dump.c
new file mode 100644
index 000000000000..70c8ac30c2d8
--- /dev/null
+++ b/dmake/dbug/malloc/dump.c
@@ -0,0 +1,103 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+#include "tostring.h"
+
+/*
+ * Function: malloc_dump()
+ *
+ * Purpose: to dump a printed copy of the malloc chain and
+ * associated data elements
+ *
+ * Arguments: fd - file descriptor to write data to
+ *
+ * Returns: nothing of any use
+ *
+ * Narrative: Just print out all the junk
+ *
+ * Notes: This function is implemented using low level calls because
+ * of the likelyhood that the malloc tree is damaged when it
+ * is called. (Lots of things in the c library use malloc and
+ * we don't want to get into a catch-22).
+ *
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: dump.c,v 1.2 2006-07-25 10:07:38 rt Exp $";
+#endif
+
+
+#define ERRSTR "I/O Error on malloc dump file descriptor\n"
+
+#define WRITEOUT(fd,str,len) if( write(fd,str,(unsigned)len) != len ) \
+ { \
+ (void) write(2,ERRSTR,\
+ (unsigned)strlen(ERRSTR));\
+ exit(120); \
+ }
+
+void
+malloc_dump(fd)
+ int fd;
+{
+ char buffer[512];
+ void exit();
+ int i;
+ extern char * malloc_data_end;
+ extern char * malloc_data_start;
+ extern struct mlist * malloc_end;
+ extern struct mlist malloc_start;
+ struct mlist * ptr;
+
+ WRITEOUT(fd,"MALLOC CHAIN:\n",14);
+ WRITEOUT(fd,"-------------------- START ----------------\n",44);
+
+ for(i=0; i < 80; i++)
+ {
+ buffer[i] = ' ';
+ }
+
+ for(ptr = &malloc_start; ptr; ptr = ptr->next)
+ {
+ (void) tostring(buffer, (int)ptr, 8, B_HEX, '0');
+ (void) tostring(buffer+9, (int)ptr->next, 8, B_HEX, '0');
+ (void) tostring(buffer+18, (int)ptr->prev, 8, B_HEX, '0');
+ (void) tostring(buffer+27, (int)ptr->flag, 10, B_HEX, '0');
+ (void) tostring(buffer+38, (int)ptr->s.size, 8, B_DEC, ' ');
+ (void) tostring(buffer+47, (int)ptr->s.size, 8, B_HEX, '0');
+ (void) tostring(buffer+57, (int)ptr->data, 8, B_HEX, '0');
+ buffer[46] = '(';
+ buffer[55] = ')';
+ buffer[65] = '\n';
+ WRITEOUT(fd,buffer,66);
+ }
+ WRITEOUT(fd,"-------------------- DONE -----------------\n",44);
+
+ WRITEOUT(fd,"Malloc start: ",19);
+ (void) tostring(buffer, (int) &malloc_start, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+ WRITEOUT(fd,"Malloc end: ", 19);
+ (void) tostring(buffer, (int) malloc_end, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+ WRITEOUT(fd,"Malloc data start: ", 19);
+ (void) tostring(buffer, (int) malloc_data_start, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+ WRITEOUT(fd,"Malloc data end: ", 19);
+ (void) tostring(buffer, (int) malloc_data_end, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+} /* malloc_dump(... */
+
+
diff --git a/dmake/dbug/malloc/free.c b/dmake/dbug/malloc/free.c
new file mode 100644
index 000000000000..a8fc3ca259b6
--- /dev/null
+++ b/dmake/dbug/malloc/free.c
@@ -0,0 +1,150 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+#include "debug.h"
+
+/*
+ * Function: free()
+ *
+ * Purpose: to deallocate malloced data
+ *
+ * Arguments: ptr - pointer to data area to deallocate
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ * verify pointer is within malloc region
+ * get mlist pointer from passed address
+ * verify magic number
+ * verify inuse flag
+ * verify pointer connections with surrounding segments
+ * turn off inuse flag
+ * verify no data overrun into non-malloced area at end of segment
+ * IF possible join segment with next segment
+ * IF possible join segment with previous segment
+ * Clear all data in segment (to make sure it isn't reused)
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: free.c,v 1.2 2006-07-25 10:07:53 rt Exp $";
+#endif
+
+void
+free(cptr)
+ char * cptr;
+{
+ char * func = "free";
+ int i;
+ extern int malloc_checking;
+ extern struct mlist * malloc_end;
+ extern int malloc_errno;
+ extern char * malloc_data_end;
+ extern char * malloc_data_start;
+ void malloc_join();
+ void malloc_memset();
+ struct mlist * oldptr;
+ struct mlist * ptr;
+
+ /*
+ * IF malloc chain checking is on, go do it.
+ */
+ if( malloc_checking )
+ {
+ (void) malloc_chain_check(1);
+ }
+
+ /*
+ * verify that cptr is within the malloc region...
+ */
+ if( cptr < malloc_data_start || cptr > malloc_data_end )
+ {
+ malloc_errno = M_CODE_BAD_PTR;
+ malloc_warning(func);
+ return;
+ }
+
+ /*
+ * convert pointer to mlist struct pointer. To do this we must
+ * move the pointer backwards the correct number of bytes...
+ */
+
+ ptr = (struct mlist *) (cptr - M_SIZE);
+
+ if( (ptr->flag&M_MAGIC) != M_MAGIC )
+ {
+ malloc_errno = M_CODE_BAD_MAGIC;
+ malloc_warning(func);
+ return;
+ }
+
+ if( ! (ptr->flag & M_INUSE) )
+ {
+ malloc_errno = M_CODE_NOT_INUSE;
+ malloc_warning(func);
+ return;
+ }
+
+ if( (ptr->prev && (ptr->prev->next != ptr) ) ||
+ (ptr->next && (ptr->next->prev != ptr) ) ||
+ ((ptr->next == NULL) && (ptr->prev == NULL)) )
+ {
+ malloc_errno = M_CODE_BAD_CONNECT;
+ malloc_warning(func);
+ return;
+ }
+
+ ptr->flag &= ~M_INUSE;
+
+ /*
+ * verify that the user did not overrun the requested number of bytes.
+ */
+ for(i=ptr->r_size; i < ptr->s.size; i++)
+ {
+ if( ptr->data[i] != M_FILL )
+ {
+ malloc_errno = M_CODE_OVERRUN;
+ malloc_warning(func);
+ break;
+ }
+ }
+
+ DEBUG3(10,"pointers: prev: 0x%.7x, ptr: 0x%.7x, next: 0x%.7x",
+ ptr->prev, ptr, ptr->next);
+
+ DEBUG3(10,"size: prev: %9d, ptr: %9d, next: %9d",
+ ptr->prev->s.size, ptr->s.size, ptr->next->s.size);
+
+ DEBUG3(10,"flags: prev: 0x%.7x, ptr: 0x%.7x, next: 0x%.7x",
+ ptr->prev->flag, ptr->flag, ptr->next->flag);
+
+ /*
+ * check to see if this block can be combined with the next and/or
+ * previous block. Since it may be joined with the previous block
+ * we will save a pointer to the previous block and test to verify
+ * if it is joined (it's next ptr will no longer point to ptr).
+ */
+ malloc_join(ptr,ptr->next,0,0);
+
+ oldptr = ptr->prev;
+
+ malloc_join(ptr->prev, ptr,0,0);
+
+ if( oldptr->next != ptr )
+ {
+ DEBUG0(10,"Oldptr was changed");
+ ptr = oldptr;
+ }
+
+ /*
+ * fill this block with '\02's to ensure that nobody is using a
+ * pointer to already freed data...
+ */
+ malloc_memset(ptr->data,M_FREE_FILL,(int)ptr->s.size);
+
+}
+
diff --git a/dmake/dbug/malloc/m_init.c b/dmake/dbug/malloc/m_init.c
new file mode 100644
index 000000000000..d4fdc0788f4b
--- /dev/null
+++ b/dmake/dbug/malloc/m_init.c
@@ -0,0 +1,79 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+
+/*
+ * Function: malloc_init()
+ *
+ * Purpose: to initialize the pointers and variables use by the
+ * malloc() debugging library
+ *
+ * Arguments: none
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative: Just initialize all the needed variables. Use mallopt
+ * to set options taken from the environment.
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: m_init.c,v 1.2 2006-07-25 10:08:07 rt Exp $";
+#endif
+
+void
+malloc_init()
+{
+ char * cptr;
+ char * getenv();
+ union malloptarg m;
+ extern char * malloc_data_end;
+ extern char * malloc_data_start;
+ extern struct mlist * malloc_end;
+ extern struct mlist malloc_start;
+ char * sbrk();
+
+ /*
+ * If already initialized...
+ */
+ if( malloc_data_start != (char *) 0)
+ {
+ return;
+ }
+
+
+ malloc_data_start = sbrk(0);
+ malloc_data_end = malloc_data_start;
+ malloc_start.s.size = 0;
+ malloc_end = &malloc_start;
+
+ if( (cptr=getenv("MALLOC_WARN")) != NULL )
+ {
+ m.i = atoi(cptr);
+ (void) mallopt(MALLOC_WARN,m);
+ }
+
+ if( (cptr=getenv("MALLOC_FATAL")) != NULL)
+ {
+ m.i = atoi(cptr);
+ (void) mallopt(MALLOC_FATAL,m);
+ }
+
+ if( (cptr=getenv("MALLOC_CKCHAIN")) != NULL)
+ {
+ m.i = atoi(cptr);
+ (void) mallopt(MALLOC_CKCHAIN,m);
+ }
+
+ if( (cptr=getenv("MALLOC_ERRFILE")) != NULL)
+ {
+ m.str = cptr;
+ (void) mallopt(MALLOC_ERRFILE,m);
+ }
+
+}
+
diff --git a/dmake/dbug/malloc/m_perror.c b/dmake/dbug/malloc/m_perror.c
new file mode 100644
index 000000000000..b5620182ac4e
--- /dev/null
+++ b/dmake/dbug/malloc/m_perror.c
@@ -0,0 +1,73 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#ifndef lint
+static
+char rcsid[] = "$Id: m_perror.c,v 1.2 2006-07-25 10:08:21 rt Exp $";
+#endif
+
+/*
+ * malloc errno error strings...
+ */
+
+char *malloc_err_strings[] =
+{
+ "No errors",
+ "Malloc chain is corrupted, pointers out of order",
+ "Malloc chain is corrupted, end before end pointer",
+ "Pointer is not within malloc area",
+ "Malloc region does not have valid magic number in header",
+ "Pointers between this segment and ajoining segments are invalid",
+ "Data has overrun beyond requested number of bytes",
+ "Data in free'd area has been modified",
+ "Data are is not in use (can't be freed or realloced)",
+ "Unable to get additional memory from the system",
+ "Pointer within malloc region, but outside of malloc data bounds",
+ (char *) 0
+};
+
+/*
+ * Function: malloc_perror()
+ *
+ * Purpose: to print malloc_errno error message
+ *
+ * Arguments: str - string to print with error message
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ */
+void
+malloc_perror(str)
+ char * str;
+{
+ extern int malloc_errno;
+ register char * s;
+ register char * t;
+
+ if( str && *str)
+ {
+ for(s=str; *s; s++)
+ {
+ /* do nothing */;
+ }
+
+ (void) write(2,str,(unsigned)(s-str));
+ (void) write(2,": ",(unsigned)2);
+ }
+
+ t = malloc_err_strings[malloc_errno];
+
+ for(s=t; *s; s++)
+ {
+ /* do nothing */;
+ }
+
+ (void) write(2,t,(unsigned)(s-t));
+
+ (void) write(2,"\n",(unsigned)1);
+}
+
diff --git a/dmake/dbug/malloc/makefile b/dmake/dbug/malloc/makefile
new file mode 100644
index 000000000000..88395c7b8f6c
--- /dev/null
+++ b/dmake/dbug/malloc/makefile
@@ -0,0 +1,77 @@
+#
+# (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+# You may copy, distribute, and use this software as long as this
+# copyright statement is not removed.
+#
+#
+# This is the Makefile for the malloc debugging library
+#
+# $Id: makefile,v 1.1.1.1 2000-09-22 15:33:26 hr Exp $
+#
+CC=cc
+# for System V systems use this CFLAGS
+#CFLAGS=-g -DSYS5
+# else for BSD use:
+#CFLAGS=-g
+LINT=lint
+SHARCMD=shar -o mallocshar -l50 -x -a -n Malloclib
+SHELL=/bin/sh
+
+LIB=libmalloc.a
+
+SRCS= malloc.c \
+ free.c \
+ realloc.c \
+ calloc.c \
+ string.c \
+ mlc_chk.c \
+ mlc_chn.c \
+ memory.c \
+ tostring.c \
+ m_perror.c \
+ m_init.c \
+ mallopt.c \
+ dump.c
+
+OBJS= malloc.o \
+ free.o \
+ realloc.o \
+ calloc.o \
+ string.o \
+ mlc_chk.o \
+ mlc_chn.o \
+ memory.o \
+ tostring.o \
+ m_perror.o \
+ m_init.o \
+ mallopt.o \
+ dump.o
+
+TESTS=testmlc testmem
+
+all: $(LIB) $(TESTS)
+
+clean:
+ rm -f $(TESTS) pgm $(LIB) *.o *.ln
+
+sharfile:
+ $(SHARCMD) Makefile README patchlevel *.[ch3]
+
+$(LIB): $(OBJS)
+ ar ru $(LIB) $(OBJS)
+ -if test -s /bin/ranlib; then /bin/ranlib $(LIB); else exit 0; fi
+ -if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(LIB); else exit 0; fi
+
+testmlc: $(LIB) testmlc.o
+ $(CC) -o $@ testmlc.o $(LIB)
+
+testmem: $(LIB) testmem.o
+ $(CC) -o $@ testmem.o $(LIB)
+
+lint:
+ $(LINT) $(CFLAGS) $(SRCS) testmlc.c testmem.c
+
+
+$(OBJS): malloc.h
+
+tostring.o malloc.o dump.o: tostring.h
diff --git a/dmake/dbug/malloc/malloc.3 b/dmake/dbug/malloc/malloc.3
new file mode 100644
index 000000000000..f5e1d2dc0dab
--- /dev/null
+++ b/dmake/dbug/malloc/malloc.3
@@ -0,0 +1,223 @@
+.TH MALLOC 3 "" "" "1.0"
+.ds ]T
+.\"/*
+.\" * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+.\" * You may copy, distribute, and use this software as long as this
+.\" * copyright statement is not removed.
+.\" */
+.\" $Id: malloc.3,v 1.1.1.1 2000-09-22 15:33:26 hr Exp $
+.SH NAME
+malloc \t- debugging malloc library
+.SH SYNOPSIS
+.ft B
+.nf
+#include <malloc.h>
+
+char * calloc(nelem,elsize);
+void free(ptr);
+char * malloc(size);
+int malloc_chain_check(flag);
+void malloc_dump(fd);
+int mallopt(cmd,val)
+char * realloc(ptr,size);
+
+int cmd,fd,flag;
+unsigned elsize,nelem,size;
+char * ptr;
+union malloptarg val;
+
+.fi
+.ft R
+.SH DESCRIPTION
+This malloc library is a replacement for the standard library to be used
+during software development/debugging. See the standard malloc(3) pages
+for more information on the use of the following functions:
+.nf
+.in +.5i
+calloc(), free(), malloc(), realloc()
+.in -.5i
+.fi
+.sp
+This library differs from the standard malloc library in the
+following ways:
+.P
+1. Each malloc segment contains a magic number so that free can
+verify that the pointer passed points to a valid malloc segment.
+.P
+2. Each malloc segment is filled with a non-zero pattern so that code that
+depends upon malloc segments being null will fail.
+.P
+3. The size of each segment will be at least 1 byte larger than requested
+and the extra bytes will be filled with a non-zero pattern. When free is
+called, it will verify that you did not go beyond the number of bytes
+you asked for.
+.P
+4. When a segment is freed, it will be filled with a different non-zero pattern
+to ensure that the program doesn't depend upon the use of already freed data.
+.P
+5. Whenever any of the string or memory functions (str*, b*, mem*) are
+called with a pointer that is within the malloc arena, the operation is
+checked to verify that it does not overrun the malloced segment. A failure
+of this check is considered a "warning level error" (described later) and
+is handled accordingly.
+.P
+7. Run time checking can include verification of the malloc chain at each
+and every call to one of the malloc functions or manually by calling the
+malloc_chain_check function.
+.P
+6. When a problem is found, the action taken is specified at runtime by
+environment variables or at compile time by the use of the mallopt()
+function.
+.P
+There are two arbitrary levels of errors, warning and fatal, that this
+library will detect. They are broken down as follows:
+.P
+.nf
+.in +.25i
+Warning messages include:
+.sp
+.in +.5i
+.ti -.25i
+Calling free with a bad pointer
+.br
+.ti -.25i
+Calling a bstring/string/memory (3) function which will go beyond
+the end of a malloc block. Note that the library function is
+not modified to refuse the operation.
+.sp
+.in -.5i
+Fatal errors are:
+.in +.5i
+.ti -.25i
+Detectable corruption to the malloc chain.
+.in -.5i
+.in -.25i
+.P
+The error handling for each level (warning or fatal) are specified using
+environment variables or mallopt(). The coding for the error handling is
+as follows:
+.sp
+.nf
+.in +.5i
+.ti -.25i
+ 0 - continue operations
+.ti -.25i
+ 1 - drop core and exit
+.ti -.25i
+ 2 - just exit
+.ti -.25i
+ 3 - drop core, but continue executing. Core files will
+be placed into core.[PID].[counter] i.e: core.00123.001
+.ti -.25i
+128 - dump malloc chain and continue
+.ti -.25i
+129 - dump malloc chain, dump core, and exit
+.ti -.25i
+130 - dump malloc chain, exit
+.ti -.25i
+131 - dump malloc chain, dump core, continue processing
+.in -.5i
+.P
+In addition error messages can be placed into an error file.
+.P
+\fBmalloc_opt\fP() is used to set the malloc debugging options. The
+following options can be set:
+.br
+.sp
+.in +.5i
+MALLOC_WARN - set the error handling for warning level errors. \fBval.i\fP is
+an integer that can contain any one of the following values:
+.sp
+.in +.5i
+M_HANDLE_IGNORE - ignore error
+.br
+M_HANDLE_ABORT - drop core and exit
+.br
+M_HANDLE_EXIT - just exit (no core drop)
+.br
+M_HANDLE_CORE - drop core, but keep on going
+.br
+.in -.5i
+.sp
+In addition, M_HANDLE_DUMP may be or'd in to cause a dump of the current
+malloc chain.
+.br
+.sp
+MALLOC_FATAL - set the error handling for fatal level errors. \fBval.i\fP is
+equivalent to \fBval.i\fP for MALLOC_WARN.
+.br
+.sp
+MALLOC_ERRFILE - set the destination for malloc error messages. \fBval.str\fP
+is a pointer to a character string containing the name of the file to be used
+for error messages.
+.br
+.sp
+MALLOC_CKCHAIN - set the malloc chain checking flag. If \fBval.i\fP is
+non-zero, chain checking at every call to malloc is turned on.
+.br
+.sp
+For example, to set up the session to generate a core file for
+every malloc warning, to drop core and exit on a malloc fatal, and
+to log all messages to the file "malloc_log" do the following:
+.sp
+.nf
+.in +.5i
+#include <malloc.h>
+malloc_opt(MALLOC_WARN,131);
+malloc_opt(MALLOC_FATAL,1);
+malloc_opt(MALLOC_ERRFILE,"malloc_log");
+.in -.5i
+.fi
+.in -.5i
+.sp
+\fBmalloc_opt\fP() can be used to set/alter the debugging options at any
+time.
+.P
+\fBmalloc_dump\fP() will dump a table of the malloc arena showing all
+allocated/freed segments and the first few bytes of data in each segment.
+\fBfd\fP is the file descriptor to write the data to.
+.P
+\fBmalloc_chain_check\fP() will check the status of the malloc arena.
+If \fBflag\fP is non-zero, an error found in the chain will cause a
+fatal error. \fBmalloc_chain_check\fP() returns zero when there are no
+problems found in the malloc chain, non-zero otherwise.
+.SH "ENVIRONMENT VARIABLES"
+Environment variables can be used to control error handling, error logging
+and malloc chain checking at run time. The following environment variables
+are used:
+.P
+MALLOC_WARN - specifies the error handling for warning errors
+.br
+MALLOC_FATAL - specifies the error handling for fatal errors
+.br
+MALLOC_ERRFILE - specifies the error log file for error messages.
+.br
+MALLOC_CKCHAIN - if 1, turns on malloc chain checking at every call to any
+of the malloc functions.
+.P
+For example, to set up the session to generate a core file for
+every malloc warning, to drop core and exit on a malloc fatal, and
+to log all messages to the file "malloc_log" do the following:
+.sp
+.nf
+.in +.5i
+MALLOC_WARN=131
+MALLOC_FATAL=1
+MALLOC_ERRFILE=malloc_log
+
+export MALLOC_WARN MALLOC_FATAL MALLOC_ERRFILE
+.in -.5i
+.fi
+.SH WARNINGS
+This malloc library and it's associated string and memory functions are
+much less efficient than the standard functions due in part to the extra
+error checking. You do not want to use this library when generating a
+production (i.e. releasable) version of your software. It should only
+be used during development and testing.
+.SH SEE ALSO
+stat(2)
+.SH AUTHOR
+Conor P. Cahill
+Virtual Technologies Incorporated
+.sp
+uunet!virtech!cpcahil
diff --git a/dmake/dbug/malloc/malloc.c b/dmake/dbug/malloc/malloc.c
new file mode 100644
index 000000000000..ff84e3efce9f
--- /dev/null
+++ b/dmake/dbug/malloc/malloc.c
@@ -0,0 +1,627 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include "malloc.h"
+#include "tostring.h"
+
+/*
+ * Function: malloc()
+ *
+ * Purpose: memory allocator
+ *
+ * Arguments: size - size of data area needed
+ *
+ * Returns: pointer to allocated area, or NULL if unable
+ * to allocate addtional data.
+ *
+ * Narrative:
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: malloc.c,v 1.2 2006-07-25 10:08:36 rt Exp $";
+#endif
+
+extern int malloc_checking;
+char * malloc_data_start;
+char * malloc_data_end;
+struct mlist * malloc_end;
+int malloc_errfd = 2;
+int malloc_errno;
+int malloc_fatal_level = M_HANDLE_CORE;
+struct mlist malloc_start;
+int malloc_warn_level;
+void malloc_memset();
+
+char *
+malloc(size)
+ unsigned int size;
+{
+ char * func = "malloc";
+ char * getenv();
+ void malloc_fatal();
+ void malloc_init();
+ void malloc_split();
+ void malloc_warning();
+ unsigned int need;
+ struct mlist * oldptr;
+ struct mlist * ptr;
+ char * sbrk();
+
+ /*
+ * If this is the first call to malloc...
+ */
+ if( malloc_data_start == (char *) 0 )
+ {
+ malloc_init();
+ }
+
+ /*
+ * If malloc chain checking is on, go do it.
+ */
+ if( malloc_checking )
+ {
+ (void) malloc_chain_check(1);
+ }
+
+ /*
+ * always make sure there is at least on extra byte in the malloc
+ * area so that we can verify that the user does not overrun the
+ * data area.
+ */
+ size++;
+
+ /*
+ * Now look for a free area of memory of size bytes...
+ */
+ oldptr = NULL;
+ for(ptr = &malloc_start; ; ptr = ptr->next)
+ {
+ /*
+ * Since the malloc chain is a forward only chain, any
+ * pointer that we get should always be positioned in
+ * memory following the previous pointer. If this is not
+ * so, we must have a corrupted chain.
+ */
+ if( ptr )
+ {
+ if( ptr<oldptr )
+ {
+ malloc_errno = M_CODE_CHAIN_BROKE;
+ malloc_fatal(func);
+ return(NULL);
+ }
+ oldptr = ptr;
+ }
+ else if( oldptr != malloc_end )
+ {
+ /*
+ * This should never happen. If it does, then
+ * we got a real problem.
+ */
+ malloc_errno = M_CODE_NO_END;
+ malloc_fatal(func);
+ return(NULL);
+ }
+
+
+ /*
+ * if this element is already in use...
+ */
+ if( ptr && ((ptr->flag & M_INUSE) != 0) )
+ {
+ continue;
+ }
+
+ /*
+ * if there isn't room for this block..
+ */
+ if( ptr && (ptr->s.size < size) )
+ {
+ continue;
+ }
+
+ /*
+ * If ptr is null, we have run out of memory and must sbrk more
+ */
+ if( ptr == NULL )
+ {
+ need = (size + M_SIZE) * (size > 10*1024 ? 1:2);
+ if( need < M_BLOCKSIZE )
+ {
+ need = M_BLOCKSIZE;
+ }
+ else if( need & (M_BLOCKSIZE-1) )
+ {
+ need &= ~(M_BLOCKSIZE-1);
+ need += M_BLOCKSIZE;
+ }
+ ptr = (struct mlist *) sbrk((int)need);
+ if( ptr == (struct mlist *) -1 )
+ {
+ malloc_errno = M_CODE_NOMORE_MEM;
+ malloc_fatal(func);
+ }
+ malloc_data_end = sbrk((int)0);
+
+ ptr->prev = oldptr;
+ ptr->next = (struct mlist *) 0;
+ ptr->s.size = need - M_SIZE;
+ ptr->flag = M_MAGIC;
+
+ oldptr->next = ptr;
+ malloc_end = ptr;
+
+
+ } /* if( ptr ==... */
+
+ /*
+ * Now ptr points to a memory location that can store
+ * this data, so lets go to work.
+ */
+
+ ptr->r_size = size; /* save requested size */
+ ptr->flag |= M_INUSE;
+
+ /*
+ * split off unneeded data area in this block, if possible...
+ */
+ malloc_split(ptr);
+
+ /*
+ * re-adjust the requested size so that it is what the user
+ * actually requested...
+ */
+
+ ptr->r_size--;
+
+ /*
+ * just to make sure that noone is misusing malloced
+ * memory without initializing it, lets set it to
+ * all '\01's. We call local_memset() because memset()
+ * may be checking for malloc'd ptrs and this isn't
+ * a malloc'd ptr yet.
+ */
+ malloc_memset(ptr->data,M_FILL,(int)ptr->s.size);
+
+ return( ptr->data);
+
+ } /* for(... */
+
+} /* malloc(... */
+
+/*
+ * Function: malloc_split()
+ *
+ * Purpose: to split a malloc segment if there is enough room at the
+ * end of the segment that isn't being used
+ *
+ * Arguments: ptr - pointer to segment to split
+ *
+ * Returns: nothing of any use.
+ *
+ * Narrative:
+ * get the needed size of the module
+ * round the size up to appropriat boundry
+ * calculate amount of left over space
+ * if there is enough left over space
+ * create new malloc block out of remainder
+ * if next block is free
+ * join the two blocks together
+ * fill new empty block with free space filler
+ * re-adjust pointers and size of current malloc block
+ *
+ *
+ *
+ * Mod History:
+ * 90/01/27 cpcahil Initial revision.
+ */
+void
+malloc_split(ptr)
+ struct mlist * ptr;
+{
+ extern struct mlist * malloc_end;
+ void malloc_join();
+ int rest;
+ int size;
+ struct mlist * tptr;
+
+ size = ptr->r_size;
+
+ /*
+ * roundup size to the appropriate boundry
+ */
+
+ M_ROUNDUP(size);
+
+ /*
+ * figure out how much room is left in the array.
+ * if there is enough room, create a new mlist
+ * structure there.
+ */
+
+ if( ptr->s.size > size )
+ {
+ rest = ptr->s.size - size;
+ }
+ else
+ {
+ rest = 0;
+ }
+
+ if( rest > (M_SIZE+M_RND) )
+ {
+ tptr = (struct mlist *) (ptr->data+size);
+ tptr->prev = ptr;
+ tptr->next = ptr->next;
+ tptr->flag = M_MAGIC;
+ tptr->s.size = rest - M_SIZE;
+
+ /*
+ * If possible, join this segment with the next one
+ */
+
+ malloc_join(tptr, tptr->next,0,0);
+
+ if( tptr->next )
+ {
+ tptr->next->prev = tptr;
+ }
+
+ malloc_memset(tptr->data,M_FREE_FILL, (int)tptr->s.size);
+
+ ptr->next = tptr;
+ ptr->s.size = size;
+
+ if( malloc_end == ptr )
+ {
+ malloc_end = tptr;
+ }
+ }
+
+} /* malloc_split(... */
+
+/*
+ * Function: malloc_join()
+ *
+ * Purpose: to join two malloc segments together (if possible)
+ *
+ * Arguments: ptr - pointer to segment to join to.
+ * nextptr - pointer to next segment to join to ptr.
+ *
+ * Returns: nothing of any values.
+ *
+ * Narrative:
+ *
+ * Mod History:
+ * 90/01/27 cpcahil Initial revision.
+ */
+void
+malloc_join(ptr,nextptr, inuse_override, fill_flag)
+ struct mlist * ptr;
+ struct mlist * nextptr;
+ int inuse_override;
+ int fill_flag;
+{
+ unsigned int newsize;
+
+ if( ptr && ! (inuse_override || (ptr->flag & M_INUSE)) &&
+ nextptr && ! (nextptr->flag & M_INUSE) &&
+ ((ptr->data+ptr->s.size) == (char *) nextptr) )
+ {
+ if( malloc_end == nextptr )
+ {
+ malloc_end = ptr;
+ }
+ ptr->next = nextptr->next;
+ newsize = nextptr->s.size + M_SIZE;
+
+ /*
+ * if we are to fill and this segment is in use,
+ * fill in with M_FILL newly added space...
+ */
+
+ if(fill_flag && (ptr->flag & M_INUSE) )
+ {
+ malloc_memset(ptr->data+ptr->s.size,
+ M_FILL, (int)(nextptr->s.size + M_SIZE));
+ }
+
+ ptr->s.size += newsize;
+ if( ptr->next )
+ {
+ ptr->next->prev = ptr;
+ }
+ }
+
+} /* malloc_join(... */
+
+
+/*
+ * The following mess is just to ensure that the versions of these functions in
+ * the current library are included (to make sure that we don't accidentaly get
+ * the libc versions. (This is the lazy man's -u ld directive)
+ */
+
+void free();
+int strcmp();
+int memcmp();
+char * realloc();
+
+void (*malloc_void_funcs[])() =
+{
+ free,
+};
+
+int (*malloc_int_funcs[])() =
+{
+ strcmp,
+ memcmp,
+};
+
+char * (*malloc_char_star_funcs[])() =
+{
+ realloc,
+};
+
+/*
+ * This is malloc's own memset which is used without checking the parameters.
+ */
+
+void
+malloc_memset(ptr,byte,len)
+ char * ptr;
+ char byte;
+ int len;
+{
+
+ while(len-- > 0)
+ {
+ *ptr++ = byte;
+ }
+
+} /* malloc_memset(... */
+
+/*
+ * Function: malloc_fatal()
+ *
+ * Purpose: to display fatal error message and take approrpriate action
+ *
+ * Arguments: funcname - name of function calling this routine
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ * Notes: This routine does not make use of any libc functions to build
+ * and/or disply the error message. This is due to the fact that
+ * we are probably at a point where malloc is having a real problem
+ * and we don't want to call any function that may use malloc.
+ */
+void
+malloc_fatal(funcname)
+ char * funcname;
+{
+ char errbuf[128];
+ void exit();
+ void malloc_err_handler();
+ extern char * malloc_err_strings[];
+ extern int malloc_errno;
+ extern int malloc_fatal_level;
+ char * s;
+ char * t;
+
+ s = errbuf;
+ t = "Fatal error: ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+ t = funcname;
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = "(): ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = malloc_err_strings[malloc_errno];
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ *(s++) = '\n';
+
+ if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
+ {
+ (void) write(2,"I/O error to error file\n",(unsigned)24);
+ exit(110);
+ }
+ malloc_err_handler(malloc_fatal_level);
+
+} /* malloc_fatal(... */
+
+/*
+ * Function: malloc_warning()
+ *
+ * Purpose: to display warning error message and take approrpriate action
+ *
+ * Arguments: funcname - name of function calling this routine
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ * Notes: This routine does not make use of any libc functions to build
+ * and/or disply the error message. This is due to the fact that
+ * we are probably at a point where malloc is having a real problem
+ * and we don't want to call any function that may use malloc.
+ */
+void
+malloc_warning(funcname)
+ char * funcname;
+{
+ char errbuf[128];
+ void exit();
+ void malloc_err_handler();
+ extern char * malloc_err_strings[];
+ extern int malloc_errno;
+ extern int malloc_warn_level;
+ char * s;
+ char * t;
+
+ s = errbuf;
+ t = "Warning: ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+ t = funcname;
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = "(): ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = malloc_err_strings[malloc_errno];
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ *(s++) = '\n';
+
+ if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
+ {
+ (void) write(2,"I/O error to error file\n",(unsigned)24);
+ exit(110);
+ }
+
+ malloc_err_handler(malloc_warn_level);
+
+} /* malloc_warning(... */
+
+/*
+ * Function: malloc_err_handler()
+ *
+ * Purpose: to take the appropriate action for warning and/or fatal
+ * error conditions.
+ *
+ * Arguments: level - error handling level
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ * Notes: This routine does not make use of any libc functions to build
+ * and/or disply the error message. This is due to the fact that
+ * we are probably at a point where malloc is having a real problem
+ * and we don't want to call any function that may use malloc.
+ */
+void
+malloc_err_handler(level)
+{
+ void exit();
+ void malloc_dump();
+ extern int malloc_errfd;
+
+ if( level & M_HANDLE_DUMP )
+ {
+ malloc_dump(malloc_errfd);
+ }
+
+ switch( level & ~M_HANDLE_DUMP )
+ {
+ /*
+ * If we are to drop a core file and exit
+ */
+ case M_HANDLE_ABORT:
+ (void) abort();
+ break;
+
+ /*
+ * If we are to exit..
+ */
+ case M_HANDLE_EXIT:
+ exit(200);
+ break;
+
+#ifndef __MSDOS__
+ /*
+ * If we are to dump a core, but keep going on our merry way
+ */
+ case M_HANDLE_CORE:
+ {
+ int pid;
+
+ /*
+ * fork so child can abort (and dump core)
+ */
+ if( (pid = fork()) == 0 )
+ {
+ (void) write(2,"Child dumping core\n",
+ (unsigned)9);
+ (void) abort();
+ }
+
+ /*
+ * wait for child to finish dumping core
+ */
+ while( wait((int *)0) != pid)
+ {
+ }
+
+ /*
+ * Move core file to core.pid.cnt so
+ * multiple cores don't overwrite each
+ * other.
+ */
+ if( access("core",0) == 0 )
+ {
+ static int corecnt;
+ char filenam[32];
+ filenam[0] = 'c';
+ filenam[1] = 'o';
+ filenam[2] = 'r';
+ filenam[3] = 'e';
+ filenam[4] = '.';
+ (void)tostring(filenam+5,getpid(),
+ 5, B_DEC, '0');
+ filenam[10] = '.';
+ (void)tostring(filenam+11,corecnt++,
+ 3, B_DEC, '0');
+ filenam[14] = '\0';
+ (void) unlink(filenam);
+ if( link("core",filenam) == 0)
+ {
+ (void) unlink("core");
+ }
+ }
+ }
+#endif
+
+
+ /*
+ * If we are to just ignore the error and keep on processing
+ */
+ case M_HANDLE_IGNORE:
+ break;
+
+ } /* switch(... */
+
+} /* malloc_err_handler(... */
+
diff --git a/dmake/dbug/malloc/malloc.h b/dmake/dbug/malloc/malloc.h
new file mode 100644
index 000000000000..ed8c34f2a333
--- /dev/null
+++ b/dmake/dbug/malloc/malloc.h
@@ -0,0 +1,85 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+/*
+ * $Id: malloc.h,v 1.2 2006-07-25 10:08:50 rt Exp $
+ */
+struct mlist
+{
+ struct mlist * next; /* next entry in chain */
+ struct mlist * prev; /* prev entry in chain */
+ int flag; /* inuse flag */
+ unsigned int r_size; /* requested size */
+ union
+ {
+ unsigned int size; /* actual size */
+ double unused_just_for_alignment;
+ } s;
+ char data[4];
+};
+
+#define M_SIZE ((int)(char *)((struct mlist *)0)->data)
+#define M_RND 0x08
+
+#define M_INUSE 0x01
+#define M_MAGIC 0x03156100
+
+#define M_BLOCKSIZE (1024*8)
+
+#define M_FILL '\01'
+#define M_FREE_FILL '\02'
+
+#define M_ROUNDUP(size) {\
+ if( size & (M_RND-1) ) \
+ { \
+ size &= ~(M_RND-1); \
+ size += M_RND; \
+ } \
+ }
+
+/*
+ * Malloc warning/fatal error handler defines...
+ */
+#define M_HANDLE_DUMP 0x80 /* 128 */
+#define M_HANDLE_IGNORE 0
+#define M_HANDLE_ABORT 1
+#define M_HANDLE_EXIT 2
+#define M_HANDLE_CORE 3
+
+/*
+ * Mallopt commands and defaults
+ */
+
+#define MALLOC_WARN 1 /* set malloc warning handling */
+#define MALLOC_FATAL 2 /* set malloc fatal handling */
+#define MALLOC_ERRFILE 3 /* specify malloc error file */
+#define MALLOC_CKCHAIN 4 /* turn on chain checking */
+union malloptarg
+{
+ int i;
+ char * str;
+};
+
+/*
+ * Malloc warning/fatal error codes
+ */
+
+#define M_CODE_CHAIN_BROKE 1 /* malloc chain is broken */
+#define M_CODE_NO_END 2 /* chain end != endptr */
+#define M_CODE_BAD_PTR 3 /* pointer not in malloc area */
+#define M_CODE_BAD_MAGIC 4 /* bad magic number in header */
+#define M_CODE_BAD_CONNECT 5 /* chain poingers corrupt */
+#define M_CODE_OVERRUN 6 /* data overrun in malloc seg */
+#define M_CODE_REUSE 7 /* reuse of freed area */
+#define M_CODE_NOT_INUSE 8 /* pointer is not in use */
+#define M_CODE_NOMORE_MEM 9 /* no more memory available */
+#define M_CODE_OUTOF_BOUNDS 10 /* gone beyound bounds */
+
+void malloc_warning();
+void malloc_fatal();
+void malloc_check_data();
+void malloc_check_str();
+void malloc_verify();
+
diff --git a/dmake/dbug/malloc/mallopt.c b/dmake/dbug/malloc/mallopt.c
new file mode 100644
index 000000000000..d70daf88647a
--- /dev/null
+++ b/dmake/dbug/malloc/mallopt.c
@@ -0,0 +1,98 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include "malloc.h"
+
+/*
+ * Function: mallopt()
+ *
+ * Purpose: to set options for the malloc debugging library
+ *
+ * Arguments: none
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: mallopt.c,v 1.2 2006-07-25 10:09:05 rt Exp $";
+#endif
+
+int
+mallopt(cmd,value)
+ int cmd;
+ union malloptarg value;
+{
+ int i;
+ extern int malloc_checking;
+ extern char * malloc_data_start;
+ extern int malloc_errfd;
+ extern int malloc_fatal_level;
+ void malloc_init();
+ extern int malloc_warn_level;
+ register char * s;
+
+ /*
+ * If not initialized...
+ */
+ if( malloc_data_start == (char *) 0)
+ {
+ malloc_init();
+ }
+
+
+ switch(cmd)
+ {
+ case MALLOC_WARN:
+ malloc_warn_level = value.i;
+ break;
+
+ case MALLOC_FATAL:
+ malloc_fatal_level = value.i;
+ break;
+
+ case MALLOC_CKCHAIN:
+ malloc_checking = value.i;
+ break;
+
+ case MALLOC_ERRFILE:
+
+ i = open(value.str,O_CREAT|O_APPEND|O_WRONLY,0666);
+ if( i == -1 )
+ {
+ (void) write(2,
+ "Unable to open malloc error file: ",
+ (unsigned) 34);
+ for(s=value.str; *s; s++)
+ {
+ /* do nothing */;
+ }
+ (void) write(2,value.str,
+ (unsigned)(s-value.str));
+ (void) write(2,"\n",(unsigned)1);
+ }
+ else
+ {
+ if( malloc_errfd != 2 )
+ {
+ (void) close(malloc_errfd);
+ }
+ malloc_errfd = i;
+ }
+
+ break;
+
+ default:
+ return(1);
+ }
+
+ return(0);
+}
+
diff --git a/dmake/dbug/malloc/memory.c b/dmake/dbug/malloc/memory.c
new file mode 100644
index 000000000000..b2087a76f5af
--- /dev/null
+++ b/dmake/dbug/malloc/memory.c
@@ -0,0 +1,195 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: memory.c,v 1.2 2006-07-25 10:09:19 rt Exp $";
+#endif
+
+void malloc_check_data();
+
+char *
+memccpy(ptr1, ptr2, ch, len)
+ register char * ptr1;
+ register char * ptr2;
+ int len;
+ int ch;
+{
+ int check;
+ register int i;
+ char * rtn;
+
+ /*
+ * I know that the assignment could be done in the following, but
+ * I wanted to perform a check before any assignment, so first I
+ * determine the length, check the pointers and then do the assignment.
+ */
+ for( i=0; (i < len) && (ptr2[i] != ch); i++)
+ {
+ }
+ if( ptr2[i] == ch )
+ {
+ check = i+1;
+ }
+ else
+ {
+ check = len;
+ }
+
+ malloc_check_data("memccpy", ptr1, check);
+ malloc_check_data("memccpy", ptr2, check);
+
+ /*
+ * if we found the character...
+ */
+
+ if( i < len )
+ {
+ rtn = ptr1+i+1;
+ i++;
+ }
+ else
+ {
+ rtn = (char *) 0;
+ }
+
+ while( i-- )
+ {
+ *(ptr1++) = *(ptr2++);
+ }
+
+ return(rtn);
+}
+
+char *
+memchr(ptr1,ch,len)
+ register char * ptr1;
+ register int ch;
+ int len;
+{
+ int i;
+
+ for( i=0; (i < len) && (ptr1[i] != (char) ch); i++)
+ {
+ }
+
+ malloc_check_data("memchr", ptr1, i);
+
+ if( i < len )
+ {
+ return( ptr1+i );
+ }
+ else
+ {
+ return( (char *) 0);
+ }
+}
+
+char *
+memcpy(ptr1, ptr2, len)
+ register char * ptr1;
+ register char * ptr2;
+ register int len;
+{
+ char * rtn = ptr1;
+
+ malloc_check_data("memcpy", ptr1, len);
+ malloc_check_data("memcpy", ptr2, len);
+
+ /*
+ * while the normal memcpy does not guarrantee that it will
+ * handle overlapping memory correctly, we will try...
+ */
+ if( ptr1 > ptr2 && ptr1 < (ptr2+len))
+ {
+ ptr1 += (len-1);
+ ptr2 += (len-1);
+ while( len-- > 0 )
+ {
+ *(ptr1--) = *(ptr2--);
+ }
+ }
+ else
+ {
+ while( len-- > 0 )
+ {
+ *(ptr1++) = *(ptr2++);
+ }
+ }
+
+ return(rtn);
+}
+
+int
+memcmp(ptr1, ptr2, len)
+ register char * ptr1;
+ register char * ptr2;
+ register int len;
+{
+ malloc_check_data("memcpy", ptr1, len);
+ malloc_check_data("memcpy", ptr2, len);
+
+ while( --len >= 0 && (*ptr1 == *ptr2) )
+ {
+ ptr1++;
+ ptr2++;
+ }
+
+ /*
+ * If stopped by len, return zero
+ */
+ if( len < 0 )
+ {
+ return(0);
+ }
+
+ return( *ptr1 - *ptr2 );
+}
+
+char *
+memset(ptr1, ch, len)
+ register char * ptr1;
+ register int ch;
+ register int len;
+{
+ char * rtn = ptr1;
+
+ malloc_check_data("memcpy", ptr1, len);
+
+ while( len-- )
+ {
+ *(ptr1++) = ch;
+ }
+
+ return(rtn);
+}
+
+char *
+bcopy(ptr2,ptr1,len)
+ char * ptr2;
+ char * ptr1;
+ int len;
+{
+ return(memcpy(ptr1,ptr2,len));
+}
+
+char *
+bzero(ptr1,len)
+ char * ptr1;
+ int len;
+{
+ return(memset(ptr1,'\0',len));
+}
+
+int
+bcmp(ptr2, ptr1, len)
+ char * ptr1;
+ char * ptr2;
+ int len;
+{
+ return( memcmp(ptr1,ptr2,len) );
+}
+
diff --git a/dmake/dbug/malloc/mlc_chk.c b/dmake/dbug/malloc/mlc_chk.c
new file mode 100644
index 000000000000..08a01172cb66
--- /dev/null
+++ b/dmake/dbug/malloc/mlc_chk.c
@@ -0,0 +1,256 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#include <stdio.h>
+#include "malloc.h"
+#include "debug.h"
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: mlc_chk.c,v 1.2 2006-07-25 10:09:34 rt Exp $";
+#endif
+
+extern struct mlist malloc_start;
+extern struct mlist * malloc_end;
+extern char * malloc_data_start;
+extern char * malloc_data_end;
+
+/*
+ * Function: malloc_in_arena()
+ *
+ * Purpose: to verify address is within malloc arena.
+ *
+ * Arguments: ptr - pointer to verify
+ *
+ * Returns: TRUE - if pointer is within malloc area
+ * FALSE - otherwise
+ *
+ * Narrative:
+ * IF pointer is >= malloc area start AND <= malloc area end
+ * return TRUE
+ * ELSE
+ * return FALSE
+ *
+ * Mod History:
+ * 90/01/24 cpcahil Initial revision.
+ */
+int
+malloc_in_arena(ptr)
+ char * ptr;
+{
+ extern char * malloc_data_start;
+ extern char * malloc_data_end;
+ int rtn = 0;
+
+ if( ptr >= malloc_data_start && ptr <= malloc_data_end )
+ {
+ rtn = 1;
+ }
+
+ return(rtn);
+}
+
+/*
+ * Function: malloc_check_str()
+ *
+ * Arguments: func - name of function calling this routine
+ * str - pointer to area to check
+ *
+ * Purpose: to verify that if str is within the malloc arena, the data
+ * it points to does not extend beyond the applicable region.
+ *
+ * Returns: Nothing of any use (function is void).
+ *
+ * Narrative:
+ * IF pointer is within malloc arena
+ * determin length of string
+ * call malloc_verify() to verify data is withing applicable region
+ * return
+ *
+ * Mod History:
+ * 90/01/24 cpcahil Initial revision.
+ * 90/01/29 cpcahil Added code to ignore recursive calls.
+ */
+void
+malloc_check_str(func,str)
+ char * func;
+ char * str;
+{
+ static int layers;
+ register char * s;
+
+ if( (layers++ == 0) && malloc_in_arena(str) )
+ {
+ for( s=str; *s; s++)
+ {
+ }
+
+ malloc_verify(func,str,s-str+1);
+ }
+
+ layers--;
+}
+
+/*
+ * Function: malloc_check_strn()
+ *
+ * Arguments: func - name of function calling this routine
+ * str - pointer to area to check
+ * len - max length of string
+ *
+ * Purpose: to verify that if str is within the malloc arena, the data
+ * it points to does not extend beyond the applicable region.
+ *
+ * Returns: Nothing of any use (function is void).
+ *
+ * Narrative:
+ * IF pointer is within malloc arena
+ * determin length of string
+ * call malloc_verify() to verify data is withing applicable region
+ * return
+ *
+ * Mod History:
+ * 90/01/24 cpcahil Initial revision.
+ * 90/01/29 cpcahil Added code to ignore recursive calls.
+ * 90/08/29 cpcahil added length (for strn* functions)
+ */
+void
+malloc_check_strn(func,str,len)
+ char * func;
+ char * str;
+ int len;
+{
+ register int i;
+ static int layers;
+ register char * s;
+
+ if( (layers++ == 0) && malloc_in_arena(str) )
+ {
+ for( s=str,i=0; (i < len) && *s; s++)
+ {
+ }
+
+ malloc_verify(func,str,s-str+1);
+ }
+
+ layers--;
+}
+
+/*
+ * Function: malloc_check_data()
+ *
+ * Arguments: func - name of function calling this routine
+ * ptr - pointer to area to check
+ * len - length to verify
+ *
+ * Purpose: to verify that if ptr is within the malloc arena, the data
+ * it points to does not extend beyond the applicable region.
+ *
+ * Returns: Nothing of any use (function is void).
+ *
+ * Narrative:
+ * IF pointer is within malloc arena
+ * call malloc_verify() to verify data is withing applicable region
+ * return
+ *
+ * Mod History:
+ * 90/01/24 cpcahil Initial revision.
+ * 90/01/29 cpcahil Added code to ignore recursive calls.
+ */
+void
+malloc_check_data(func,ptr,len)
+ char * func;
+ char * ptr;
+ int len;
+{
+ static int layers;
+
+ if( layers++ == 0 )
+ {
+ DEBUG3(40,"malloc_check_data(%s,0x%x,%d) called...",
+ func,ptr,len);
+ if( malloc_in_arena(ptr) )
+ {
+ DEBUG0(10,"pointer in malloc arena, verifying...");
+ malloc_verify(func,ptr,len);
+ }
+ }
+
+ layers--;
+}
+
+/*
+ * Function: malloc_verify()
+ *
+ * Arguments: func - name of function calling the malloc check routines
+ * ptr - pointer to area to check
+ * len - length to verify
+ *
+ * Purpose: to verify that the data ptr points to does not extend beyond
+ * the applicable malloc region. This function is only called
+ * if it has been determined that ptr points into the malloc arena.
+ *
+ * Returns: Nothing of any use (function is void).
+ *
+ * Narrative:
+ *
+ * Mod History:
+ * 90/01/24 cpcahil Initial revision.
+ */
+void
+malloc_verify(func,ptr,len)
+ char * func;
+ char * ptr;
+ int len;
+{
+ extern struct mlist * malloc_end;
+ extern int malloc_errno;
+ extern struct mlist malloc_start;
+ struct mlist * mptr;
+
+ DEBUG3(40,"malloc_verify(%s,0x%x,%d) called...", func,ptr,len);
+ /*
+ * Find the malloc block that includes this pointer
+ */
+ mptr = &malloc_start;
+ while( mptr &&
+ ! (((char *)mptr < ptr) && ((mptr->data+mptr->s.size) > ptr) ) )
+ {
+ mptr = mptr->next;
+ }
+
+ /*
+ * if ptr was not in a malloc block, it must be part of
+ * some direct sbrk() stuff, so just return.
+ */
+ if( ! mptr )
+ {
+ DEBUG1(10,"ptr (0x%x) not found in malloc search", ptr);
+ return;
+ }
+
+ /*
+ * Now we have a valid malloc block that contains the indicated
+ * pointer. We must verify that it is withing the requested block
+ * size (as opposed to the real block size which is rounded up to
+ * allow for correct alignment).
+ */
+
+ DEBUG4(60,"Checking 0x%x-0x%x, 0x%x-0x%x",
+ ptr, ptr+len, mptr->data, mptr->data+mptr->r_size);
+
+ if( (ptr < mptr->data) || ((ptr+len) > (mptr->data+mptr->r_size)) )
+ {
+ DEBUG4(0,"pointer not within region 0x%x-0x%x, 0x%x-0x%x",
+ ptr, ptr+len, mptr->data, mptr->data+mptr->r_size);
+
+ malloc_errno = M_CODE_OUTOF_BOUNDS;
+ malloc_warning(func);
+ }
+
+ return;
+}
+
diff --git a/dmake/dbug/malloc/mlc_chn.c b/dmake/dbug/malloc/mlc_chn.c
new file mode 100644
index 000000000000..3f24333611f9
--- /dev/null
+++ b/dmake/dbug/malloc/mlc_chn.c
@@ -0,0 +1,188 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include "malloc.h"
+
+/*
+ * Function: malloc_chain_check()
+ *
+ * Purpose: to verify malloc chain is intact
+ *
+ * Arguments: todo - 0 - just check and return status
+ * 1 - call malloc_warn if error detected
+ *
+ * Returns: 0 - malloc chain intact & no overflows
+ * other - problems detected in malloc chain
+ *
+ * Narrative:
+ *
+ * Notes: If todo is non-zero the malloc_warn function, when called
+ * may not return (i.e. it may exit)
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: mlc_chn.c,v 1.1.1.1 2000-09-22 15:33:26 hr Exp $";
+#endif
+
+
+int
+malloc_chain_check(todo)
+ int todo;
+{
+ char * func = "malloc_chain_check";
+ int i;
+ extern char * malloc_data_start;
+ extern char * malloc_data_end;
+ extern struct mlist * malloc_end;
+ extern int malloc_errno;
+ extern struct mlist malloc_start;
+ struct mlist * oldptr;
+ struct mlist * ptr;
+ int rtn = 0;
+
+ oldptr = &malloc_start;
+ for(ptr = malloc_start.next; ; ptr = ptr->next)
+ {
+ /*
+ * Since the malloc chain is a forward only chain, any
+ * pointer that we get should always be positioned in
+ * memory following the previous pointer. If this is not
+ * so, we must have a corrupted chain.
+ */
+ if( ptr )
+ {
+ if(ptr < oldptr )
+ {
+ malloc_errno = M_CODE_CHAIN_BROKE;
+ if( todo )
+ {
+ malloc_fatal(func);
+ }
+ rtn++;
+ break;
+ }
+ oldptr = ptr;
+ }
+ else
+ {
+ if( oldptr != malloc_end )
+ {
+ /*
+ * This should never happen. If it does, then
+ * we got a real problem.
+ */
+ malloc_errno = M_CODE_NO_END;
+ if( todo )
+ {
+ malloc_fatal(func);
+ }
+ rtn++;
+ }
+ break;
+ }
+
+ /*
+ * verify that ptr is within the malloc region...
+ * since we started within the malloc chain this should never
+ * happen.
+ */
+
+ if( ((char *)ptr < malloc_data_start) ||
+ ((char *)ptr > malloc_data_end) )
+ {
+ malloc_errno = M_CODE_BAD_PTR;
+ if( todo )
+ {
+ malloc_fatal(func);
+ }
+ rtn++;
+ break;
+ }
+
+ /*
+ * verify magic flag is set
+ */
+
+ if( (ptr->flag&M_MAGIC) != M_MAGIC )
+ {
+ malloc_errno = M_CODE_BAD_MAGIC;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ continue;
+ }
+
+ /*
+ * verify segments are correctly linked together
+ */
+
+ if( (ptr->prev && (ptr->prev->next != ptr) ) ||
+ (ptr->next && (ptr->next->prev != ptr) ) ||
+ ((ptr->next == NULL) && (ptr->prev == NULL)) )
+ {
+ malloc_errno = M_CODE_BAD_CONNECT;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ continue;
+ }
+
+ /*
+ * If this segment is allocated
+ */
+
+ if( (ptr->flag & M_INUSE) != 0 )
+ {
+ /*
+ * verify no overflow of data area
+ */
+
+ for(i=ptr->r_size; i < ptr->s.size; i++)
+ {
+ if( ptr->data[i] != M_FILL )
+ {
+ malloc_errno = M_CODE_OVERRUN;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ break;
+ }
+ }
+ }
+ else /* it's not allocated so */
+ {
+ /*
+ * verify no reuse of freed data blocks
+ */
+
+ for(i=0; i < ptr->s.size; i++)
+ {
+ if( ptr->data[i] != M_FREE_FILL )
+ {
+ malloc_errno = M_CODE_REUSE;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ break;
+ }
+ }
+ }
+
+ } /* for(... */
+
+ return(rtn);
+
+} /* malloc_chain_check(... */
diff --git a/dmake/dbug/malloc/patchlev b/dmake/dbug/malloc/patchlev
new file mode 100644
index 000000000000..00750edc07d6
--- /dev/null
+++ b/dmake/dbug/malloc/patchlev
@@ -0,0 +1 @@
+3
diff --git a/dmake/dbug/malloc/realloc.c b/dmake/dbug/malloc/realloc.c
new file mode 100644
index 000000000000..2801cd86212d
--- /dev/null
+++ b/dmake/dbug/malloc/realloc.c
@@ -0,0 +1,180 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+
+/*
+ * Function: realloc()
+ *
+ * Purpose: to re-allocate a data area.
+ *
+ * Arguments: cptr - pointer to area to reallocate
+ * size - size to change area to
+ *
+ * Returns: pointer to new area (may be same area)
+ *
+ * Narrative: verify pointer is within malloc region
+ * obtain mlist pointer from cptr
+ * verify magic number is correct
+ * verify inuse flag is set
+ * verify connection to adjoining segments is correct
+ * save requested size
+ * round-up size to appropriate boundry
+ * IF size is bigger than what is in this segment
+ * try to join next segment to this segment
+ * IF size is less than what is is this segment
+ * determine leftover amount of space
+ * ELSE
+ * allocate new segment of size bites
+ * IF allocation failed
+ * return NULL
+ * copy previous data to new segment
+ * free previous segment
+ * return new pointer
+ * split of extra space in this segment (if any)
+ * clear bytes beyound what they had before
+ * return pointer to data
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: realloc.c,v 1.2 2006-07-25 10:09:48 rt Exp $";
+#endif
+
+char *
+realloc(cptr,size)
+ char * cptr;
+ unsigned int size;
+{
+ void free();
+ char * func = "realloc";
+ int i;
+ char * malloc();
+ extern int malloc_checking;
+ extern struct mlist * malloc_end;
+ extern int malloc_errno;
+ extern char * malloc_data_end;
+ extern char * malloc_data_start;
+ void malloc_join();
+ void malloc_memset();
+ void malloc_split();
+ char * memcpy();
+ char * new_cptr;
+ struct mlist * ptr;
+ int r_size;
+
+ /*
+ * IF malloc chain checking is on, go do it.
+ */
+ if( malloc_checking )
+ {
+ (void) malloc_chain_check(1);
+ }
+
+ /*
+ * verify that cptr is within the malloc region...
+ */
+ if( cptr < malloc_data_start || cptr > malloc_data_end )
+ {
+ malloc_errno = M_CODE_BAD_PTR;
+ malloc_warning(func);
+ return (NULL);
+ }
+
+ /*
+ * convert pointer to mlist struct pointer. To do this we must
+ * move the pointer backwards the correct number of bytes...
+ */
+
+ ptr = (struct mlist *) (cptr - M_SIZE);
+
+ if( (ptr->flag&M_MAGIC) != M_MAGIC )
+ {
+ malloc_errno = M_CODE_BAD_MAGIC;
+ malloc_warning(func);
+ return(NULL);
+ }
+
+ if( ! (ptr->flag & M_INUSE) )
+ {
+ malloc_errno = M_CODE_NOT_INUSE ;
+ malloc_warning(func);
+ return(NULL);
+ }
+
+ if( (ptr->prev && (ptr->prev->next != ptr) ) ||
+ (ptr->next && (ptr->next->prev != ptr) ) ||
+ ((ptr->next == NULL) && (ptr->prev == NULL)) )
+ {
+ malloc_errno = M_CODE_BAD_CONNECT;
+ malloc_warning(func);
+ return(NULL);
+ }
+
+ r_size = ++size;
+
+ M_ROUNDUP(size);
+
+ if( size > ptr->s.size )
+ {
+ malloc_join(ptr,ptr->next,1,1);
+ }
+
+ if( size > ptr->s.size )
+ {
+ /*
+ * else we can't combine it, so lets allocate a new chunk,
+ * copy the data and free the old chunk...
+ */
+ new_cptr = malloc(size);
+
+ if( new_cptr == (char *) 0)
+ {
+ return(new_cptr);
+ }
+
+ if( r_size < ptr->r_size )
+ {
+ i = r_size;
+ }
+ else
+ {
+ i = ptr->r_size;
+ }
+ (void)memcpy(new_cptr,ptr->data,i);
+ free(cptr);
+ return(new_cptr);
+
+ } /* else... */
+
+ /*
+ * save amount of real data in new segment (this will be used in the
+ * memset later) and then save requested size of this segment.
+ */
+
+ if( ptr->r_size < r_size )
+ {
+ i = ptr->r_size;
+ }
+ else
+ {
+ i = r_size;
+ }
+
+ ptr->r_size = r_size;
+
+ /*
+ * split off extra free space at end of this segment, if possible...
+ */
+
+ malloc_split(ptr);
+
+ malloc_memset( ptr->data+i, M_FILL, (int) (ptr->s.size - i));
+
+ return(ptr->data);
+
+} /* realloc(... */
+
+
diff --git a/dmake/dbug/malloc/string.c b/dmake/dbug/malloc/string.c
new file mode 100644
index 000000000000..7b92bf07ad1b
--- /dev/null
+++ b/dmake/dbug/malloc/string.c
@@ -0,0 +1,533 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "malloc.h"
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: string.c,v 1.2 2006-07-25 10:10:03 rt Exp $";
+#endif
+
+int malloc_checking = 0;
+
+char *
+strcat(str1,str2)
+ register char * str1;
+ register char * str2;
+{
+ char * rtn;
+ int len;
+
+ /*
+ * check pointers agains malloc region. The malloc* functions
+ * will properly handle the case where a pointer does not
+ * point into malloc space.
+ */
+ malloc_checking = 1;
+
+ len = strlen(str2);
+ malloc_check_str("strcat", str2);
+
+ len += strlen(str1) + 1;
+ malloc_checking = 0;
+
+ malloc_check_data("strcat", str1, len);
+
+ rtn = str1;
+
+ while( *str1 )
+ {
+ str1++;
+ }
+
+ while( (*str1 = *str2) != '\0' )
+ {
+ str1++;
+ str2++;
+ }
+
+ return(rtn);
+}
+
+char *
+strdup(str1)
+ register char * str1;
+{
+ char * malloc();
+ char * rtn;
+ register char * str2;
+
+ malloc_check_str("strdup", str1);
+
+ rtn = str2 = malloc((unsigned)strlen(str1)+1);
+
+ if( rtn != (char *) 0)
+ {
+ while( (*str2 = *str1) != '\0' )
+ {
+ str1++;
+ str2++;
+ }
+ }
+
+ return(rtn);
+}
+
+char *
+strncat(str1,str2,len)
+ register char * str1;
+ register char * str2;
+ register int len;
+{
+ int len1;
+ int len2;
+ char * rtn;
+
+ malloc_check_strn("strncat", str2, len);
+
+ malloc_checking = 1;
+
+ len2 = strlen(str2) + 1;
+ len1 = strlen(str1);
+
+ malloc_checking = 0;
+
+
+ if( (len+1) < len2 )
+ {
+ len1 += len + 1;
+ }
+ else
+ {
+ len1 += len2;
+ }
+ malloc_check_data("strncat", str1, len1);
+
+ rtn = str1;
+
+ while( *str1 )
+ {
+ str1++;
+ }
+
+ while( len-- && ((*str1++ = *str2++) != '\0') )
+ {
+ }
+
+ if( ! len )
+ {
+ *str1 = '\0';
+ }
+
+ return(rtn);
+}
+
+int
+strcmp(str1,str2)
+ register char * str1;
+ register char * str2;
+{
+ malloc_check_str("strcmp", str1);
+ malloc_check_str("strcmp", str2);
+
+ while( *str1 && (*str1 == *str2) )
+ {
+ str1++;
+ str2++;
+ }
+
+
+ /*
+ * in order to deal with the case of a negative last char of either
+ * string when the other string has a null
+ */
+ if( (*str2 == '\0') && (*str1 == '\0') )
+ {
+ return(0);
+ }
+ else if( *str2 == '\0' )
+ {
+ return(1);
+ }
+ else if( *str1 == '\0' )
+ {
+ return(-1);
+ }
+
+ return( *str1 - *str2 );
+}
+
+int
+strncmp(str1,str2,len)
+ register char * str1;
+ register char * str2;
+ register int len;
+{
+ malloc_check_strn("strncmp", str1, len);
+ malloc_check_strn("strncmp", str2, len);
+
+ while( --len >= 0 && *str1 && (*str1 == *str2) )
+ {
+ str1++;
+ str2++;
+ }
+
+ if( len < 0 )
+ {
+ return(0);
+ }
+ /*
+ * in order to deal with the case of a negative last char of either
+ * string when the other string has a null
+ */
+ if( (*str2 == '\0') && (*str1 == '\0') )
+ {
+ return(0);
+ }
+ else if( *str2 == '\0' )
+ {
+ return(1);
+ }
+ else if( *str1 == '\0' )
+ {
+ return(-1);
+ }
+
+ return( *str1 - *str2 );
+}
+
+char *
+strcpy(str1,str2)
+ register char * str1;
+ register char * str2;
+{
+ char * rtn;
+ int len;
+
+ malloc_checking = 1;
+ len = strlen(str2) + 1;
+ malloc_checking = 0;
+
+ malloc_check_data("strcpy", str1, len);
+ malloc_check_data("strcpy", str2, len);
+
+ rtn = str1;
+
+ while( (*str1++ = *str2++) != '\0')
+ {
+ }
+
+ return(rtn);
+}
+
+char *
+strncpy(str1,str2,len)
+ register char * str1;
+ register char * str2;
+ register int len;
+{
+ extern int malloc_checking;
+ char * rtn;
+
+ malloc_check_data("strncpy", str1, len);
+ malloc_check_strn("strncpy", str2, len);
+
+ rtn = str1;
+
+ while((len-- > 0) && (*str1++ = *str2++) != '\0')
+ {
+ }
+ while( (len-- > 0) )
+ {
+ *str1++ = '\0';
+ }
+
+ return(rtn);
+}
+
+int
+strlen(str1)
+ register char * str1;
+{
+ register char * s;
+
+ if(! malloc_checking )
+ {
+ malloc_check_str("strlen", str1);
+ }
+
+ for( s = str1; *s; s++)
+ {
+ }
+
+ return( s - str1 );
+}
+
+char *
+strchr(str1,c)
+ register char * str1;
+ register int c;
+{
+ malloc_check_str("strchr", str1);
+
+ while( *str1 && (*str1 != (char) c) )
+ {
+ str1++;
+ }
+
+ if(*str1 != (char) c)
+ {
+ str1 = (char *) 0;
+ }
+
+ return(str1);
+}
+
+char *
+strrchr(str1,c)
+ register char * str1;
+ register int c;
+{
+ register char * rtn = (char *) 0;
+
+ malloc_check_str("strrchr", str1);
+
+ while( *str1 )
+ {
+ if(*str1 == (char) c )
+ {
+ rtn = str1;
+ }
+ str1++;
+ }
+
+ if( *str1 == (char) c)
+ {
+ rtn = str1;
+ }
+
+ return(rtn);
+}
+
+char *
+index(str1,c)
+ char * str1;
+ char c;
+{
+ return( strchr(str1,c) );
+}
+
+char *
+rindex(str1,c)
+ char * str1;
+ char c;
+{
+ return( strrchr(str1,c) );
+}
+
+char *
+strpbrk(str1,str2)
+ register char * str1;
+ register char * str2;
+{
+ register char * tmp;
+
+ malloc_check_str("strpbrk", str1);
+ malloc_check_str("strpbrk", str2);
+
+ while(*str1)
+ {
+ for( tmp=str2; *tmp && *tmp != *str1; tmp++)
+ {
+ }
+ if( *tmp )
+ {
+ break;
+ }
+ str1++;
+ }
+
+ if( ! *str1 )
+ {
+ str1 = (char *) 0;
+ }
+
+ return(str1);
+}
+
+int
+strspn(str1,str2)
+ register char * str1;
+ register char * str2;
+{
+ register char * tmp;
+ char * orig = str1;
+
+ malloc_check_str("strspn", str1);
+ malloc_check_str("strspn", str2);
+
+ while(*str1)
+ {
+ for( tmp=str2; *tmp && *tmp != *str1; tmp++)
+ {
+ }
+ if(! *tmp )
+ {
+ break;
+ }
+ str1++;
+ }
+
+ return( (int) (str1 - orig) );
+}
+
+int
+strcspn(str1,str2)
+ register char * str1;
+ register char * str2;
+{
+ register char * tmp;
+ char * orig = str1;
+
+ malloc_check_str("strcspn", str1);
+ malloc_check_str("strcspn", str2);
+
+ while(*str1)
+ {
+ for( tmp=str2; *tmp && *tmp != *str1; tmp++)
+ {
+ }
+ if( *tmp )
+ {
+ break;
+ }
+ str1++;
+ }
+
+ return( (int) (str1 - orig) );
+}
+
+/*
+ * strtok() source taken from that posted to comp.lang.c by Chris Torek
+ * in Jan 1990.
+ */
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Get next token from string s (NULL on 2nd, 3rd, etc. calls),
+ * where tokens are nonempty strings separated by runs of
+ * chars from delim. Writes NULs into s to end tokens. delim need not
+ * remain constant from call to call.
+ *
+ * Modified by cpc: changed variable names to conform with naming
+ * conventions used in rest of code. Added malloc pointer
+ * check calls.
+ */
+char *
+strtok(str1, str2)
+ char * str1;
+ char * str2;
+{
+ static char * last;
+ char * strtoken();
+
+ if( str1 )
+ {
+ malloc_check_str("strtok", str1);
+ last = str1;
+ }
+ malloc_check_str("strtok", str2);
+
+ return (strtoken(&last, str2, 1));
+}
+
+
+/*
+ * Get next token from string *stringp, where tokens are (possibly empty)
+ * strings separated by characters from delim. Tokens are separated
+ * by exactly one delimiter iff the skip parameter is false; otherwise
+ * they are separated by runs of characters from delim, because we
+ * skip over any initial `delim' characters.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim will usually, but need not, remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strtoken returns NULL.
+ */
+char *
+strtoken(stringp, delim, skip)
+ register char **stringp;
+ register char *delim;
+ int skip;
+{
+ register char *s;
+ register char *spanp;
+ register int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+
+ if (skip) {
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim)).
+ */
+ cont:
+ c = *s;
+ for (spanp = delim; (sc = *spanp++) != 0;) {
+ if (c == sc) {
+ s++;
+ goto cont;
+ }
+ }
+ if (c == 0) { /* no token found */
+ *stringp = NULL;
+ return (NULL);
+ }
+ }
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
diff --git a/dmake/dbug/malloc/testmem.c b/dmake/dbug/malloc/testmem.c
new file mode 100644
index 000000000000..46fba912f8c0
--- /dev/null
+++ b/dmake/dbug/malloc/testmem.c
@@ -0,0 +1,646 @@
+/*
+ * This stuff is all stolen (with permission, since it was in the public
+ * domain) from Henry Spencer's string and memory library. Thanks Henry.
+ */
+
+/*
+ * Test program for string(3) routines.
+ *
+ * Note that at least one Bell Labs implementation of the string
+ * routines flunks a couple of these tests -- the ones which test
+ * behavior on "negative" characters.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+char * index();
+char * rindex();
+
+#define STREQ(a, b) (strcmp((a), (b)) == 0)
+
+char *it = "<UNSET>"; /* Routine name for message routines. */
+int waserror = 0; /* For exit status. */
+
+char uctest[] = "\004\203"; /* For testing signedness of chars. */
+int charsigned; /* Result. */
+
+/*
+ - check - complain if condition is not true
+ */
+void
+check(thing, number)
+int thing;
+int number; /* Test number for error message. */
+{
+ if (!thing) {
+ printf("%s flunked test %d\n", it, number);
+ waserror = 1;
+ }
+}
+
+/*
+ - equal - complain if first two args don't strcmp as equal
+ */
+void
+equal(a, b, number)
+char *a;
+char *b;
+int number; /* Test number for error message. */
+{
+ check(a != NULL && b != NULL && STREQ(a, b), number);
+}
+
+char one[50];
+char two[50];
+
+#ifdef UNIXERR
+#define ERR 1
+#endif
+#ifdef BERKERR
+#define ERR 1
+#endif
+#ifdef ERR
+int f;
+extern char *sys_errlist[];
+extern int sys_nerr;
+extern int errno;
+#endif
+
+/* ARGSUSED */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ /*
+ * First, establish whether chars are signed.
+ */
+ if (uctest[0] < uctest[1])
+ charsigned = 0;
+ else
+ charsigned = 1;
+
+ /*
+ * Then, do the rest of the work. Split into two functions because
+ * some compilers get unhappy about a single immense function.
+ */
+ first();
+ second();
+
+ exit((waserror) ? 1 : 0);
+}
+
+first()
+{
+ /*
+ * Test strcmp first because we use it to test other things.
+ */
+ it = "strcmp";
+ check(strcmp("", "") == 0, 1); /* Trivial case. */
+ check(strcmp("a", "a") == 0, 2); /* Identity. */
+ check(strcmp("abc", "abc") == 0, 3); /* Multicharacter. */
+ check(strcmp("abc", "abcd") < 0, 4); /* Length mismatches. */
+ check(strcmp("abcd", "abc") > 0, 5);
+ check(strcmp("abcd", "abce") < 0, 6); /* Honest miscompares. */
+ check(strcmp("abce", "abcd") > 0, 7);
+ check(strcmp("a\203", "a") > 0, 8); /* Tricky if char signed. */
+ if (charsigned) /* Sign-bit comparison. */
+ check(strcmp("a\203", "a\003") < 0, 9);
+ else
+ check(strcmp("a\203", "a\003") > 0, 9);
+ check(strcmp("a", "a\203") < 0, 10); /* Tricky if char signed. */
+
+ /*
+ * Test strcpy next because we need it to set up other tests.
+ */
+ it = "strcpy";
+ check(strcpy(one, "abcd") == one, 1); /* Returned value. */
+ equal(one, "abcd", 2); /* Basic test. */
+
+ (void) strcpy(one, "x");
+ equal(one, "x", 3); /* Writeover. */
+ equal(one+2, "cd", 4); /* Wrote too much? */
+
+ (void) strcpy(two, "hi there");
+ (void) strcpy(one, two);
+ equal(one, "hi there", 5); /* Basic test encore. */
+ equal(two, "hi there", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "");
+ equal(one, "", 7); /* Boundary condition. */
+
+ /*
+ * strcat
+ */
+ it = "strcat";
+ (void) strcpy(one, "ijk");
+ check(strcat(one, "lmn") == one, 1); /* Returned value. */
+ equal(one, "ijklmn", 2); /* Basic test. */
+
+ (void) strcpy(one, "x");
+ (void) strcat(one, "yz");
+ equal(one, "xyz", 3); /* Writeover. */
+ equal(one+4, "mn", 4); /* Wrote too much? */
+
+ (void) strcpy(one, "gh");
+ (void) strcpy(two, "ef");
+ (void) strcat(one, two);
+ equal(one, "ghef", 5); /* Basic test encore. */
+ equal(two, "ef", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "");
+ (void) strcat(one, "");
+ equal(one, "", 7); /* Boundary conditions. */
+ (void) strcpy(one, "ab");
+ (void) strcat(one, "");
+ equal(one, "ab", 8);
+ (void) strcpy(one, "");
+ (void) strcat(one, "cd");
+ equal(one, "cd", 9);
+
+ /*
+ * strncat - first test it as strcat, with big counts, then
+ * test the count mechanism.
+ */
+ it = "strncat";
+ (void) strcpy(one, "ijk");
+ check(strncat(one, "lmn", 99) == one, 1); /* Returned value. */
+ equal(one, "ijklmn", 2); /* Basic test. */
+
+ (void) strcpy(one, "x");
+ (void) strncat(one, "yz", 99);
+ equal(one, "xyz", 3); /* Writeover. */
+ equal(one+4, "mn", 4); /* Wrote too much? */
+
+ (void) strcpy(one, "gh");
+ (void) strcpy(two, "ef");
+ (void) strncat(one, two, 99);
+ equal(one, "ghef", 5); /* Basic test encore. */
+ equal(two, "ef", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "");
+ (void) strncat(one, "", 99);
+ equal(one, "", 7); /* Boundary conditions. */
+ (void) strcpy(one, "ab");
+ (void) strncat(one, "", 99);
+ equal(one, "ab", 8);
+ (void) strcpy(one, "");
+ (void) strncat(one, "cd", 99);
+ equal(one, "cd", 9);
+
+ (void) strcpy(one, "ab");
+ (void) strncat(one, "cdef", 2);
+ equal(one, "abcd", 10); /* Count-limited. */
+
+ (void) strncat(one, "gh", 0);
+ equal(one, "abcd", 11); /* Zero count. */
+
+ (void) strncat(one, "gh", 2);
+ equal(one, "abcdgh", 12); /* Count and length equal. */
+
+ /*
+ * strncmp - first test as strcmp with big counts, then test
+ * count code.
+ */
+ it = "strncmp";
+ check(strncmp("", "", 99) == 0, 1); /* Trivial case. */
+ check(strncmp("a", "a", 99) == 0, 2); /* Identity. */
+ check(strncmp("abc", "abc", 99) == 0, 3); /* Multicharacter. */
+ check(strncmp("abc", "abcd", 99) < 0, 4); /* Length unequal. */
+ check(strncmp("abcd", "abc", 99) > 0, 5);
+ check(strncmp("abcd", "abce", 99) < 0, 6); /* Honestly unequal. */
+ check(strncmp("abce", "abcd", 99) > 0, 7);
+ check(strncmp("a\203", "a", 2) > 0, 8); /* Tricky if '\203' < 0 */
+ if (charsigned) /* Sign-bit comparison. */
+ check(strncmp("a\203", "a\003", 2) < 0, 9);
+ else
+ check(strncmp("a\203", "a\003", 2) > 0, 9);
+ check(strncmp("abce", "abcd", 3) == 0, 10); /* Count limited. */
+ check(strncmp("abce", "abc", 3) == 0, 11); /* Count == length. */
+ check(strncmp("abcd", "abce", 4) < 0, 12); /* Nudging limit. */
+ check(strncmp("abc", "def", 0) == 0, 13); /* Zero count. */
+
+ /*
+ * strncpy - testing is a bit different because of odd semantics
+ */
+ it = "strncpy";
+ check(strncpy(one, "abc", 4) == one, 1); /* Returned value. */
+ equal(one, "abc", 2); /* Did the copy go right? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 2);
+ equal(one, "xycdefgh", 3); /* Copy cut by count. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 3); /* Copy cut just before NUL. */
+ equal(one, "xyzdefgh", 4);
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 4); /* Copy just includes NUL. */
+ equal(one, "xyz", 5);
+ equal(one+4, "efgh", 6); /* Wrote too much? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 5); /* Copy includes padding. */
+ equal(one, "xyz", 7);
+ equal(one+4, "", 8);
+ equal(one+5, "fgh", 9);
+
+ (void) strcpy(one, "abc");
+ (void) strncpy(one, "xyz", 0); /* Zero-length copy. */
+ equal(one, "abc", 10);
+
+ (void) strncpy(one, "", 2); /* Zero-length source. */
+ equal(one, "", 11);
+ equal(one+1, "", 12);
+ equal(one+2, "c", 13);
+
+ (void) strcpy(one, "hi there");
+ (void) strncpy(two, one, 9);
+ equal(two, "hi there", 14); /* Just paranoia. */
+ equal(one, "hi there", 15); /* Stomped on source? */
+
+ /*
+ * strlen
+ */
+ it = "strlen";
+ check(strlen("") == 0, 1); /* Empty. */
+ check(strlen("a") == 1, 2); /* Single char. */
+ check(strlen("abcd") == 4, 3); /* Multiple chars. */
+
+ /*
+ * strchr
+ */
+ it = "strchr";
+ check(strchr("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(strchr(one, 'c') == one+2, 2); /* Basic test. */
+ check(strchr(one, 'd') == one+3, 3); /* End of string. */
+ check(strchr(one, 'a') == one, 4); /* Beginning. */
+ check(strchr(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(strchr(one, 'b') == one+1, 6); /* Finding first. */
+ (void) strcpy(one, "");
+ check(strchr(one, 'b') == NULL, 7); /* Empty string. */
+ check(strchr(one, '\0') == one, 8); /* NUL in empty string. */
+
+ /*
+ * index - just like strchr
+ */
+ it = "index";
+ check(index("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(index(one, 'c') == one+2, 2); /* Basic test. */
+ check(index(one, 'd') == one+3, 3); /* End of string. */
+ check(index(one, 'a') == one, 4); /* Beginning. */
+ check(index(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(index(one, 'b') == one+1, 6); /* Finding first. */
+ (void) strcpy(one, "");
+ check(index(one, 'b') == NULL, 7); /* Empty string. */
+ check(index(one, '\0') == one, 8); /* NUL in empty string. */
+
+ /*
+ * strrchr
+ */
+ it = "strrchr";
+ check(strrchr("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(strrchr(one, 'c') == one+2, 2); /* Basic test. */
+ check(strrchr(one, 'd') == one+3, 3); /* End of string. */
+ check(strrchr(one, 'a') == one, 4); /* Beginning. */
+ check(strrchr(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(strrchr(one, 'b') == one+3, 6); /* Finding last. */
+ (void) strcpy(one, "");
+ check(strrchr(one, 'b') == NULL, 7); /* Empty string. */
+ check(strrchr(one, '\0') == one, 8); /* NUL in empty string. */
+
+ /*
+ * rindex - just like strrchr
+ */
+ it = "rindex";
+ check(rindex("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(rindex(one, 'c') == one+2, 2); /* Basic test. */
+ check(rindex(one, 'd') == one+3, 3); /* End of string. */
+ check(rindex(one, 'a') == one, 4); /* Beginning. */
+ check(rindex(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(rindex(one, 'b') == one+3, 6); /* Finding last. */
+ (void) strcpy(one, "");
+ check(rindex(one, 'b') == NULL, 7); /* Empty string. */
+ check(rindex(one, '\0') == one, 8); /* NUL in empty string. */
+}
+
+second()
+{
+ /*
+ * strpbrk - somewhat like strchr
+ */
+ it = "strpbrk";
+ check(strpbrk("abcd", "z") == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(strpbrk(one, "c") == one+2, 2); /* Basic test. */
+ check(strpbrk(one, "d") == one+3, 3); /* End of string. */
+ check(strpbrk(one, "a") == one, 4); /* Beginning. */
+ check(strpbrk(one, "") == NULL, 5); /* Empty search list. */
+ check(strpbrk(one, "cb") == one+1, 6); /* Multiple search. */
+ (void) strcpy(one, "abcabdea");
+ check(strpbrk(one, "b") == one+1, 7); /* Finding first. */
+ check(strpbrk(one, "cb") == one+1, 8); /* With multiple search. */
+ check(strpbrk(one, "db") == one+1, 9); /* Another variant. */
+ (void) strcpy(one, "");
+ check(strpbrk(one, "bc") == NULL, 10); /* Empty string. */
+ check(strpbrk(one, "") == NULL, 11); /* Both strings empty. */
+
+#if 0
+ /*
+ * strstr - somewhat like strchr
+ */
+ it = "strstr";
+ check(strstr("abcd", "z") == NULL, 1); /* Not found. */
+ check(strstr("abcd", "abx") == NULL, 2); /* Dead end. */
+ (void) strcpy(one, "abcd");
+ check(strstr(one, "c") == one+2, 3); /* Basic test. */
+ check(strstr(one, "bc") == one+1, 4); /* Multichar. */
+ check(strstr(one, "d") == one+3, 5); /* End of string. */
+ check(strstr(one, "cd") == one+2, 6); /* Tail of string. */
+ check(strstr(one, "abc") == one, 7); /* Beginning. */
+ check(strstr(one, "abcd") == one, 8); /* Exact match. */
+ check(strstr(one, "abcde") == NULL, 9); /* Too long. */
+ check(strstr(one, "de") == NULL, 10); /* Past end. */
+ check(strstr(one, "") == one+4, 11); /* Finding empty. */
+ (void) strcpy(one, "ababa");
+ check(strstr(one, "ba") == one+1, 12); /* Finding first. */
+ (void) strcpy(one, "");
+ check(strstr(one, "b") == NULL, 13); /* Empty string. */
+ check(strstr(one, "") == one, 14); /* Empty in empty string. */
+ (void) strcpy(one, "bcbca");
+ check(strstr(one, "bca") == one+2, 15); /* False start. */
+ (void) strcpy(one, "bbbcabbca");
+ check(strstr(one, "bbca") == one+1, 16); /* With overlap. */
+#endif
+
+ /*
+ * strspn
+ */
+ it = "strspn";
+ check(strspn("abcba", "abc") == 5, 1); /* Whole string. */
+ check(strspn("abcba", "ab") == 2, 2); /* Partial. */
+ check(strspn("abc", "qx") == 0, 3); /* None. */
+ check(strspn("", "ab") == 0, 4); /* Null string. */
+ check(strspn("abc", "") == 0, 5); /* Null search list. */
+
+ /*
+ * strcspn
+ */
+ it = "strcspn";
+ check(strcspn("abcba", "qx") == 5, 1); /* Whole string. */
+ check(strcspn("abcba", "cx") == 2, 2); /* Partial. */
+ check(strcspn("abc", "abc") == 0, 3); /* None. */
+ check(strcspn("", "ab") == 0, 4); /* Null string. */
+ check(strcspn("abc", "") == 3, 5); /* Null search list. */
+
+ /*
+ * strtok - the hard one
+ */
+ it = "strtok";
+ (void) strcpy(one, "first, second, third");
+ equal(strtok(one, ", "), "first", 1); /* Basic test. */
+ equal(one, "first", 2);
+ equal(strtok((char *)NULL, ", "), "second", 3);
+ equal(strtok((char *)NULL, ", "), "third", 4);
+ check(strtok((char *)NULL, ", ") == NULL, 5);
+ (void) strcpy(one, ", first, ");
+ equal(strtok(one, ", "), "first", 6); /* Extra delims, 1 tok. */
+ check(strtok((char *)NULL, ", ") == NULL, 7);
+ (void) strcpy(one, "1a, 1b; 2a, 2b");
+ equal(strtok(one, ", "), "1a", 8); /* Changing delim lists. */
+ equal(strtok((char *)NULL, "; "), "1b", 9);
+ equal(strtok((char *)NULL, ", "), "2a", 10);
+ (void) strcpy(two, "x-y");
+ equal(strtok(two, "-"), "x", 11); /* New string before done. */
+ equal(strtok((char *)NULL, "-"), "y", 12);
+ check(strtok((char *)NULL, "-") == NULL, 13);
+ (void) strcpy(one, "a,b, c,, ,d");
+ equal(strtok(one, ", "), "a", 14); /* Different separators. */
+ equal(strtok((char *)NULL, ", "), "b", 15);
+ equal(strtok((char *)NULL, " ,"), "c", 16); /* Permute list too. */
+ equal(strtok((char *)NULL, " ,"), "d", 17);
+ check(strtok((char *)NULL, ", ") == NULL, 18);
+ check(strtok((char *)NULL, ", ") == NULL, 19); /* Persistence. */
+ (void) strcpy(one, ", ");
+ check(strtok(one, ", ") == NULL, 20); /* No tokens. */
+ (void) strcpy(one, "");
+ check(strtok(one, ", ") == NULL, 21); /* Empty string. */
+ (void) strcpy(one, "abc");
+ equal(strtok(one, ", "), "abc", 22); /* No delimiters. */
+ check(strtok((char *)NULL, ", ") == NULL, 23);
+ (void) strcpy(one, "abc");
+ equal(strtok(one, ""), "abc", 24); /* Empty delimiter list. */
+ check(strtok((char *)NULL, "") == NULL, 25);
+ (void) strcpy(one, "abcdefgh");
+ (void) strcpy(one, "a,b,c");
+ equal(strtok(one, ","), "a", 26); /* Basics again... */
+ equal(strtok((char *)NULL, ","), "b", 27);
+ equal(strtok((char *)NULL, ","), "c", 28);
+ check(strtok((char *)NULL, ",") == NULL, 29);
+ equal(one+6, "gh", 30); /* Stomped past end? */
+ equal(one, "a", 31); /* Stomped old tokens? */
+ equal(one+2, "b", 32);
+ equal(one+4, "c", 33);
+
+ /*
+ * memcmp
+ */
+ it = "memcmp";
+ check(memcmp("a", "a", 1) == 0, 1); /* Identity. */
+ check(memcmp("abc", "abc", 3) == 0, 2); /* Multicharacter. */
+ check(memcmp("abcd", "abce", 4) < 0, 3); /* Honestly unequal. */
+ check(memcmp("abce", "abcd", 4) > 0, 4);
+ check(memcmp("alph", "beta", 4) < 0, 5);
+ if (charsigned) /* Sign-bit comparison. */
+ check(memcmp("a\203", "a\003", 2) < 0, 6);
+ else
+ check(memcmp("a\203", "a\003", 2) > 0, 6);
+ check(memcmp("abce", "abcd", 3) == 0, 7); /* Count limited. */
+ check(memcmp("abc", "def", 0) == 0, 8); /* Zero count. */
+
+ /*
+ * memchr
+ */
+ it = "memchr";
+ check(memchr("abcd", 'z', 4) == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(memchr(one, 'c', 4) == one+2, 2); /* Basic test. */
+ check(memchr(one, 'd', 4) == one+3, 3); /* End of string. */
+ check(memchr(one, 'a', 4) == one, 4); /* Beginning. */
+ check(memchr(one, '\0', 5) == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(memchr(one, 'b', 5) == one+1, 6); /* Finding first. */
+ check(memchr(one, 'b', 0) == NULL, 7); /* Zero count. */
+ check(memchr(one, 'a', 1) == one, 8); /* Singleton case. */
+ (void) strcpy(one, "a\203b");
+ check(memchr(one, 0203, 3) == one+1, 9); /* Unsignedness. */
+
+ /*
+ * memcpy
+ *
+ * Note that X3J11 says memcpy must work regardless of overlap.
+ * The SVID says it might fail.
+ */
+ it = "memcpy";
+ check(memcpy(one, "abc", 4) == one, 1); /* Returned value. */
+ equal(one, "abc", 2); /* Did the copy go right? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one+1, "xyz", 2);
+ equal(one, "axydefgh", 3); /* Basic test. */
+
+ (void) strcpy(one, "abc");
+ (void) memcpy(one, "xyz", 0);
+ equal(one, "abc", 4); /* Zero-length copy. */
+
+ (void) strcpy(one, "hi there");
+ (void) strcpy(two, "foo");
+ (void) memcpy(two, one, 9);
+ equal(two, "hi there", 5); /* Just paranoia. */
+ equal(one, "hi there", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one+1, one, 9);
+ equal(one, "aabcdefgh", 7); /* Overlap, right-to-left. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one+1, one+2, 7);
+ equal(one, "acdefgh", 8); /* Overlap, left-to-right. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one, one, 9);
+ equal(one, "abcdefgh", 9); /* 100% overlap. */
+
+ /*
+ * memccpy - first test like memcpy, then the search part
+ *
+ * The SVID, the only place where memccpy is mentioned, says
+ * overlap might fail, so we don't try it. Besides, it's hard
+ * to see the rationale for a non-left-to-right memccpy.
+ */
+ it = "memccpy";
+ check(memccpy(one, "abc", 'q', 4) == NULL, 1); /* Returned value. */
+ equal(one, "abc", 2); /* Did the copy go right? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memccpy(one+1, "xyz", 'q', 2);
+ equal(one, "axydefgh", 3); /* Basic test. */
+
+ (void) strcpy(one, "abc");
+ (void) memccpy(one, "xyz", 'q', 0);
+ equal(one, "abc", 4); /* Zero-length copy. */
+
+ (void) strcpy(one, "hi there");
+ (void) strcpy(two, "foo");
+ (void) memccpy(two, one, 'q', 9);
+ equal(two, "hi there", 5); /* Just paranoia. */
+ equal(one, "hi there", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strcpy(two, "horsefeathers");
+ check(memccpy(two, one, 'f', 9) == two+6, 7); /* Returned value. */
+ equal(one, "abcdefgh", 8); /* Source intact? */
+ equal(two, "abcdefeathers", 9); /* Copy correct? */
+
+ (void) strcpy(one, "abcd");
+ (void) strcpy(two, "bumblebee");
+ check(memccpy(two, one, 'a', 4) == two+1, 10); /* First char. */
+ equal(two, "aumblebee", 11);
+ check(memccpy(two, one, 'd', 4) == two+4, 12); /* Last char. */
+ equal(two, "abcdlebee", 13);
+ (void) strcpy(one, "xyz");
+ check(memccpy(two, one, 'x', 1) == two+1, 14); /* Singleton. */
+ equal(two, "xbcdlebee", 15);
+
+ /*
+ * memset
+ */
+ it = "memset";
+ (void) strcpy(one, "abcdefgh");
+ check(memset(one+1, 'x', 3) == one+1, 1); /* Return value. */
+ equal(one, "axxxefgh", 2); /* Basic test. */
+
+ (void) memset(one+2, 'y', 0);
+ equal(one, "axxxefgh", 3); /* Zero-length set. */
+
+ (void) memset(one+5, 0, 1);
+ equal(one, "axxxe", 4); /* Zero fill. */
+ equal(one+6, "gh", 5); /* And the leftover. */
+
+ (void) memset(one+2, 010045, 1);
+ equal(one, "ax\045xe", 6); /* Unsigned char convert. */
+
+ /*
+ * bcopy - much like memcpy
+ *
+ * Berklix manual is silent about overlap, so don't test it.
+ */
+ it = "bcopy";
+ (void) bcopy("abc", one, 4);
+ equal(one, "abc", 1); /* Simple copy. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) bcopy("xyz", one+1, 2);
+ equal(one, "axydefgh", 2); /* Basic test. */
+
+ (void) strcpy(one, "abc");
+ (void) bcopy("xyz", one, 0);
+ equal(one, "abc", 3); /* Zero-length copy. */
+
+ (void) strcpy(one, "hi there");
+ (void) strcpy(two, "foo");
+ (void) bcopy(one, two, 9);
+ equal(two, "hi there", 4); /* Just paranoia. */
+ equal(one, "hi there", 5); /* Stomped on source? */
+
+ /*
+ * bzero
+ */
+ it = "bzero";
+ (void) strcpy(one, "abcdef");
+ bzero(one+2, 2);
+ equal(one, "ab", 1); /* Basic test. */
+ equal(one+3, "", 2);
+ equal(one+4, "ef", 3);
+
+ (void) strcpy(one, "abcdef");
+ bzero(one+2, 0);
+ equal(one, "abcdef", 4); /* Zero-length copy. */
+
+ /*
+ * bcmp - somewhat like memcmp
+ */
+ it = "bcmp";
+ check(bcmp("a", "a", 1) == 0, 1); /* Identity. */
+ check(bcmp("abc", "abc", 3) == 0, 2); /* Multicharacter. */
+ check(bcmp("abcd", "abce", 4) != 0, 3); /* Honestly unequal. */
+ check(bcmp("abce", "abcd", 4) != 0, 4);
+ check(bcmp("alph", "beta", 4) != 0, 5);
+ check(bcmp("abce", "abcd", 3) == 0, 6); /* Count limited. */
+ check(bcmp("abc", "def", 0) == 0, 8); /* Zero count. */
+
+#ifdef ERR
+ /*
+ * strerror - VERY system-dependent
+ */
+ it = "strerror";
+ f = open("/", 1); /* Should always fail. */
+ check(f < 0 && errno > 0 && errno < sys_nerr, 1);
+ equal(strerror(errno), sys_errlist[errno], 2);
+#ifdef UNIXERR
+ equal(strerror(errno), "Is a directory", 3);
+#endif
+#ifdef BERKERR
+ equal(strerror(errno), "Permission denied", 3);
+#endif
+#endif
+}
diff --git a/dmake/dbug/malloc/testmlc.c b/dmake/dbug/malloc/testmlc.c
new file mode 100644
index 000000000000..16e11736cc18
--- /dev/null
+++ b/dmake/dbug/malloc/testmlc.c
@@ -0,0 +1,176 @@
+/* NOT copyright by SoftQuad Inc. -- msb, 1988 */
+#ifndef lint
+static char *SQ_SccsId = "@(#)mtest3.c 1.2 88/08/25";
+#endif
+#include <stdio.h>
+/*
+** looptest.c -- intensive allocator tester
+**
+** Usage: looptest
+**
+** History:
+** 4-Feb-1987 rtech!daveb
+*/
+
+# ifdef SYS5
+# define random rand
+# else
+# include <sys/vadvise.h>
+# endif
+
+# include <stdio.h>
+# include <signal.h>
+# include <setjmp.h>
+
+# define MAXITER 1000000 /* main loop iterations */
+# define MAXOBJS 1000 /* objects in pool */
+# define BIGOBJ 90000 /* max size of a big object */
+# define TINYOBJ 80 /* max size of a small object */
+# define BIGMOD 100 /* 1 in BIGMOD is a BIGOBJ */
+# define STATMOD 10000 /* interation interval for status */
+
+main( argc, argv )
+int argc;
+char **argv;
+{
+ register int **objs; /* array of objects */
+ register int *sizes; /* array of object sizes */
+ register int n; /* iteration counter */
+ register int i; /* object index */
+ register int size; /* object size */
+ register int r; /* random number */
+
+ int objmax; /* max size this iteration */
+ int cnt; /* number of allocated objects */
+ int nm = 0; /* number of mallocs */
+ int nre = 0; /* number of reallocs */
+ int nal; /* number of allocated objects */
+ int nfre; /* number of free list objects */
+ long alm; /* memory in allocated objects */
+ long frem; /* memory in free list */
+ long startsize; /* size at loop start */
+ long endsize; /* size at loop exit */
+ long maxiter = 0; /* real max # iterations */
+
+ extern char end; /* memory before heap */
+ char *calloc();
+ char *malloc();
+ char *sbrk();
+ long atol();
+
+# ifndef SYS5
+ /* your milage may vary... */
+ vadvise( VA_ANOM );
+# endif
+
+ if (argc > 1)
+ maxiter = atol (argv[1]);
+ if (maxiter <= 0)
+ maxiter = MAXITER;
+
+ printf("MAXITER %d MAXOBJS %d ", maxiter, MAXOBJS );
+ printf("BIGOBJ %d, TINYOBJ %d, nbig/ntiny 1/%d\n",
+ BIGOBJ, TINYOBJ, BIGMOD );
+ fflush( stdout );
+
+ if( NULL == (objs = (int **)calloc( MAXOBJS, sizeof( *objs ) ) ) )
+ {
+ fprintf(stderr, "Can't allocate memory for objs array\n");
+ exit(1);
+ }
+
+ if( NULL == ( sizes = (int *)calloc( MAXOBJS, sizeof( *sizes ) ) ) )
+ {
+ fprintf(stderr, "Can't allocate memory for sizes array\n");
+ exit(1);
+ }
+
+ /* as per recent discussion on net.lang.c, calloc does not
+ ** necessarily fill in NULL pointers...
+ */
+ for( i = 0; i < MAXOBJS; i++ )
+ objs[ i ] = NULL;
+
+ startsize = sbrk(0) - &end;
+ printf( "Memory use at start: %d bytes\n", startsize );
+ fflush(stdout);
+
+ printf("Starting the test...\n");
+ fflush(stdout);
+ for( n = 0; n < maxiter ; n++ )
+ {
+ if( !(n % STATMOD) )
+ {
+ printf("%d iterations\n", n);
+ fflush(stdout);
+ }
+
+ /* determine object of interst and it's size */
+
+ r = random();
+ objmax = ( r % BIGMOD ) ? TINYOBJ : BIGOBJ;
+ size = r % objmax;
+ i = r % (MAXOBJS - 1);
+
+ /* either replace the object of get a new one */
+
+ if( objs[ i ] == NULL )
+ {
+ objs[ i ] = (int *)malloc( size );
+ nm++;
+ }
+ else
+ {
+ /* don't keep bigger objects around */
+ if( size > sizes[ i ] )
+ {
+ objs[ i ] = (int *)realloc( objs[ i ], size );
+ nre++;
+ }
+ else
+ {
+ free( objs[ i ] );
+ objs[ i ] = (int *)malloc( size );
+ nm++;
+ }
+ }
+
+ sizes[ i ] = size;
+ if( objs[ i ] == NULL )
+ {
+ printf("\nCouldn't allocate %d byte object!\n",
+ size );
+ break;
+ }
+ } /* for() */
+
+ printf( "\n" );
+ cnt = 0;
+ for( i = 0; i < MAXOBJS; i++ )
+ if( objs[ i ] )
+ cnt++;
+
+ printf( "Did %d iterations, %d objects, %d mallocs, %d reallocs\n",
+ n, cnt, nm, nre );
+ printf( "Memory use at end: %d bytes\n", sbrk(0) - &end );
+ fflush( stdout );
+
+ /* free all the objects */
+ for( i = 0; i < MAXOBJS; i++ )
+ if( objs[ i ] != NULL )
+ free( objs[ i ] );
+
+ endsize = sbrk(0) - &end;
+ printf( "Memory use after free: %d bytes\n", endsize );
+ fflush( stdout );
+
+ if( startsize != endsize )
+ printf("startsize %d != endsize %d\n", startsize, endsize );
+
+ free( objs );
+ free( sizes );
+
+ malloc_dump(2);
+ exit( 0 );
+}
+
diff --git a/dmake/dbug/malloc/tostring.c b/dmake/dbug/malloc/tostring.c
new file mode 100644
index 000000000000..e3bc9990271d
--- /dev/null
+++ b/dmake/dbug/malloc/tostring.c
@@ -0,0 +1,132 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include "tostring.h"
+
+/*
+ * Function: tostring()
+ *
+ * Purpose: to convert an integer to an ascii display string
+ *
+ * Arguments: buf - place to put the
+ * val - integer to convert
+ * len - length of output field (0 if just enough to hold data)
+ * base - base for number conversion (only works for base <= 16)
+ * fill - fill char when len > # digits
+ *
+ * Returns: length of string
+ *
+ * Narrative: IF fill character is non-blank
+ * Determine base
+ * If base is HEX
+ * add "0x" to begining of string
+ * IF base is OCTAL
+ * add "0" to begining of string
+ *
+ * While value is greater than zero
+ * use val % base as index into xlation str to get cur char
+ * divide val by base
+ *
+ * Determine fill-in length
+ *
+ * Fill in fill chars
+ *
+ * Copy in number
+ *
+ *
+ * Mod History:
+ * 90/01/24 cpcahil Initial revision.
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: tostring.c,v 1.2 2006-07-25 10:10:17 rt Exp $";
+#endif
+
+#define T_LEN 10
+
+int
+tostring(buf,val,len,base,fill)
+ int base;
+ char * buf;
+ char fill;
+ int len;
+ int val;
+
+{
+ char * bufstart = buf;
+ int i = T_LEN;
+ char * xbuf = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ char tbuf[T_LEN];
+
+ /*
+ * if we are filling with non-blanks, make sure the
+ * proper start string is added
+ */
+ if( fill != ' ' )
+ {
+ switch(base)
+ {
+ case B_HEX:
+ *(buf++) = '0';
+ *(buf++) = 'x';
+ if( len )
+ {
+ len -= 2;
+ }
+ break;
+ case B_OCTAL:
+ *(buf++) = fill;
+ if( len )
+ {
+ len--;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ while( val > 0 )
+ {
+ tbuf[--i] = xbuf[val % base];
+ val = val / base;
+ }
+
+ if( len )
+ {
+ len -= (T_LEN - i);
+
+ if( len > 0 )
+ {
+ while(len-- > 0)
+ {
+ *(buf++) = fill;
+ }
+ }
+ else
+ {
+ /*
+ * string is too long so we must truncate
+ * off some characters. We do this the easiest
+ * way by just incrementing i. This means the
+ * most significant digits are lost.
+ */
+ while( len++ < 0 )
+ {
+ i++;
+ }
+ }
+ }
+
+ while( i < T_LEN )
+ {
+ *(buf++) = tbuf[i++];
+ }
+
+ return( (int) (buf - bufstart) );
+
+} /* tostring(... */
+
diff --git a/dmake/dbug/malloc/tostring.h b/dmake/dbug/malloc/tostring.h
new file mode 100644
index 000000000000..ccde36db4173
--- /dev/null
+++ b/dmake/dbug/malloc/tostring.h
@@ -0,0 +1,13 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+/*
+ * $Id: tostring.h,v 1.2 2006-07-25 10:10:32 rt Exp $
+ */
+#define B_BIN 2
+#define B_DEC 10
+#define B_HEX 16
+#define B_OCTAL 8
+
diff --git a/dmake/dbug/readme b/dmake/dbug/readme
new file mode 100644
index 000000000000..15efc00a7edc
--- /dev/null
+++ b/dmake/dbug/readme
@@ -0,0 +1,13 @@
+This directory contains two public domain debugging packages.
+
+ 1. Fred Fishes DEBUG macros.
+ 2. Connor P. Cahills malloc library.
+
+Descriptions of both can be found in their respective sub-directories. dbug
+for the DEBUG macros and malloc for the malloc library. I have left the
+malloc distribution intact as it comes from the net except for the changes
+noted in the _changes file.
+
+I thank the authors for making them available for others to use.
+
+-dennis