#!/bin/sh
# This is a shell archive (produced by shar 3.50)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 05/20/1994 16:39 UTC by gjc@world
# Source directory /home/ie/gjc/tmp
#
# existing files will NOT be overwritten unless -c is specified
# This format requires very little intelligence at unshar time.
# "if test", "echo", "true", and "sed" may be needed.
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#  10708 -rw------- READ.ME
#   3035 -rw------- crashme.1
#  21701 -rw------- crashme.c
#     84 -rw------- crashme.opt
#   1314 -rw------- descrip.mms
#     28 -rw------- make.bat
#    172 -rw------- makefile
#   1009 -rw------- makefile.wnt
#  13951 -rw------- pddet.c
#
# ============= READ.ME ==============
if test -f 'READ.ME' -a X"$1" != X"-c"; then
	echo 'x - skipping READ.ME (File already exists)'
else
echo 'x - extracting READ.ME (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'READ.ME' &&
Xread.me updated 20-may-1994 for crashme 2.4
X
XSee the source crashme.c for reports of system crashes.
X
X
XAcknowledgements.
X
XMany people have provided suggestions and comments and feedback. Some
Xin private email and some as published on the comp.arch newsgroups.
XBut as the author of this gross hack I take full responsibility for
Xany errors in the information presented.
X
X-----------------------------------------------------
X
XA bit of background on crashme. It is a tool for testing the robustness
Xof an operating environment using a technique of "Random Input" response
Xanalysis. This I first saw formally proposed in the book Cybernetics
Xby Norbert Wiener, but which any parent who has observed his children
Xplaying and learning would be well disposed to describe in detail.
X
X* The operating environment under consideration is the user-mode process.
X
X* The Random Input is provided by the execution of a sequence of pseudo-random
X  data as an instruction stream.
X
X* The response analysis is to catch and record machine and software
X  generated exceptions/errors/signals and to retry using new random data
X  in both the current user-mode process and in newly created subprocesses.
X
X-----------------------------------------------------
X
XNotes for release 2.2 of Crashme. 9-MAY-1994 GJC@MITECH.COM
X
XAdded the X.Y syntax for the NBYTES argument. This may run faster,
Xdoing more tests per second. A reasonable value for Y would be
Xthe number of bytes in a machine instruction.
X
XMany people have suggested that the output of previous versions was
Xfar too verbose, and that that was not only annoying but also
Xeffectively slowing down the program. Therefore there is a new argument
Xavailable after the subprocess control argument, which is a verboseness
Xlevel from 0 to 5. Using a level of 2 will print out only summary
Xinformation about the runs. e.g.
X
X$ crashme +2000 666 50 00:30:00 2
XCrashme: (c) Copyright 1990, 1991 George J. Carrette
XVersion: 1.7 25-SEP-1991
XSubprocess run for 1800 seconds (0 00:30:00)
XTest complete, total real time: 1801 seconds (0 00:30:01)
Xexit status ... number of cases
X       1100 ...     2
X    3522652 ...     4
X       1036 ...     1
X       1084 ...     7
X       1108 ...    19
X          1 ...   432
X         12 ...   137
X
XThe table of exit status codes and frequencies is a new interesting
Xaspect of the test. This test was run on a VMS system, so that we have
Xa normal process exit 432 times, access violation 137 times,
Xand reserved operand fault 19 times, etc. As the number of tries goes
Xup (50 in this case) we would expect that the number of normal process
Xexits to go down.
X
X
XIf you define an environment variable (or vms logical name)
Xcalled CRASHLOG then each subprocess will append to a file the
Xarguments it was given. In that way you can recover what instance
Xpossibly caused a crash, but remember that without frequent disk fsync
Xoperations most Unix systems will leave a CRASHLOG that is out of
Xdate by a few minutes or more.
X
XHere is some output supplied by nik@infonode.ingr.com on one of his machines.
X
XProcessor : Intergraph Clipper C300 RISC processor
X            16Mb memory + 4k I cache and 4K D cache
X
XOperating System: CLIX Version c.5.3.2
X                  derived from AT&T SVR 3.1 with BSD enhancements.
X
XCrashme: (c) Copyright 1990, 1991 George J. Carrette
XVersion: 1.7 25-SEP-1991
XSubprocess run for 9000 seconds (0 02:30:00)
XTest complete, total real time: 9004 seconds (0 02:30:04)
Xexit status ... number of cases
X        136 ...     1
X      24576 ...     1
X         14 ...     1
X        138 ...    11
X        135 ...    27
X        140 ...    26
X        132 ...   430
X        139 ...    18
X      12800 ...   567
X
XThe status values here could be decoded by reading the documentation
Xfor the "wait" system procedure, and looking up the correct part of
Xthe value in the sys_errlist[] array. That is left as an exersize for the 
Xreader.
X
X------------------------------------------------------------------------
X
XTo compile, some systems may need #include <sys/types.h>.
X
XAlso, note the conditionalized code in bad_malloc. If your system
Xonly gets the signal "segmentation violation" then you may need
Xto consider conditionalizations along this line. 
X
XHowever, on a machine with a segmented address space, that has
X"instructions" in one segment and "data" in another, it is highly
Xunlikely that the code for setting up and invoking the "void (*badboy)()" 
Xwill have any interesting effect. Nothing other than an easily
Xhandled SIGSEGV will result in the inner testing loop.
X
XSome PDP-11 systems would be examples of this situation (different I and D
Xspace).
X
X---MACHINE O/S SPECIFIC NOTES---
X
XMACHINE:: DEC C (OPENVMS ALPHA AXP):
X
X  $ CC/PREFIX=ALL/NOOPTIMIZE CRASHME
X  $ LINK CRASHME
X
XNew for version 2.2 code has been added to hackishly manipulate
Xthe Procedure Descriptor data format. It seems be executing random
Xinstructions like we would want.
X
X#if defined(__ALPHA) && defined(VMS) && !defined(NOCASTAWAY)
X
XWithout this hack crashme on this platform has very little chance
Xof causing anything other than a SIGBUS bus error.
X
XPerhaps a smart "learning" mode of random-data creation could achieve
Xthe same ends, maximizing some measurement of punishment.
X
XTest I've tried:
X
X $crashme +1000.48 0 100 03:00:00 2
X
XMACHINE:: Windows NT:
X 
X The only files needed are crashme.c,makefile.wnt, and make.bat
X cd into the directory containing the files and you can make two versions.
X crashme and crashmep (posix).
X
X >make  
X
XIn WIN32 subsystem the subprocess-all-at-once mode has not been implemented,
Xbut the sequential (-nsub) and timed modes have been implemented.
X
XIn posix subsystem you must use the full name of the file in the command
Xif you want to generated subprocesses.
X  >crashmep.exe .....
X
X
XOn an 486DX2-66 machine the following caused a totally
Xwedged up machine in the Windows NT final release. (Build 511).
XThis was built in WIN32 mode with debugging on.
X
X >crashme +1000 666 50 12:00:00 3
X
XIn the posix subsystem the more verbose modes were not ever observed
Xto go through more than 2 setjmp/longjmp cycles on a given random
Xnumber seed.  In the WIN32 subsystem there was a greater variety of
Xfault conditions.
X
XThe above crash took place after about 6 hours of running. Final
Xsubprocess arguments were +1000 24131 50, and we verified twice that
Xinvoking the following crashed the OS within seconds.
X
X >crashme +1000 24131 50
X
X
XI have always been concerned that the more complex the unprotected data
Xin the user address space the more likely it is for a program being
Xdeveloped to generate inscrutable errors that an
X"application developer" level of person will be unable to understand.
XAnd worse, will end up spinning wheels for
Xlarge amounts of time, thereby delaying projects and risking deadline
Xfailures, and even worse, forcing management to bring in super-experienced
X(and limited availability) people into a project in order to get it going
Xagain.
X
XThe WINDOWS NT client-server model is one way around this problem.
XHaving a subsystem in a different address space is one way to protect
Xcomplex data manipulated through an API. However, as page 127 of 
X"Inside Windows NT" there are some optimizations that make an unspoken
Xtrade-off between the robustness afforded by a protected seperate address space
Xand efficiency of implementation on an API.
X
XRobustness and 'scrutability of failure situations' vs efficiency.
X
XMACHINE:: OS/2
X
XIt has been reported that this runs when compiled gcc crashme.c -o crashme.exe
XIn order to disable the dialog boxes reporting abnormal process termination,
Xadd this to CONFIG.SYS:  AUTOFAIL=YES. Or the following code to main:
X
X  DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
X
XAnother person says:
X
X >Emx is the only c compiler under OS/2 that supports fork.
X
X
X------------------------------------------------------------------------
X
XSurvey of Procedure Descriptor Usage. The emphasis here is on
Xcurrently shipping products. The program pddet.c included
Xwith the distribution can be used to determine some of this
Xinformation.
X
XArchitecture    |D| Desc | Env | Reg | Apos | Atyp | Rpos | Rtyp | 
X------------------------------------------------------------------
XVAX             |2| No   | No  | Yes | No   | No   | No   | No   |
XALPHA, OPENVMS  |3| Yes  | Yes | Yes | Yes  | Opt  | Yes  | Opt  |
XALPHA, WNT      | | No   |     |     |      |      |      |      |
XALPHA, OSF/1    | | No   |     |     |      |      |      |      |
XRS/6000, AIX    |2| Yes  | Yes | No  | No   | No   | No   | No   |
XPowerPC,        |2| Yes  | Yes | No  | No   | No   | No   | No   |
XMIPS, Unix      | |      |     |     |      |      |      |      |
XMIPS, WNT       | |      |     |     |      |      |      |      |
XIntel, WNT      | |      |     |     |      |      |      |      |
XSparc, SUNOS    | | No   |     |     |      |      |      |      |
XPA-RISC, HPUX   |2| Yes  |     |     |      |      |      |      |
X------------------------------------------------------------------
X
XLegend:
X
XD    ... level of detailed information I have available
X         1 = Verbal description or suspect from pddet.c
X         2 = exact structure details including code for CRASHME.C
X             or obvious what it is from pddet.c
X         3 = crashme uses manufacturers include files for descriptors.
XDesc ... Uses descriptors
XEnv  ... has pointer to non-static environment
XReg  ... describes registers used
XApos ... describes argument positions (stack, registers) or number.
XAtyp ... describes argument types
XRpos ... describes return value position.
XRtyp ... describes return value types
X
XLayout of Descriptors. Sizes in bytes.
X
X
XALPHA OPENVMS:
X
X[FLAGS&KIND]       2
X[REG-SAVE]         2
X[REG-FOR-RETPC]    1
X[REG-FOR-RETVAL]   1
X[SIGNATURE-OFFSET] 2
X[START-PC]         8
X[Other stuff ...]  from 8 to 32 bytes worth.
X
XAIX 
X
Xactually points to a 3 word struct with:
X - the actual function address
X - Table Of Contents (r2) register value
X - Environment (r11) pointer (for nested functions)
X
XPOWERPC
X
X[PROGRAM-COUNTER]
X[TABLE-OF-CONTENTS]
X[EXCEPTION-INFO]
X
X[Editorial comment taken from comp.arch:] Not to sound picky about
Xthis, but this is not really part of the POWER/PowerPC architecture.
XThere is no special support for this in the hardware, it is just the
Xscheme the software designers came up with in order to support shared
Xlibraries. Other schemes would be possible. [GJC comment] Pretty
Xmuch true for every architecture.
X
XPA-RISC HPUX.
X
XThe pddet.c program was used, and suggested descriptors of 8
Xbytes long. The -examine 8 argument showed what appeared to
Xbe a 4-byte starting PC followed by a table of contents.
XNote: If somebody knows what /usr/include/sys/*.h file to use
Xfor this, please let me know.
X
SHAR_EOF
true || echo 'restore of READ.ME failed'
fi
# ============= crashme.1 ==============
if test -f 'crashme.1' -a X"$1" != X"-c"; then
	echo 'x - skipping crashme.1 (File already exists)'
else
echo 'x - extracting crashme.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'crashme.1' &&
X.TH CRASHME 1C LOCAL 
X.SH NAME
Xcrashme \- test operating environment software robustness
X.SH SYNOPSIS
X.B crashme
X[NBYTES] [SRAND] [NTRYS] [NSUB] [VERBOSE]
X.SH DESCRIPTION
X.I crashme
Xis a very simple program that tests the operating environment's
Xrobustness by invoking random data as if it were a procedure.
XThe standard signals are caught and handled with a setjmp back
Xto a loop which will try again to produce a fault by executing
Xrandom data. Some people call this stress testing.
X
X.RE
X.SS COMMAND LINE OPTIONS
X.TP 8
X.BI [NBYTES]
XThe
X.I [NBYTES]
Xshould be an integer, specifying the size of the random data string
Xin bytes. If given negative then the bytes are printed instead of
Xbeing executed. If given with an explicit plus sign then the
Xstorage for the bytes is freshly malloc'ed each time. This can have an
Xeffect on machines with seperate I and D cache mechanisms. The argument
Xcan also have a dot in it, X.Y, in which case Y is a increment for
Xa pointer into the random data. The buffer is recalculated only when
Xthe pointer gets near the end of the data.
X
X.TP
X.BI [SRAND]
XThe 
X.I [SRAND]
Xis an input seed to the random number generator, passed to srand.
X.TP
X.BI [NTRIES]
XThe
X.I [NTRIES]
Xis how many times to loop before exiting normally from the program.
X.TP
X.BI [NSUB]
XThe
X.I [NSUB] 
Xis optional, the number of vfork subprocesses running all at once.
XIf negative run one after another. If given as a 
Xtime hrs:mns:scs (hours, minutes, seconds) then
Xone subprocess will be run to completion, followed by another, until
Xthe time limit has been reached.  If this argument is given as the empty 
Xstring or . then it is ignored.
X
XWhen in sequential-subprocess mode there is a 30 second time limit on
Xeach subprocess. This is to allow the instruction-set-space random
Xwalk to continue when a process bashes itself into an infinite loop.
XFor example, the ntrys can be bashed to a very large number with
Xnbytes bashed to zero. (10 second limit on Windows NT).
X
XThe SRAND argument is incremented by one for each subprocess.
X
X.TP
X.BI [VERBOSE]
XThe
X.I [VERBOSE] 
Xarg is optional. 0 is the least verbose, 5 the most.
X
X.SH EXAMPLE
XThis is a suggested test, to run it for a least an hour.
X
Xcrashme +2000 666 100 1:00:00
X
X.SH FILES
Xcrashme.c
X.PD
X.SH DIAGNOSTICS
XWhen a signal is caught the number and nature of the signal is indicated.
XSetting the environment variable CRASHLOG will cause each subprocess to
Xrecord the arguments it was given.
X.SH BUGS
XNot all signals are caught, and the state of the user program/process
Xenviroment can be sufficiently damaged such that the program terminates
Xbefore going through all [NTRIES] operations.
X
XIf the architecture uses some kind of procedure descriptor but no
Xspecial code has been not been added to castaway() in crashme.c
Xthen the stress test will not be as potent as it would otherwise be.
X
XBeware: This program can crash your computer if the
Xoperating system or hardware of same is buggy. User data may be lost.
X.SH AUTHOR
XGeorge J Carrette. GJC\@MITECH.COM
X.SH VERSION
X2.4 20-MAY-1994
SHAR_EOF
true || echo 'restore of crashme.1 failed'
fi
# ============= crashme.c ==============
if test -f 'crashme.c' -a X"$1" != X"-c"; then
	echo 'x - skipping crashme.c (File already exists)'
else
echo 'x - extracting crashme.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'crashme.c' &&
X/* crashme: Create a string of random bytes and then jump to it.
X            crashme [+]<nbytes>[.inc] <srand> <ntrys> [nsub] [verboseness] */
X
Xchar *crashme_version = "2.4 20-MAY-1994";
X
X/*
X *             COPYRIGHT (c) 1990-1994 BY        *
X *  GEORGE J. CARRETTE, CONCORD, MASSACHUSETTS.  *
X *             ALL RIGHTS RESERVED               *
X
XPermission to use, copy, modify, distribute and sell this software
Xand its documentation for any purpose and without fee is hereby
Xgranted, provided that the above copyright notice appear in all copies
Xand that both that copyright notice and this permission notice appear
Xin supporting documentation, and that the name of the author
Xnot be used in advertising or publicity pertaining to distribution
Xof the software without specific, written prior permission.
X
XTHE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
XHE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
XSOFTWARE.
X
XA signal handler is set up so that in most cases the machine exception
Xgenerated by the illegal instructions, bad operands, etc in the procedure
Xmade up of random data are caught; and another round of randomness may
Xbe tried. Eventually a random instruction may corrupt the program or
Xthe machine state in such a way that the program must halt. This is
Xa test of the robustness of the hardware/software for instruction
Xfault handling.
X
XNote: Running this program just a few times, using total CPU time of
Xless than a few seconds SHOULD NOT GIVE YOU ANY CONFIDENCE in system
Xrobustness. Having it run for hours, with tens of thousands of cases
Xwould be a different thing. It would also make sense to run this
Xstress test at the same time you run other tests, like a multi-user
Xbenchmark.
X
XComments may be addressed to the author at GJC@MITECH.COM
X
XSee the documentation in crashme.1 and READ.ME, or read this code for 
Xa description of command line arguments to this program. 
X
XVersion Date         Description
X----------------------------------------------------------------------
X 1.0    early 1990   initial hack.
X 1.1    19-SEP-1990  added more signals and an alarm to abort looping.
X 1.2    25-JUN-1991  added [nsub] to vfork multiple subprocesses of self.
X 1.3    14-AUG-1991  +nbytes malloc option, and -nsub option.
X 1.4    29-AUG-1991  fix +nbytes (subproc). Add time-driven nprocs. SIGINT.
X 1.5     3-SEP-1991  added alarm subprocess monitor to vfork_main.
X 1.6     5-SEP-1991  some systems don't have vfork, so use fork by default.
X 1.7    25-SEP-1991  verboseness level, exit summary report.
X 1.8      -SEP-1991  address page protection issues on badboy.
X 1.9     6-AUG-1993  DECC(VMS)/WIN32/NT/Posix, #ifdef some SIGxxx.
X 2.0     7-SEP-1993  More extensive WIN32 conditionalization. record_note.
X 2.1     6-MAY-1994  Added "dot" syntax to NBYTES. Modularized castaway.
X 2.2     9-MAY-1994  __ALPHA && VMS version is now more interesting.
X 2.3    11-MAY-1994  Added _IBMRT2 and _POWER code.
X 2.4    20-MAY-1994  Added __hpux. Linux from jik@cam.ov.com.
X
XSuggested test: At least let the thing run the length of your lunch break,
Xin this case 1 hour, 10 minutes, and 30 seconds.
X
X  crashme +2000 666 100 1:10:30 2
X
XAlso, it may spend more time trapping and less time computing random bytes
Xby using these arguments:
X
X  crashme +2000.80 666 100 1:10:30 2
X
X                        CRASH REPORTS
X
XDate,               Machine              Crashme        Reported 
XCrashme Ver   Make    Model OS Version   Arguments      by:        
X------------------------------------------------------------------------------
X10-JUL-90 1.0 SUN     4/110 4.1          1000 20 200    GJC@paradigm.com
X10-JUL-90 1.0 SUN     4/280 4.0.3        1000 20 200    GJC@paradigm.com
X31-JUL-90 1.0 DIGITAL DECstation 3100    100 10 10000   GAVRON@ARIZONA.EDU
X31-JUL-90 1.0 IBM     RT                 100 10 10000   GAVRON@ARIZONA.EDU
X 1-AUG-90 1.0 DIGITAL DECstation 5000    10000 230 1000 hudgens@scri.fsu.edu
X 3-AUG-90 1.0 Alliant FX/2800                           SJA@SIRIUS.HUT.FI
X27-JUN-91 1.2 SUN     4/110 4.1.1        10 1000 10     LPH@PARADIGM.COM   
X27-JUN-91 1.2 SUN     4/110 4.1.1        1000 20 200 10 LPH@PARADIGM.COM   
X29-JUN-91 1.2 SUN     4/40C 4.1.1        9 29748 5877 4 jon@uk.ac.oxford.robots
X29-JUN-91 1.2 SUN     4/60 4.1.1         9 29748 5877 4 jon@uk.ac.oxford.robots
X29-JUN-91 1.2 SUN     4/100 4.1.1        9 29748 5877 4 jon@uk.ac.oxford.robots
X29-JUN-91 1.2 SUN     4/65 4.1.1         9 29748 5877 4 jon@uk.ac.oxford.robots
X18-JUL-91 1.2 SGI     Iris4d Unix 3.3.2  1000 $$ 1000 4 tsacas@ilog.ilog.fr
X29-JUL-91 1.1 IBM     RS/6000 AIX 1.3    script         brandis@inf.ethz.ch
X 5-SEP-91 1.6 IBM     RS/6000-320 AIX 3.1.5 +2000 666 50 40:00:00 LPH
X26-SEP-91 1.8 Nixdorf Targon/35 TOS3.3   script         petri@ibr.cs.tu-bs.de
X 9-SEP-93 2.0 Microsoft WNT Build 511 i486 +1000 24131 50 gjc@mitech.com
X 3-FEB-94 1.8 HP710/HP-UX 9.00 +2000 666 100 2:00:00 5 UFOP@fpsp.fapesp.br
X 5-MAY-94 2.0 HP807/HPUX 9.00  4000 666 100 00:30:00 2 UFOP@fpsp.fapesp.br
X
XNotes: Crashme V1.0 {1000 20 200} used to down the SUN 4/110. V1.2 does *not*
Xcrash SUNOS 4.1.1 on the same arguments. Although using the extra argument
Xfor subprocesses it will crash, with the console reporting:
X"Bad Trap, Bad Kernel Read Fault, Bus error. Reboot" 
X
XScript means invoking file with many calls to crashme such as this:
X#/bin/csh
Xcrashme 1020 234 500 &
Xcrashme 394 38484 5723 &
Xcrashme 3784 474 474 &
Xcrashme 437 4747 38 &
Xcrashme 47848 4745 123 &
Xcrashme 4747 4747 3463 &
Xcrashme 474 46464 262 &
Xcrashme 37 3644 3723 &
Xcrashme 374 46464 22 &
Xcrashme 3747 464 363 &
Xcrashme 347 4747 44 &
Xcrashme 37374 374 66 &
Xcrashme 3737 474 4444 &
X
XThe 4-argument case of crashme could likely do as well as executing
Xa script.
X
X*/
X
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#ifdef WIN32
X#include <excpt.h>
X#include <windows.h>
X#else
X#include <signal.h>
X#include <setjmp.h>
X#endif
X#include <time.h>
X#ifdef VMS
X#include <processes.h>
X#endif
X
X#ifdef pyr
X#include <sys/mman.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/vmmac.h>
X#define strchr index
X#endif
X
X#ifdef linux
X#include <unistd.h>
X#endif
X
Xtypedef void (*BADBOY)();
X
XBADBOY badboy;
X
Xlong nbytes,nseed,ntrys;
Xlong incptr = 0;
Xlong offset = 0;
Xlong next_offset = 0;
Xlong malloc_flag = 0;
Xunsigned char *the_data;
Xchar *note_buffer;
Xchar *notes;
X
Xlong verbose_level = 5;
X
Xvoid old_main(),copyright_note(),vfork_main(),badboy_loop();
Xvoid record_note();
X
X
XFILE *logfile = NULL;
X
Xvoid record_note()
X{char *logfilename;
X if (!(logfilename = getenv("CRASHLOG"))) return;
X if (!(logfile = fopen(logfilename,
X		       (strncmp(note_buffer,"Subprocess",10) == 0)
X		       ? "a" : "w")))
X   {perror(logfilename);
X    return;}
X if (note_buffer[strlen(note_buffer)-1] != '\n')
X   strcat(note_buffer,"\n");
X fputs(note_buffer,logfile);
X fclose(logfile);
X logfile = NULL;}
X
Xvoid open_record()
X{char *logfilename;
X if (!(logfilename = getenv("CRASHLOG"))) return;
X if (!(logfile = fopen(logfilename,"a")))
X   {perror(logfilename);
X    return;}}
X
Xvoid close_record()
X{if (logfile)
X   {fclose(logfile);
X    logfile = NULL;}}
X 
Xvoid note(level)
X     long level;
X{if (level > verbose_level) return;
X strcat(note_buffer,"\n");
X fputs(note_buffer,stdout);
X if (logfile)
X   fputs(note_buffer,logfile);}
X
X#ifndef WIN32
Xjmp_buf again_buff;
X#endif
X
Xunsigned char *bad_malloc(n)
X     long n;
X{unsigned char *data;
X data = (unsigned char *) malloc(n);
X#ifdef pyr
X if (mprotect(((int)data/PAGSIZ)*PAGSIZ, (n/PAGSIZ+1)*PAGSIZ,
X	      PROT_READ|PROT_WRITE|PROT_EXEC))
X   perror("mprotect");
X#endif
X return(data);}
X
X#ifndef WIN32
X
Xvoid again_handler(sig)
X     int sig;
X{char *ss;
X switch(sig)
X   {case SIGILL: ss =   " illegal instruction"; break;
X#ifdef SIGTRAP
X    case SIGTRAP: ss =   " trace trap"; break;
X#endif
X    case SIGFPE: ss =   " arithmetic exception"; break;
X#ifdef SIGBUS
X    case SIGBUS: ss =  " bus error"; break;
X#endif
X    case SIGSEGV: ss =  " segmentation violation"; break;
X#ifdef SIGIOT
X    case SIGIOT: ss = " IOT instruction"; break;
X#endif
X#ifdef SIGEMT
X    case SIGEMT: ss = " EMT instruction"; break;
X#endif
X#ifdef SIGALRM
X    case SIGALRM: ss = " alarm clock"; break;
X#endif
X    case SIGINT:  ss = " interrupt"; break;
X    default: ss = "";}
X sprintf(notes,"Got signal %d%s",sig,ss);
X note(5);
X longjmp(again_buff,3);}
X
Xvoid my_signal(sig, func)
X     int sig;
X     void (*func)();
X{
X#ifndef SA_ONESHOT
X signal(sig, func);
X#else
X struct sigaction act;
X act.sa_handler = func;
X act.sa_mask = 0;
X#ifdef linux
X act.sa_restorer = 0;
X#endif /* linux */
X act.sa_flags = SA_NOMASK;
X#ifdef SA_RESTART
X act.sa_flags |= SA_RESTART;
X#endif
X sigaction(sig, &act, 0);
X#endif /* SA_ONESHOT */
X}
X 
Xset_up_signals()
X{my_signal(SIGILL,again_handler);
X#ifdef SIGTRAP
X my_signal(SIGTRAP,again_handler);
X#endif
X my_signal(SIGFPE,again_handler);
X#ifdef SIGBUS
X my_signal(SIGBUS,again_handler);
X#endif
X my_signal(SIGSEGV,again_handler);
X#ifdef SIGIOT
X my_signal(SIGIOT,again_handler);
X#endif
X#ifdef SIGEMT
X my_signal(SIGEMT,again_handler);
X#endif
X#ifdef SIGALRM
X my_signal(SIGALRM,again_handler);
X#endif
X my_signal(SIGINT,again_handler);}
X
X#endif
X
Xcompute_badboy_1(n)
X     long n;
X{long j;
X if (malloc_flag == 1)
X   the_data = bad_malloc(n);
X for(j=0;j<n;++j) the_data[j] = (rand() >> 7) & 0xFF;
X if (nbytes < 0)
X   {sprintf(notes,"Dump of %ld bytes of data",n);
X    note(1);
X    for(j=0;j<n;++j)
X      {fprintf(stdout,"%3d",the_data[j]);
X       if ((j % 20) == 19) putc('\n',stdout); else putc(' ',stdout);}
X    putc('\n',stdout);}}
X
Xvoid proto_badboy()
X{printf("Hello world.\n");}
X
X#if defined(__ALPHA) && defined(VMS) && !defined(NOCASTAWAY)
X#include <pdscdef.h>
X#endif
X
XBADBOY castaway(dat)
X     char *dat;
X{
X#if defined(VAX) && !defined(NOCASTAWAY)
X  /* register save mask avoids bashing our callers locals */
X  ((unsigned short *)dat)[0] = 0x0FFC;
X#endif
X#if defined(__ALPHA) && defined(VMS) && !defined(NOCASTAWAY)
X  struct pdscdef *p,*b;
X  p = (struct pdscdef *) proto_badboy;
X  b = (struct pdscdef *) dat;
X  memcpy(b,p,sizeof(struct pdscdef));
X  b->pdsc$q_entry[1] = 0;
X  b->pdsc$q_entry[0] = (int)&dat[sizeof(struct pdscdef)];
X#endif
X#if (defined(_IBMR2) || defined(_POWER)) && !defined(NOCASTAWAY)
X  struct fdesc {void *fcn_addr; void *toc; void *linkage;} *p,*b;
X  p = (struct fdesc *) proto_badboy;
X  b = (struct fdesc *) dat;
X  memcpy(b,p,sizeof(struct fdesc));
X  b->fcn_addr = (void *) &dat[sizeof(struct fdesc)];
X#endif
X#if defined(__hpux) && defined(__hppa) && !defined(NOCASTAWAY)
X  struct fdesc {void *fcn_addr; void *toc;} *p,*b;
X  p = (struct fdesc *) proto_badboy;
X  b = (struct fdesc *) dat;
X  memcpy(b,p,sizeof(struct fdesc));
X  b->fcn_addr = (void *) &dat[sizeof(struct fdesc)];
X#endif
X  return((BADBOY)dat);}
X
Xcompute_badboy()
X{long n;
X n = (nbytes < 0) ? - nbytes : nbytes;
X if (incptr == 0)
X   {compute_badboy_1(n);
X    badboy = castaway(the_data);}
X else if ((next_offset == 0) || (next_offset > ((n * 90) / 100)))
X   {compute_badboy_1(n);
X    offset = 0;
X    next_offset = offset + incptr;
X    badboy = castaway(the_data);}
X else
X   {offset = next_offset;
X    next_offset = offset + incptr;
X    badboy = castaway(&the_data[offset]);}}
X
X/* maybe add this code before invoking badboy. But it didn't seem
X   to be needed when using +1000.
X   FlushInstructionCache(GetCurrentProcess(),
X                         the_data,(nbytes < 0) ? - nbytes : nbytes);
X*/
X
Xtry_one_crash()
X{if (nbytes > 0)
X   (*badboy)();
X else if (nbytes == 0)
X   while(1);}
X
Xchar *subprocess_ind = "subprocess";
X 
Xmain(argc,argv)
X     int argc; char **argv;
X{long nsubs,hrs,mns,scs,tflag,j,m;
X note_buffer = (char *) malloc(512);
X notes = note_buffer;
X if ((argc == 7) &&
X     (strcmp(argv[6],subprocess_ind) == 0))
X   {sprintf(note_buffer,"Subprocess %s: ",argv[4]);
X    notes = note_buffer + strlen(note_buffer);
X    verbose_level = atol(argv[5]);
X    sprintf(notes,"starting");
X    note(3);
X    old_main(4,argv);}
X else if (argc == 4)
X   old_main(4,argv);
X else if ((argc == 6) && ((strlen(argv[4]) == 0) ||
X			  (strcmp(argv[4],".") == 0)))
X   {verbose_level = atol(argv[5]);
X    old_main(4,argv);}
X else if ((argc == 5) || (argc == 6))
X   {if (argc == 6)
X      verbose_level = atol(argv[5]);
X    copyright_note(1);
X    if (argc < 7)
X      m = argc;
X    else
X      m = 6;
X    strcpy(notes,"crashme");
X    for(j=1;j<m;++j)
X      {strcat(notes," ");
X       strcat(notes,argv[j]);}
X    note(1);
X    record_note();
X    if (strchr(argv[4],':'))
X      {sscanf(argv[4],"%d:%d:%d",&hrs,&mns,&scs);
X       tflag = 1;
X       nsubs = (((hrs * 60) + mns) * 60) + scs;
X       sprintf(notes,"Subprocess run for %d seconds (%d %02d:%02d:%02d)",
X	       nsubs, hrs / 24, hrs % 24,mns,scs);}
X    else
X      {tflag = 0;
X       nsubs = atol(argv[4]);
X       sprintf(notes,"Creating %d crashme subprocesses",nsubs);}
X    note(1);
X    vfork_main(tflag,nsubs,argv[0],argv[1],atol(argv[2]),argv[3]);}
X else
X   {sprintf(notes,
X	    "crashme [+]<nbytes>[.inc] <srand> <ntrys> [nsub] [verbose]");
X    note(0);}}
X
Xvoid copyright_note(n)
X     long n;
X{sprintf(notes,"Crashme: (c) Copyright 1990-1994 George J. Carrette");
X note(n);
X sprintf(notes,"Version: %s",crashme_version);
X note(n);}
X
Xvoid old_main(argc,argv)
X     int argc;
X     char **argv;
X{char *ptr;
X copyright_note(3);
X nbytes = atol(argv[1]);
X if (ptr = strchr(argv[1],'.'))
X   incptr = atol(&ptr[1]);
X if (argv[1][0] == '+') malloc_flag = 1;
X nseed = atol(argv[2]);
X ntrys = atol(argv[3]);
X sprintf(notes,"crashme %s%ld.%d %ld %ld",
X	 (malloc_flag == 0) ? "" : "+",nbytes,incptr,nseed,ntrys);
X note(3);
X record_note();
X if (malloc_flag == 0)
X   {the_data = bad_malloc((nbytes < 0) ? -nbytes : nbytes);
X    badboy = castaway(the_data);
X    sprintf(notes,"Badboy at %d. 0x%X",badboy,badboy);
X    note(3);}
X srand(nseed);
X#ifdef WIN32
X SetErrorMode(SEM_FAILCRITICALERRORS |
X	      SEM_NOGPFAULTERRORBOX |
X	      SEM_NOOPENFILEERRORBOX);
X#endif
X badboy_loop();}
X
X#ifdef WIN32
XDWORD exception_filter(DWORD value)
X{int sev,cus,res,fac,cod;
X sev = 3 & (value >> 30);
X cus = 1 & (value >> 29);
X res = 1 & (value >> 28);
X fac = 07777 & (value >> 16);
X cod = 0xFFFF & value;
X sprintf(notes,"sev(%d)cus(%d)res(%d)fac(%d)code(%d)",
X	 sev,cus,res,fac,cod);
X note(5);
X return(EXCEPTION_EXECUTE_HANDLER);}
X#endif
X
Xvoid badboy_loop()
X{int i;
X for(i=0;i<ntrys;++i)
X   {compute_badboy();
X    if (offset)
X      sprintf(notes,"try %d, offset %d",i,offset);
X    else if (malloc_flag == 1)
X      sprintf(notes,"try %d, Badboy at %d. 0x%X",i,badboy,badboy);
X    else
X      sprintf(notes,"try %d",i);
X    note(5);
X
X#ifdef WIN32
X    try {try_one_crash();
X	 sprintf(notes,"didn't barf!");
X	 note(5);}
X    except(exception_filter(GetExceptionCode()))
X      {}
X#else
X    if (setjmp(again_buff) == 3)
X      {sprintf(notes,"Barfed");
X       note(5);}
X    else
X      {set_up_signals();
X       alarm(10);
X       try_one_crash();
X       sprintf(notes,"didn't barf!");
X       note(5);}
X#endif
X  }}
X
Xstruct status_list
X{long status;
X long count;
X struct status_list *next;};
X
Xstruct status_list *slist = NULL;
X
Xrecord_status(n)
X     long n;
X{struct status_list *l;
X for(l=slist;l != NULL; l = l->next)
X   if (n == l->status)
X     return(++l->count);
X l = (struct status_list *) malloc(sizeof(struct status_list));
X l->count = 1;
X l->status = n;
X l->next = slist;
X slist = l;
X return(1);}
X
Xsummarize_status()
X{struct status_list *l;
X sprintf(notes,"exit status ... number of cases");
X note(2);
X for(l=slist;l != NULL; l = l->next)
X   {sprintf(notes,"exit status ... number of cases");
X    sprintf(notes,"%11d ... %5d",l->status,l->count);
X    note(2);}}
X
X#ifndef WIN32
X
Xlong monitor_pid = 0;
Xlong monitor_period = 5;
Xlong monitor_limit =  6; /* 30 second limit on a subprocess */
Xlong monitor_count = 0;
Xlong monitor_active = 0;
X
Xvoid monitor_fcn(sig)
X     int sig;
X{long status;
X my_signal(SIGALRM,monitor_fcn);
X alarm(monitor_period);
X if (monitor_active)
X   {++monitor_count;
X    if (monitor_count >= monitor_limit)
X      {sprintf(notes,"time limit reached on pid %d 0x%X. using kill.",
X	       monitor_pid,monitor_pid);
X       note(3);
X       status = kill(monitor_pid,SIGKILL);
X       if (status < 0)
X	 {sprintf(notes,"failed to kill process");
X	  note(3);}
X       monitor_active = 0;}}}
X
Xvoid vfork_main(tflag,nsubs,cmd,nb,sr,nt)
X     long tflag,nsubs,sr;
X     char *cmd,*nb,*nt;
X{long j,pid,n,seq,total_time,dys,hrs,mns,scs;
X int status;
X char arg2[20],arg4[20],arg5[20];
X time_t before_time,after_time;
X if (tflag == 1)
X   {seq = 1;
X    n = 100000000;}
X else if (nsubs < 0)
X   {n = -nsubs;
X    seq = 1;}
X else
X   {n = nsubs;
X    seq = 0;}
X if (seq == 1)
X   {my_signal(SIGALRM,monitor_fcn);
X    alarm(monitor_period);}
X time(&before_time);
X sprintf(arg5,"%d",verbose_level);
X for(j=0;j<n;++j)
X   {sprintf(arg2,"%d",sr+j);
X    sprintf(arg4,"%d",j+1);
X#ifdef VMS
X    status = vfork();
X#else
X    status = fork();
X#endif
X    if (status == 0)
X      {status = execl(cmd,cmd,nb,arg2,nt,arg4,arg5,subprocess_ind,0);
X       if (status == -1)
X	 {perror(cmd);
X	  exit(1);}}
X    else if (status < 0)
X      perror(cmd);
X    else
X      {sprintf(notes,"pid = %d 0x%X (subprocess %d)",status,status,j+1);
X       note(3);
X       if (seq == 1)
X	 {monitor_pid = status;
X	  monitor_count = 0;
X	  monitor_active = 1;
X	  while((pid = wait(&status)) > 0)
X	    {monitor_active = 0;
X	     sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status);
X	     note(3);
X	     record_status(status);}}
X       if (tflag == 1)
X	 {time(&after_time);
X	  total_time = after_time - before_time;
X	  if (total_time >= nsubs)
X	    {sprintf(notes,"Time limit reached after run %d",j+1);
X	     note(2);
X	     break;}}}}
X if (seq == 0)
X   while((pid = wait(&status)) > 0)
X     {sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status);
X      note(3);
X      record_status(status);}
X time(&after_time);
X total_time = after_time - before_time;
X scs = total_time;
X mns = scs / 60;
X hrs = mns / 60;
X dys = hrs / 24;
X scs = scs % 60;
X mns = mns % 60;
X hrs = hrs % 24;
X open_record();
X sprintf(notes,
X	 "Test complete, total real time: %d seconds (%d %02d:%02d:%02d)",
X	 total_time,dys,hrs,mns,scs);
X note(1);
X summarize_status();
X close_record();}
X
X#else
X
Xvoid chk_CloseHandle(HANDLE h)
X{DWORD err;
X if (CloseHandle(h) == FALSE)
X   {err = GetLastError();
X    sprintf(notes,"err %d trying to close handle.",err);
X    note(3);}}
X
Xint maxticks = 100; /* tenths of a second before forced termination
X		       of the subprocess */
X
Xvoid vfork_main(tflag,nsubs,cmd,nb,sr,nt)
X     long tflag,nsubs,sr;
X     char *cmd,*nb,*nt;
X{long j,pid,n,seq,total_time,dys,hrs,mns,scs;
X char arg2[20],arg4[20],arg5[20];
X time_t before_time,after_time;
X char cmdbuf[250];
X int nticks;
X PROCESS_INFORMATION pinfo;
X STARTUPINFO sinfo;
X DWORD exit_code,err;
X if (tflag == 1)
X   {seq = 1;
X    n = 100000000;}
X else if (nsubs < 0)
X   {n = -nsubs;
X    seq = 1;}
X else
X   {n = nsubs;
X    seq = 0;}
X /* tflag says this is a timed run. So nsub is the time in seconds.
X    seq says to run in sequence, not created nsub processes all
X    at once. */
X if (seq == 0)
X   {printf("Not implemented. Use [-nsub] or [HH:MM:SS] instead.\n");
X    return;}
X time(&before_time);
X sprintf(arg5,"%d",verbose_level);
X for(j=0;j<n;++j)
X   {sprintf(arg2,"%d",sr+j);
X    sprintf(arg4,"%d",j+1);
X    sprintf(cmdbuf,"%s %s %s %s %s %s %s",
X	    cmd,nb,arg2,nt,arg4,arg5,subprocess_ind);
X    /* kind of dumb that this sinfo structure is a required argument */
X    memset(&sinfo,0,sizeof(STARTUPINFO));
X    sinfo.cb = sizeof (STARTUPINFO);
X    if (CreateProcess(NULL,cmdbuf,NULL,NULL,TRUE,0,NULL,NULL,&sinfo,&pinfo)
X	== FALSE)
X      {err = GetLastError();
X       sprintf(notes,"err %d trying to create process",err);
X       continue;}
X    sprintf(notes,"pid = %d 0x%X (subprocess %d)",
X	    pinfo.dwProcessId,pinfo.dwProcessId,j+1);
X    note(3);
X    nticks = 0;
X    while(1)
X      {if (GetExitCodeProcess(pinfo.hProcess,&exit_code) == TRUE)
X	 {if (exit_code == STILL_ACTIVE)
X	    {if (nticks == maxticks)
X	       {sprintf(notes,"time limit reached on pid %d 0x%X. using kill.",
X			pinfo.dwProcessId,pinfo.dwProcessId);
X		note(3);
X		if (TerminateProcess(pinfo.hProcess,
X				     APPLICATION_ERROR_MASK |
X				     ERROR_SEVERITY_ERROR |
X				     1) == FALSE)
X		  {err = GetLastError();
X		   sprintf(notes,"err %d trying to terminate process.",err);
X		   note(3);
X		   chk_CloseHandle(pinfo.hProcess);
X		   chk_CloseHandle(pinfo.hThread);
X		   break;}
X		++nticks;}
X	    else
X	      {++nticks;
X	       Sleep(100);}}
X	 else
X	   {sprintf(notes,"pid %d 0x%X exited with status %d",
X		    pinfo.dwProcessId,pinfo.dwProcessId,exit_code);
X	    note(3);
X	    record_status(exit_code);
X	    chk_CloseHandle(pinfo.hProcess);
X	    chk_CloseHandle(pinfo.hThread);
X	    break;}}
X      else
X	{err = GetLastError();
X	 sprintf(notes,"err %d on GetExitCodeProcess.");
X	 note(3);
X	 chk_CloseHandle(pinfo.hProcess);
X	 chk_CloseHandle(pinfo.hThread);
X	 break;}}
X    if (tflag == 1)
X      {time(&after_time);
X       total_time = after_time - before_time;
X       if (total_time >= nsubs)
X	 {sprintf(notes,"Time limit reached after run %d",j+1);
X	  note(2);
X	  break;}}}
X time(&after_time);
X total_time = after_time - before_time;
X scs = total_time;
X mns = scs / 60;
X hrs = mns / 60;
X dys = hrs / 24;
X scs = scs % 60;
X mns = mns % 60;
X hrs = hrs % 24;
X open_record();
X sprintf(notes,
X	 "Test complete, total real time: %d seconds (%d %02d:%02d:%02d)",
X	 total_time,dys,hrs,mns,scs);
X note(1);
X summarize_status();
X open_record();}
X
X#endif
X
SHAR_EOF
true || echo 'restore of crashme.c failed'
fi
# ============= crashme.opt ==============
if test -f 'crashme.opt' -a X"$1" != X"-c"; then
	echo 'x - skipping crashme.opt (File already exists)'
else
echo 'x - extracting crashme.opt (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'crashme.opt' &&
X! VMS LINKER OPTIONS FILE
XIDENTIFICATION = "CRASHME V1.8"
XSYS$LIBRARY:VAXCRTL/SHARE
SHAR_EOF
true || echo 'restore of crashme.opt failed'
fi
# ============= descrip.mms ==============
if test -f 'descrip.mms' -a X"$1" != X"-c"; then
	echo 'x - skipping descrip.mms (File already exists)'
else
echo 'x - extracting descrip.mms (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'descrip.mms' &&
X! VMS MAKEFILE (for MMS)
X!
X
Xall depends_on crashme.exe pddet.exe
X !(ALL DONE)
X
Xcrashme.exe depends_on crashme.obj
X optarg = ",crashme.opt/opt"
X if f$getsyi("SID") .lt. 0 then optarg = ""
X link crashme.obj'optarg'
X ! re-execute the next line in your superior process:
X crashme == "$" + f$env("DEFAULT") + "CRASHME"
X
Xcrashme.obj depends_on crashme.c
X PF = ""
X if f$getsyi("SID") .lt. 0 then PF = "/PREFIX=ALL"
X CC/DEBUG/OPTIMIZE=(NOINLINE)'PF' CRASHME.C
X
Xpddet.exe depends_on pddet.obj
X optarg = ",crashme.opt/opt"
X if f$getsyi("SID") .lt. 0 then optarg = ""
X link pddet.obj'optarg'
X ! re-execute the next line in your superior process:
X pddet == "$" + f$env("DEFAULT") + "PDDET"
X
Xpddet.obj depends_on pddet.c
X PF = ""
X if f$getsyi("SID") .lt. 0 then PF = "/PREFIX=ALL"
X CC/DEBUG/OPTIMIZE=(NOINLINE)'PF' PDDET.C
X
X
Xcrashme_dbg.exe depends_on crashme.obj
X optarg = ",crashme.opt/opt"
X if f$getsyi("SID") .lt. 0 then optarg = ""
X link/debug/exe=crashme_dbg.exe crashme.obj'optarg'
X
X! note: do not use continuation character here.
XDIST_FILES = crashme.1,crashme.c,makefile,descrip.mms,crashme.opt,read.me,shar.db,makefile.wnt,make.bat,pddet.c
X
Xcrashme.shar depends_on $(DIST_FILES)
X minishar crashme.shar shar.db
X
Xcrashme.1_of_1 depends_on $(DIST_FILES)
X define share_max_part_size 1000
X vms_share $(DIST_FILES) crashme
SHAR_EOF
true || echo 'restore of descrip.mms failed'
fi
# ============= make.bat ==============
if test -f 'make.bat' -a X"$1" != X"-c"; then
	echo 'x - skipping make.bat (File already exists)'
else
echo 'x - extracting make.bat (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'make.bat' &&
XNMAKE /f MAKEFILE.WNT %1 %2
SHAR_EOF
true || echo 'restore of make.bat failed'
fi
# ============= makefile ==============
if test -f 'makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping makefile (File already exists)'
else
echo 'x - extracting makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
Xall: crashme pddet
X
Xcrashme:	crashme.o
X	cc -o crashme crashme.o
Xcrashme.o: crashme.c
X	cc -c crashme.c
X
Xpddet:	pddet.o
X	cc -o pddet pddet.o
Xpddet.o: pddet.c
X	cc -c pddet.c
X
SHAR_EOF
true || echo 'restore of makefile failed'
fi
# ============= makefile.wnt ==============
if test -f 'makefile.wnt' -a X"$1" != X"-c"; then
	echo 'x - skipping makefile.wnt (File already exists)'
else
echo 'x - extracting makefile.wnt (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile.wnt' &&
X!include <ntwin32.mak>
X
X# Makefile for Crashme, under Microsoft Windows NT.
X# use the MAKE.BAT to invoke this if you want to use
X# the posix environment. 
X#    make posix
X# in order to define environment variables needed.
X#
X# NMAKE /f MAKEFILE.WNT
X
X# 9-SEP-93 George Carrette. GJC@MITECH.COM
X
Xall: crashme.exe crashmep.exe pddet.exe
X
Xcrashme.exe : crashme.obj
X $(link) $(ldebug) $(conflags) -out:crashme.exe crashme.obj $(conlibs) 
X
Xcrashme.obj : crashme.c
X $(cc) $(cdebug) $(cflags) $(cvars) crashme.c -Focrashme.obj
X
Xpddet.exe : pddet.obj
X $(link) $(ldebug) $(conflags) -out:pddet.exe pddet.obj $(conlibs) 
X
Xpddet.obj : pddet.c
X $(cc) $(cdebug) $(cflags) $(cvars) pddet.c -Fopddet.obj
X
X#  call %mstools%\posix\setnvpsx %mstools%
X
Xcrashmep.exe : crashmep.obj
X set Lib=%%mstools%%\posix\lib;%%lib%%
X $(link) $(ldebug) $(psxflags) -out:crashmep.exe crashmep.obj $(psxlibs) 
X
Xcrashmep.obj : crashme.c
X set Include=%%mstools%%\posix\h;%%include%%
X $(cc) $(cdebug) $(cflags) $(psxvars) crashme.c -Focrashmep.obj
X
SHAR_EOF
true || echo 'restore of makefile.wnt failed'
fi
# ============= pddet.c ==============
if test -f 'pddet.c' -a X"$1" != X"-c"; then
	echo 'x - skipping pddet.c (File already exists)'
else
echo 'x - extracting pddet.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pddet.c' &&
X/*
X *             COPYRIGHT (c) 1994 BY             *
X *  GEORGE J. CARRETTE, CONCORD, MASSACHUSETTS.  *
X *             ALL RIGHTS RESERVED               *
X
XPermission to use, copy, modify, distribute and sell this software
Xand its documentation for any purpose and without fee is hereby
Xgranted, provided that the above copyright notice appear in all copies
Xand that both that copyright notice and this permission notice appear
Xin supporting documentation, and that the name of the author
Xnot be used in advertising or publicity pertaining to distribution
Xof the software without specific, written prior permission.
X
XTHE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
XHE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
XSOFTWARE.
X
XThe purpose of this routine is to attempt to detect the use of
Xprocedure descriptors by making a note of how far apart the
Xsystem allocates pointers to subroutines of different sizes.
XIf all the subroutines are the same distance apart then
Xprocedure descriptors are probably in use on this architecture.
X
XThis file should be compiled without any compiler optimization
Xsuch as inlining that would confuse the test. Although base functions
Xhave been made somewhat complex in order to avoid that in any case.
X
XNow if a linker lays out procedures like this:
X
X[DESCRIPTOR][CODE TEXT...][DESCRIPTOR][CODE TEXT...]
X
XThen this code will be confused into thinking descriptors aren't used.
XBut usually the hallmark of a descriptor architecture is that descriptors
Xare in a table located away from the program code text.
X
XThe -examine <nbytes> argument lets you see in a crude way what
Xis contained in the pointer to a procedure data.
X
X19-MAY-1994 GJC@MITECH.COM
X
X*/
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X
Xstruct v {long n;double *a;};
X
Xstruct v *vcons(n,x)
X     long n;
X     double x;
X{struct v *p;
X long j;
X p = (struct v *) malloc(sizeof(struct v));
X p->n = n;
X p->a = (double *) malloc(sizeof(double)*n);
X for(j=0;j<n;++j) p->a[j] = x;
X return(p);}
X
Xstruct v *vprod(x,y)
X     struct v *x,*y;
X{struct v *z;
X long j;
X z = vcons(x->n);
X for(j=0;j<x->n;++j) z->a[j] = x->a[j] * y->a[j];
X return(z);}
X
Xdouble vsume(x)
X     struct v *x;
X{double sum = 0.0;
X long j;
X for(j=0;j<x->n;++j) sum += x->a[j];
X return(sum);}
X
Xdouble viprod(x,y)
X     struct v *x,*y;
X{return(vsume(vprod(x,y)));}
X
Xdouble vnorm(x)
X     struct v *x;
X{return(viprod(x,x));}
X
Xdouble case10()
X{double acc = 0.0;
X acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0));
X return(acc);}
X
Xdouble case20()
X{double acc = 0.0;
X acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0));
X return(acc);}
X
Xdouble case30()
X{double acc = 0.0;
X acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(20,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(21,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(22,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(23,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(24,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(25,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(26,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(27,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(28,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(29,1.0)),2.0));
X return(acc);}
X
Xdouble case40()
X{double acc = 0.0;
X acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(20,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(21,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(22,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(23,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(24,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(25,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(26,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(27,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(28,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(29,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(30,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(31,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(32,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(33,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(34,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(35,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(36,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(37,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(38,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(39,1.0)),2.0));
X return(acc);}
X
Xdouble case50()
X{double acc = 0.0;
X acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(20,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(21,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(22,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(23,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(24,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(25,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(26,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(27,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(28,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(29,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(30,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(31,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(32,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(33,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(34,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(35,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(36,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(37,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(38,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(39,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(40,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(41,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(42,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(43,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(44,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(45,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(46,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(47,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(48,1.0)),2.0));
X acc += vnorm(vcons((long)vsume(vcons(49,1.0)),2.0));
X return(acc);}
X
Xvoid sayarch(x)
X     char *x;
X{printf("This architecture %s procedure descriptors\n",x);}
X
X
Xstruct apair {char *name;unsigned long addr;};
Xstruct adelt {long delta; long count;};
X
Xint apairl(a,b)
X     struct apair *a,*b;
X{if (a->addr < b->addr) return(-1);
X else if (a->addr > b->addr) return(1);
X else return(0);}
X
Xint adeltl(a,b)
X     struct adelt *a,*b;
X{if (a->delta < b->delta) return(-1);
X else if (a->delta > b->delta) return(1);
X else return(0);}
X
Xmain(argc,argv)
X     int argc;
X     char **argv;
X{struct apair all[10];
X struct adelt deltas[10];
X long j,k,n=10,min_delta,max_delta,delta,d,ebytes=0;
X unsigned char *data,*prev_data;
X for(j=1;(j+1)<argc;j += 2)
X   {if (strcmp(argv[j],"-examine") == 0)
X      ebytes = atol(argv[j+1]);}
X for(j=0;j<n;++j)
X   {deltas[j].delta = 0;
X    deltas[j].count = 0;}
X all[0].name = "vcons";
X all[0].addr = (unsigned long) vcons;
X all[1].name = "vprod";
X all[1].addr = (unsigned long) vprod;
X all[2].name = "vsume";
X all[2].addr = (unsigned long) vsume;
X all[3].name = "viprod";
X all[3].addr = (unsigned long) viprod;
X all[4].name = "vnorm";
X all[4].addr = (unsigned long) vnorm;
X all[5].name = "case10";
X all[5].addr = (unsigned long) case10;
X all[6].name = "case20";
X all[6].addr = (unsigned long) case20;
X all[7].name = "case30";
X all[7].addr = (unsigned long) case30;
X all[8].name = "case40";
X all[8].addr = (unsigned long) case40;
X all[9].name = "case50";
X all[9].addr = (unsigned long) case50;
X if (ebytes > 0)
X   {printf("%10s %10s %s\n","procedure","address","examine");
X    for(j=0;j<n;++j)
X      {printf("%10s %10d ",all[j].name,all[j].addr);
X       data = (unsigned char *) all[j].addr;
X       if (j > 0)
X	 prev_data = (unsigned char *) all[j-1].addr;
X       else
X	 prev_data = NULL;
X       for(k=0;k<ebytes;++k)
X	 if (prev_data && (prev_data[k] == data[k]))
X	   printf("..");
X	 else
X	   printf("%02X",data[k]);
X       printf("\n");}}
X qsort(all,n,sizeof(struct apair),apairl);
X printf("%10s %10s %10s\n","procedure","address","delta");
X for(j=0;j<n;++j)
X   {if (j>0)
X      {delta = all[j].addr - all[j-1].addr;
X       if (j == 1)
X	 min_delta = max_delta = delta;
X       else
X	 {if (delta < min_delta) min_delta = delta;
X	  if (delta > max_delta) max_delta = delta;}
X       for(k=0;k<n;++k)
X	 if(deltas[k].count == 0)
X	   {deltas[k].delta = delta;
X	    deltas[k].count = 1;
X	    break;}
X	 else if(deltas[k].delta == delta)
X	   {++deltas[k].count;
X	    break;}}
X    else
X      delta = 0;
X    printf("%10s %10d %10d\n",all[j].name,all[j].addr,delta);}
X printf("min_delta = %d, max_delta = %d\n",min_delta,max_delta);
X if (min_delta == max_delta)
X   sayarch("probably uses");
X else
X   {qsort(deltas,n,sizeof(struct adelt),adeltl);
X    printf("%10s %s\n","delta","count");
X    for(d=0,k=0;k<n;++k)
X      if (deltas[k].count > 0)
X	{printf("%10d %d\n",deltas[k].delta,deltas[k].count);
X	 ++d;}
X    if (d > 4)
X      sayarch("probably does not use");
X    else
X      sayarch("may be using");}}
SHAR_EOF
true || echo 'restore of pddet.c failed'
fi
exit 0
