crashme-2.4.orig/ 40755 1750 1750 0 6536345354 13601 5ustar jkominekjkominekcrashme-2.4.orig/crashme.1100644 1750 1750 5736 6266716134 15413 0ustar jkominekjkominek.TH CRASHME 1C LOCAL .SH NAME crashme \- test operating environment software robustness .SH SYNOPSIS .B crashme [NBYTES] [SRAND] [NTRYS] [NSUB] [VERBOSE] .SH DESCRIPTION .I crashme is a very simple program that tests the operating environment's robustness by invoking random data as if it were a procedure. The standard signals are caught and handled with a setjmp back to a loop which will try again to produce a fault by executing random data. Some people call this stress testing. .RE .SS COMMAND LINE OPTIONS .TP 8 .BI [NBYTES] The .I [NBYTES] should be an integer, specifying the size of the random data string in bytes. If given negative then the bytes are printed instead of being executed. If given with an explicit plus sign then the storage for the bytes is freshly malloc'ed each time. This can have an effect on machines with seperate I and D cache mechanisms. The argument can also have a dot in it, X.Y, in which case Y is a increment for a pointer into the random data. The buffer is recalculated only when the pointer gets near the end of the data. .TP .BI [SRAND] The .I [SRAND] is an input seed to the random number generator, passed to srand. .TP .BI [NTRIES] The .I [NTRIES] is how many times to loop before exiting normally from the program. .TP .BI [NSUB] The .I [NSUB] is optional, the number of vfork subprocesses running all at once. If negative run one after another. If given as a time hrs:mns:scs (hours, minutes, seconds) then one subprocess will be run to completion, followed by another, until the time limit has been reached. If this argument is given as the empty string or . then it is ignored. When in sequential-subprocess mode there is a 30 second time limit on each subprocess. This is to allow the instruction-set-space random walk to continue when a process bashes itself into an infinite loop. For example, the ntrys can be bashed to a very large number with nbytes bashed to zero. (10 second limit on Windows NT). The SRAND argument is incremented by one for each subprocess. .TP .BI [VERBOSE] The .I [VERBOSE] arg is optional. 0 is the least verbose, 5 the most. .SH EXAMPLE This is a suggested test, to run it for a least an hour. crashme +2000 666 100 1:00:00 .SH FILES crashme.c .PD .SH DIAGNOSTICS When a signal is caught the number and nature of the signal is indicated. Setting the environment variable CRASHLOG will cause each subprocess to record the arguments it was given. .SH BUGS Not all signals are caught, and the state of the user program/process enviroment can be sufficiently damaged such that the program terminates before going through all [NTRIES] operations. If the architecture uses some kind of procedure descriptor but no special code has been not been added to castaway() in crashme.c then the stress test will not be as potent as it would otherwise be. Beware: This program can crash your computer if the operating system or hardware of same is buggy. User data may be lost. .SH AUTHOR George J Carrette. GJC\@world.std.com .SH VERSION 2.4 20-MAY-1994 crashme-2.4.orig/crashme.c100644 1750 1750 52310 6266716234 15504 0ustar jkominekjkominek/* crashme: Create a string of random bytes and then jump to it. crashme [+][.inc] [nsub] [verboseness] */ char *crashme_version = "2.4 20-MAY-1994"; /* * COPYRIGHT (c) 1990-1994 BY * * GEORGE J. CARRETTE, CONCORD, MASSACHUSETTS. * * ALL RIGHTS RESERVED * Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. A signal handler is set up so that in most cases the machine exception generated by the illegal instructions, bad operands, etc in the procedure made up of random data are caught; and another round of randomness may be tried. Eventually a random instruction may corrupt the program or the machine state in such a way that the program must halt. This is a test of the robustness of the hardware/software for instruction fault handling. Note: Running this program just a few times, using total CPU time of less than a few seconds SHOULD NOT GIVE YOU ANY CONFIDENCE in system robustness. Having it run for hours, with tens of thousands of cases would be a different thing. It would also make sense to run this stress test at the same time you run other tests, like a multi-user benchmark. Comments may be addressed to the author at GJC@WORLD.STD.COM See the documentation in crashme.1 and READ.ME, or read this code for a description of command line arguments to this program. Version Date Description ---------------------------------------------------------------------- 1.0 early 1990 initial hack. 1.1 19-SEP-1990 added more signals and an alarm to abort looping. 1.2 25-JUN-1991 added [nsub] to vfork multiple subprocesses of self. 1.3 14-AUG-1991 +nbytes malloc option, and -nsub option. 1.4 29-AUG-1991 fix +nbytes (subproc). Add time-driven nprocs. SIGINT. 1.5 3-SEP-1991 added alarm subprocess monitor to vfork_main. 1.6 5-SEP-1991 some systems don't have vfork, so use fork by default. 1.7 25-SEP-1991 verboseness level, exit summary report. 1.8 -SEP-1991 address page protection issues on badboy. 1.9 6-AUG-1993 DECC(VMS)/WIN32/NT/Posix, #ifdef some SIGxxx. 2.0 7-SEP-1993 More extensive WIN32 conditionalization. record_note. 2.1 6-MAY-1994 Added "dot" syntax to NBYTES. Modularized castaway. 2.2 9-MAY-1994 __ALPHA && VMS version is now more interesting. 2.3 11-MAY-1994 Added _IBMRT2 and _POWER code. 2.4 20-MAY-1994 Added __hpux. Linux from jik@cam.ov.com. Suggested test: At least let the thing run the length of your lunch break, in this case 1 hour, 10 minutes, and 30 seconds. crashme +2000 666 100 1:10:30 2 Also, it may spend more time trapping and less time computing random bytes by using these arguments: crashme +2000.80 666 100 1:10:30 2 CRASH REPORTS Date, Machine Crashme Reported Crashme Ver Make Model OS Version Arguments by: ------------------------------------------------------------------------------ 10-JUL-90 1.0 SUN 4/110 4.1 1000 20 200 GJC@paradigm.com 10-JUL-90 1.0 SUN 4/280 4.0.3 1000 20 200 GJC@paradigm.com 31-JUL-90 1.0 DIGITAL DECstation 3100 100 10 10000 GAVRON@ARIZONA.EDU 31-JUL-90 1.0 IBM RT 100 10 10000 GAVRON@ARIZONA.EDU 1-AUG-90 1.0 DIGITAL DECstation 5000 10000 230 1000 hudgens@scri.fsu.edu 3-AUG-90 1.0 Alliant FX/2800 SJA@SIRIUS.HUT.FI 27-JUN-91 1.2 SUN 4/110 4.1.1 10 1000 10 LPH@PARADIGM.COM 27-JUN-91 1.2 SUN 4/110 4.1.1 1000 20 200 10 LPH@PARADIGM.COM 29-JUN-91 1.2 SUN 4/40C 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots 29-JUN-91 1.2 SUN 4/60 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots 29-JUN-91 1.2 SUN 4/100 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots 29-JUN-91 1.2 SUN 4/65 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots 18-JUL-91 1.2 SGI Iris4d Unix 3.3.2 1000 $$ 1000 4 tsacas@ilog.ilog.fr 29-JUL-91 1.1 IBM RS/6000 AIX 1.3 script brandis@inf.ethz.ch 5-SEP-91 1.6 IBM RS/6000-320 AIX 3.1.5 +2000 666 50 40:00:00 LPH 26-SEP-91 1.8 Nixdorf Targon/35 TOS3.3 script petri@ibr.cs.tu-bs.de 9-SEP-93 2.0 Microsoft WNT Build 511 i486 +1000 24131 50 gjc@mitech.com 3-FEB-94 1.8 HP710/HP-UX 9.00 +2000 666 100 2:00:00 5 UFOP@fpsp.fapesp.br 5-MAY-94 2.0 HP807/HPUX 9.00 4000 666 100 00:30:00 2 UFOP@fpsp.fapesp.br Notes: Crashme V1.0 {1000 20 200} used to down the SUN 4/110. V1.2 does *not* crash SUNOS 4.1.1 on the same arguments. Although using the extra argument for subprocesses it will crash, with the console reporting: "Bad Trap, Bad Kernel Read Fault, Bus error. Reboot" Script means invoking file with many calls to crashme such as this: #/bin/csh crashme 1020 234 500 & crashme 394 38484 5723 & crashme 3784 474 474 & crashme 437 4747 38 & crashme 47848 4745 123 & crashme 4747 4747 3463 & crashme 474 46464 262 & crashme 37 3644 3723 & crashme 374 46464 22 & crashme 3747 464 363 & crashme 347 4747 44 & crashme 37374 374 66 & crashme 3737 474 4444 & The 4-argument case of crashme could likely do as well as executing a script. */ #include #include #include #ifdef WIN32 #include #include #else #include #include #endif #include #ifdef VMS #include #endif #ifdef pyr #include #include #include #include #define strchr index #endif #ifdef linux #include #endif typedef void (*BADBOY)(); BADBOY badboy; long nbytes,nseed,ntrys; long incptr = 0; long offset = 0; long next_offset = 0; long malloc_flag = 0; unsigned char *the_data; char *note_buffer; char *notes; long verbose_level = 5; void old_main(),copyright_note(),vfork_main(),badboy_loop(); void record_note(); FILE *logfile = NULL; void record_note() {char *logfilename; if (!(logfilename = getenv("CRASHLOG"))) return; if (!(logfile = fopen(logfilename, (strncmp(note_buffer,"Subprocess",10) == 0) ? "a" : "w"))) {perror(logfilename); return;} if (note_buffer[strlen(note_buffer)-1] != '\n') strcat(note_buffer,"\n"); fputs(note_buffer,logfile); fclose(logfile); logfile = NULL;} void open_record() {char *logfilename; if (!(logfilename = getenv("CRASHLOG"))) return; if (!(logfile = fopen(logfilename,"a"))) {perror(logfilename); return;}} void close_record() {if (logfile) {fclose(logfile); logfile = NULL;}} void note(level) long level; {if (level > verbose_level) return; strcat(note_buffer,"\n"); fputs(note_buffer,stdout); if (logfile) fputs(note_buffer,logfile);} #ifndef WIN32 jmp_buf again_buff; #endif unsigned char *bad_malloc(n) long n; {unsigned char *data; data = (unsigned char *) malloc(n); #ifdef pyr if (mprotect(((int)data/PAGSIZ)*PAGSIZ, (n/PAGSIZ+1)*PAGSIZ, PROT_READ|PROT_WRITE|PROT_EXEC)) perror("mprotect"); #endif return(data);} #ifndef WIN32 void again_handler(sig) int sig; {char *ss; switch(sig) {case SIGILL: ss = " illegal instruction"; break; #ifdef SIGTRAP case SIGTRAP: ss = " trace trap"; break; #endif case SIGFPE: ss = " arithmetic exception"; break; #ifdef SIGBUS case SIGBUS: ss = " bus error"; break; #endif case SIGSEGV: ss = " segmentation violation"; break; #ifdef SIGIOT case SIGIOT: ss = " IOT instruction"; break; #endif #ifdef SIGEMT case SIGEMT: ss = " EMT instruction"; break; #endif #ifdef SIGALRM case SIGALRM: ss = " alarm clock"; break; #endif case SIGINT: ss = " interrupt"; break; default: ss = "";} sprintf(notes,"Got signal %d%s",sig,ss); note(5); longjmp(again_buff,3);} void my_signal(sig, func) int sig; void (*func)(); { #ifndef SA_ONESHOT signal(sig, func); #else struct sigaction act; act.sa_handler = func; act.sa_mask = 0; #ifdef linux act.sa_restorer = 0; #endif /* linux */ act.sa_flags = SA_NOMASK; #ifdef SA_RESTART act.sa_flags |= SA_RESTART; #endif sigaction(sig, &act, 0); #endif /* SA_ONESHOT */ } set_up_signals() {my_signal(SIGILL,again_handler); #ifdef SIGTRAP my_signal(SIGTRAP,again_handler); #endif my_signal(SIGFPE,again_handler); #ifdef SIGBUS my_signal(SIGBUS,again_handler); #endif my_signal(SIGSEGV,again_handler); #ifdef SIGIOT my_signal(SIGIOT,again_handler); #endif #ifdef SIGEMT my_signal(SIGEMT,again_handler); #endif #ifdef SIGALRM my_signal(SIGALRM,again_handler); #endif my_signal(SIGINT,again_handler);} #endif compute_badboy_1(n) long n; {long j; if (malloc_flag == 1) the_data = bad_malloc(n); for(j=0;j> 7) & 0xFF; if (nbytes < 0) {sprintf(notes,"Dump of %ld bytes of data",n); note(1); for(j=0;j #endif BADBOY castaway(dat) char *dat; { #if defined(VAX) && !defined(NOCASTAWAY) /* register save mask avoids bashing our callers locals */ ((unsigned short *)dat)[0] = 0x0FFC; #endif #if defined(__ALPHA) && defined(VMS) && !defined(NOCASTAWAY) struct pdscdef *p,*b; p = (struct pdscdef *) proto_badboy; b = (struct pdscdef *) dat; memcpy(b,p,sizeof(struct pdscdef)); b->pdsc$q_entry[1] = 0; b->pdsc$q_entry[0] = (int)&dat[sizeof(struct pdscdef)]; #endif #if (defined(_IBMR2) || defined(_POWER)) && !defined(NOCASTAWAY) struct fdesc {void *fcn_addr; void *toc; void *linkage;} *p,*b; p = (struct fdesc *) proto_badboy; b = (struct fdesc *) dat; memcpy(b,p,sizeof(struct fdesc)); b->fcn_addr = (void *) &dat[sizeof(struct fdesc)]; #endif #if defined(__hpux) && defined(__hppa) && !defined(NOCASTAWAY) struct fdesc {void *fcn_addr; void *toc;} *p,*b; p = (struct fdesc *) proto_badboy; b = (struct fdesc *) dat; memcpy(b,p,sizeof(struct fdesc)); b->fcn_addr = (void *) &dat[sizeof(struct fdesc)]; #endif return((BADBOY)dat);} compute_badboy() {long n; n = (nbytes < 0) ? - nbytes : nbytes; if (incptr == 0) {compute_badboy_1(n); badboy = castaway(the_data);} else if ((next_offset == 0) || (next_offset > ((n * 90) / 100))) {compute_badboy_1(n); offset = 0; next_offset = offset + incptr; badboy = castaway(the_data);} else {offset = next_offset; next_offset = offset + incptr; badboy = castaway(&the_data[offset]);}} /* maybe add this code before invoking badboy. But it didn't seem to be needed when using +1000. FlushInstructionCache(GetCurrentProcess(), the_data,(nbytes < 0) ? - nbytes : nbytes); */ try_one_crash() {if (nbytes > 0) (*badboy)(); else if (nbytes == 0) while(1);} char *subprocess_ind = "subprocess"; main(argc,argv) int argc; char **argv; {long nsubs,hrs,mns,scs,tflag,j,m; note_buffer = (char *) malloc(512); notes = note_buffer; if ((argc == 7) && (strcmp(argv[6],subprocess_ind) == 0)) {sprintf(note_buffer,"Subprocess %s: ",argv[4]); notes = note_buffer + strlen(note_buffer); verbose_level = atol(argv[5]); sprintf(notes,"starting"); note(3); old_main(4,argv);} else if (argc == 4) old_main(4,argv); else if ((argc == 6) && ((strlen(argv[4]) == 0) || (strcmp(argv[4],".") == 0))) {verbose_level = atol(argv[5]); old_main(4,argv);} else if ((argc == 5) || (argc == 6)) {if (argc == 6) verbose_level = atol(argv[5]); copyright_note(1); if (argc < 7) m = argc; else m = 6; strcpy(notes,"crashme"); for(j=1;j[.inc] [nsub] [verbose]"); note(0);}} void copyright_note(n) long n; {sprintf(notes,"Crashme: (c) Copyright 1990-1994 George J. Carrette"); note(n); sprintf(notes,"Version: %s",crashme_version); note(n);} void old_main(argc,argv) int argc; char **argv; {char *ptr; copyright_note(3); nbytes = atol(argv[1]); if (ptr = strchr(argv[1],'.')) incptr = atol(&ptr[1]); if (argv[1][0] == '+') malloc_flag = 1; nseed = atol(argv[2]); ntrys = atol(argv[3]); sprintf(notes,"crashme %s%ld.%d %ld %ld", (malloc_flag == 0) ? "" : "+",nbytes,incptr,nseed,ntrys); note(3); record_note(); if (malloc_flag == 0) {the_data = bad_malloc((nbytes < 0) ? -nbytes : nbytes); badboy = castaway(the_data); sprintf(notes,"Badboy at %d. 0x%X",badboy,badboy); note(3);} srand(nseed); #ifdef WIN32 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); #endif badboy_loop();} #ifdef WIN32 DWORD exception_filter(DWORD value) {int sev,cus,res,fac,cod; sev = 3 & (value >> 30); cus = 1 & (value >> 29); res = 1 & (value >> 28); fac = 07777 & (value >> 16); cod = 0xFFFF & value; sprintf(notes,"sev(%d)cus(%d)res(%d)fac(%d)code(%d)", sev,cus,res,fac,cod); note(5); return(EXCEPTION_EXECUTE_HANDLER);} #endif void badboy_loop() {int i; for(i=0;inext) if (n == l->status) return(++l->count); l = (struct status_list *) malloc(sizeof(struct status_list)); l->count = 1; l->status = n; l->next = slist; slist = l; return(1);} summarize_status() {struct status_list *l; sprintf(notes,"exit status ... number of cases"); note(2); for(l=slist;l != NULL; l = l->next) {sprintf(notes,"exit status ... number of cases"); sprintf(notes,"%11d ... %5d",l->status,l->count); note(2);}} #ifndef WIN32 long monitor_pid = 0; long monitor_period = 5; long monitor_limit = 6; /* 30 second limit on a subprocess */ long monitor_count = 0; long monitor_active = 0; void monitor_fcn(sig) int sig; {long status; my_signal(SIGALRM,monitor_fcn); alarm(monitor_period); if (monitor_active) {++monitor_count; if (monitor_count >= monitor_limit) {sprintf(notes,"time limit reached on pid %d 0x%X. using kill.", monitor_pid,monitor_pid); note(3); status = kill(monitor_pid,SIGKILL); if (status < 0) {sprintf(notes,"failed to kill process"); note(3);} monitor_active = 0;}}} void vfork_main(tflag,nsubs,cmd,nb,sr,nt) long tflag,nsubs,sr; char *cmd,*nb,*nt; {long j,pid,n,seq,total_time,dys,hrs,mns,scs; int status; char arg2[20],arg4[20],arg5[20]; time_t before_time,after_time; if (tflag == 1) {seq = 1; n = 100000000;} else if (nsubs < 0) {n = -nsubs; seq = 1;} else {n = nsubs; seq = 0;} if (seq == 1) {my_signal(SIGALRM,monitor_fcn); alarm(monitor_period);} time(&before_time); sprintf(arg5,"%d",verbose_level); for(j=0;j 0) {monitor_active = 0; sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status); note(3); record_status(status);}} if (tflag == 1) {time(&after_time); total_time = after_time - before_time; if (total_time >= nsubs) {sprintf(notes,"Time limit reached after run %d",j+1); note(2); break;}}}} if (seq == 0) while((pid = wait(&status)) > 0) {sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status); note(3); record_status(status);} time(&after_time); total_time = after_time - before_time; scs = total_time; mns = scs / 60; hrs = mns / 60; dys = hrs / 24; scs = scs % 60; mns = mns % 60; hrs = hrs % 24; open_record(); sprintf(notes, "Test complete, total real time: %d seconds (%d %02d:%02d:%02d)", total_time,dys,hrs,mns,scs); note(1); summarize_status(); close_record();} #else void chk_CloseHandle(HANDLE h) {DWORD err; if (CloseHandle(h) == FALSE) {err = GetLastError(); sprintf(notes,"err %d trying to close handle.",err); note(3);}} int maxticks = 100; /* tenths of a second before forced termination of the subprocess */ void vfork_main(tflag,nsubs,cmd,nb,sr,nt) long tflag,nsubs,sr; char *cmd,*nb,*nt; {long j,pid,n,seq,total_time,dys,hrs,mns,scs; char arg2[20],arg4[20],arg5[20]; time_t before_time,after_time; char cmdbuf[250]; int nticks; PROCESS_INFORMATION pinfo; STARTUPINFO sinfo; DWORD exit_code,err; if (tflag == 1) {seq = 1; n = 100000000;} else if (nsubs < 0) {n = -nsubs; seq = 1;} else {n = nsubs; seq = 0;} /* tflag says this is a timed run. So nsub is the time in seconds. seq says to run in sequence, not created nsub processes all at once. */ if (seq == 0) {printf("Not implemented. Use [-nsub] or [HH:MM:SS] instead.\n"); return;} time(&before_time); sprintf(arg5,"%d",verbose_level); for(j=0;j= nsubs) {sprintf(notes,"Time limit reached after run %d",j+1); note(2); break;}}} time(&after_time); total_time = after_time - before_time; scs = total_time; mns = scs / 60; hrs = mns / 60; dys = hrs / 24; scs = scs % 60; mns = mns % 60; hrs = hrs % 24; open_record(); sprintf(notes, "Test complete, total real time: %d seconds (%d %02d:%02d:%02d)", total_time,dys,hrs,mns,scs); note(1); summarize_status(); open_record();} #endif crashme-2.4.orig/crashme.html100644 1750 1750 30231 6266726303 16222 0ustar jkominekjkominek CRASHME: Random input testing.

CRASHME: Random input testing

Copyright © 1996 by George J. Carrette. All rights Reserved.

See the source crashme.c for reports of system crashes. Source code is available as a gunzip tar file, crashme.tgz or zip file crashme.zip or the old unix shar archive, crashme-2.4-shar.

Acknowledgements.

Many people have provided suggestions and comments and feedback. Some in private email and some as published on the comp.arch newsgroups. But as the author of this gross hack I take full responsibility for any errors in the information presented.


A bit of background on crashme. It is a tool for testing the robustness of an operating environment using a technique of "Random Input" response analysis. This I first saw formally proposed in the book Cybernetics by Norbert Wiener, but which any parent who has observed his children playing and learning would be well disposed to describe in detail. There is a wealth of information on the web containing references to Mr Weiner and his work, see for example www.ams.org or rleweb.mit.edu.

  • The operating environment under consideration is the user-mode process.
  • The Random Input is provided by the execution of a sequence of pseudo-random data as an instruction stream.
  • The response analysis is to catch and record machine and software generated exceptions/errors/signals and to retry using new random data in both the current user-mode process and in newly created subprocesses.

Notes for release 2.2 of Crashme. 9-MAY-1994 GJC@WORLD.STD.COM

Added the X.Y syntax for the NBYTES argument. This may run faster, doing more tests per second. A reasonable value for Y would be the number of bytes in a machine instruction.

Many people have suggested that the output of previous versions was far too verbose, and that that was not only annoying but also effectively slowing down the program. Therefore there is a new argument available after the subprocess control argument, which is a verboseness level from 0 to 5. Using a level of 2 will print out only summary information about the runs. e.g.


$ crashme +2000 666 50 00:30:00 2
Crashme: (c) Copyright 1990, 1991 George J. Carrette
Version: 1.7 25-SEP-1991
Subprocess run for 1800 seconds (0 00:30:00)
Test complete, total real time: 1801 seconds (0 00:30:01)
exit status ... number of cases
       1100 ...     2
    3522652 ...     4
       1036 ...     1
       1084 ...     7
       1108 ...    19
          1 ...   432
         12 ...   137

The table of exit status codes and frequencies is a new interesting aspect of the test. This test was run on a VMS system, so that we have a normal process exit 432 times, access violation 137 times, and reserved operand fault 19 times, etc. As the number of tries goes up (50 in this case) we would expect that the number of normal process exits to go down.

If you define an environment variable (or vms logical name) called CRASHLOG then each subprocess will append to a file the arguments it was given. In that way you can recover what instance possibly caused a crash, but remember that without frequent disk fsync operations most Unix systems will leave a CRASHLOG that is out of date by a few minutes or more.

Here is some output supplied by nik@infonode.ingr.com on one of his machines.


Processor : Intergraph Clipper C300 RISC processor
            16Mb memory + 4k I cache and 4K D cache

Operating System: CLIX Version c.5.3.2
                  derived from AT&T SVR 3.1 with BSD enhancements.

Crashme: (c) Copyright 1990, 1991 George J. Carrette
Version: 1.7 25-SEP-1991
Subprocess run for 9000 seconds (0 02:30:00)
Test complete, total real time: 9004 seconds (0 02:30:04)
exit status ... number of cases
        136 ...     1
      24576 ...     1
         14 ...     1
        138 ...    11
        135 ...    27
        140 ...    26
        132 ...   430
        139 ...    18
      12800 ...   567

The status values here could be decoded by reading the documentation for the "wait" system procedure, and looking up the correct part of the value in the sys_errlist[] array. That is left as an exersize for the reader.


To compile, some systems may need #include <sys/types.h>.

Also, note the conditionalized code in bad_malloc. If your system only gets the signal "segmentation violation" then you may need to consider conditionalizations along this line.

However, on a machine with a segmented address space, that has "instructions" in one segment and "data" in another, it is highly unlikely that the code for setting up and invoking the "void (*badboy)()" will have any interesting effect. Nothing other than an easily handled SIGSEGV will result in the inner testing loop.

Some PDP-11 systems would be examples of this situation (different I and D space).

---MACHINE O/S SPECIFIC NOTES---

MACHINE:: DEC C (OPENVMS ALPHA AXP):


$ CC/PREFIX=ALL/NOOPTIMIZE CRASHME
$ LINK CRASHME

New for version 2.2 code has been added to hackishly manipulate the Procedure Descriptor data format. It seems be executing random instructions like we would want.


#if defined(__ALPHA) && defined(VMS) && !defined(NOCASTAWAY)

Without this hack crashme on this platform has very little chance of causing anything other than a SIGBUS bus error.

Perhaps a smart "learning" mode of random-data creation could achieve the same ends, maximizing some measurement of punishment. Genetic programming might be useful.

Test I've tried:


$crashme +1000.48 0 100 03:00:00 2

MACHINE:: Windows NT:

The only files needed are crashme.c,makefile.wnt, and make.bat. cd into the directory containing the files and you can make two versions. crashme and crashmep (posix).


>make  

In WIN32 subsystem the subprocess-all-at-once mode has not been implemented, but the sequential (-nsub) and timed modes have been implemented.

In posix subsystem you must use the full name of the file in the command if you want to generate subprocesses.


>crashmep.exe .....
On an 486DX2-66 machine the following caused a totally wedged up machine in the Windows NT final release. (Build 511). This was built in WIN32 mode with debugging on.

>crashme +1000 666 50 12:00:00 3

In the posix subsystem the more verbose modes were not ever observed to go through more than 2 setjmp/longjmp cycles on a given random number seed. In the WIN32 subsystem there was a greater variety of fault conditions.

The above crash took place after about 6 hours of running. Final subprocess arguments were +1000 24131 50, and we verified twice that invoking the following crashed the OS within seconds.


>crashme +1000 24131 50

I have always been concerned that the more complex the unprotected data in the user address space the more likely it is for a program being developed to generate inscrutable errors that an "application developer" level of person will be unable to understand. And worse, will end up spinning wheels for large amounts of time, thereby delaying projects and risking deadline failures, and even worse, forcing management to bring in super-experienced (and limited availability) people into a project in order to get it going again.

The WINDOWS NT client-server model is one way around this problem. Having a subsystem in a different address space is one way to protect complex data manipulated through an API. However, as page 127 of "Inside Windows NT" there are some optimizations that make an unspoken trade-off between the robustness afforded by a protected seperate address space and efficiency of implementation on an API.

Robustness and 'scrutability of failure situations' vs efficiency.

MACHINE:: OS/2

It has been reported that this runs when compiled gcc crashme.c -o crashme.exe In order to disable the dialog boxes reporting abnormal process termination, add this to CONFIG.SYS: AUTOFAIL=YES. Or the following code to main:


DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);

Another person says that Emx is the only c compiler under OS/2 that supports fork.


Survey of Procedure Descriptor Usage. The emphasis here is on currently shipping products. The program pddet.c included with the distribution can be used to determine some of this information. Note that in some environments, e.g. Microsoft C++ 4.0 the results of PDDET will be different depending on the compilation modes chosen: debug verses release.


Architecture    |D| Desc | Env | Reg | Apos | Atyp | Rpos | Rtyp | 
------------------------------------------------------------------
VAX             |2| No   | No  | Yes | No   | No   | No   | No   |
ALPHA, OPENVMS  |3| Yes  | Yes | Yes | Yes  | Opt  | Yes  | Opt  |
ALPHA, WNT      | | No   |     |     |      |      |      |      |
ALPHA, OSF/1    | | No   |     |     |      |      |      |      |
RS/6000, AIX    |2| Yes  | Yes | No  | No   | No   | No   | No   |
PowerPC,        |2| Yes  | Yes | No  | No   | No   | No   | No   |
MIPS, Unix      | |      |     |     |      |      |      |      |
MIPS, WNT       | |      |     |     |      |      |      |      |
Intel, WNT      | |      |     |     |      |      |      |      |
Sparc, SUNOS    | | No   |     |     |      |      |      |      |
PA-RISC, HPUX   |2| Yes  |     |     |      |      |      |      |
------------------------------------------------------------------

Legend:

D    ... level of detailed information I have available
         1 = Verbal description or suspect from pddet.c
         2 = exact structure details including code for CRASHME.C
             or obvious what it is from pddet.c
         3 = crashme uses manufacturers include files for descriptors.
Desc ... Uses descriptors
Env  ... has pointer to non-static environment
Reg  ... describes registers used
Apos ... describes argument positions (stack, registers) or number.
Atyp ... describes argument types
Rpos ... describes return value position.
Rtyp ... describes return value types

Layout of Descriptors. Sizes in bytes.

ALPHA OPENVMS:

[FLAGS&KIND]       2
[REG-SAVE]         2
[REG-FOR-RETPC]    1
[REG-FOR-RETVAL]   1
[SIGNATURE-OFFSET] 2
[START-PC]         8
[Other stuff ...]  from 8 to 32 bytes worth.

AIX 

actually points to a 3 word struct with:
 - the actual function address
 - Table Of Contents (r2) register value
 - Environment (r11) pointer (for nested functions)

POWERPC

[PROGRAM-COUNTER]
[TABLE-OF-CONTENTS]
[EXCEPTION-INFO]

[Editorial comment taken from comp.arch:] Not to sound picky about this, but this is not really part of the POWER/PowerPC architecture. There is no special support for this in the hardware, it is just the scheme the software designers came up with in order to support shared libraries. Other schemes would be possible. [GJC comment] Pretty much true for every architecture.

PA-RISC HPUX.

The pddet.c program was used, and suggested descriptors of 8 bytes long. The -examine 8 argument showed what appeared to be a 4-byte starting PC followed by a table of contents. Note: If somebody knows what /usr/include/sys/*.h file to use for this, please let me know. crashme-2.4.orig/crashme.opt100644 1750 1750 124 6266714651 16021 0ustar jkominekjkominek! VMS LINKER OPTIONS FILE IDENTIFICATION = "CRASHME V1.8" SYS$LIBRARY:VAXCRTL/SHARE crashme-2.4.orig/crashme.txt100644 1750 1750 7502 6266726741 16070 0ustar jkominekjkominek CRASHME(1C) Communication Commands CRASHME(1C) NAME crashme - test operating environment software robustness SYNOPSIS crashme [NBYTES] [SRAND] [NTRYS] [NSUB] [VERBOSE] DESCRIPTION crashme is a very simple program that tests the operating environment's robustness by invoking random data as if it were a procedure. The standard signals are caught and han- dled with a setjmp back to a loop which will try again to produce a fault by executing random data. Some people call this stress testing. COMMAND LINE OPTIONS [NBYTES] The [NBYTES] should be an integer, specifying the size of the random data string in bytes. If given negative then the bytes are printed instead of being executed. If given with an explicit plus sign then the storage for the bytes is freshly malloc'ed each time. This can have an effect on machines with seperate I and D cache mechanisms. The argument can also have a dot in it, X.Y, in which case Y is a increment for a pointer into the random data. The buffer is recalculated only when the pointer gets near the end of the data. [SRAND] The [SRAND] is an input seed to the random number generator, passed to srand. [NTRIES] The [NTRIES] is how many times to loop before exit- ing normally from the program. [NSUB] The [NSUB] is optional, the number of vfork sub- processes running all at once. If negative run one after another. If given as a time hrs:mns:scs (hours, minutes, seconds) then one subprocess will be run to completion, followed by another, until the time limit has been reached. If this argument is given as the empty string or . then it is ignored. When in sequential-subprocess mode there is a 30 second time limit on each subprocess. This is to allow the instruction-set-space random walk to con- tinue when a process bashes itself into an infinite loop. For example, the ntrys can be bashed to a very large number with nbytes bashed to zero. (10 second limit on Windows NT). SunOS 5.5 Last change: LOCAL 1 CRASHME(1C) Communication Commands CRASHME(1C) The SRAND argument is incremented by one for each subprocess. [VERBOSE] The [VERBOSE] arg is optional. 0 is the least ver- bose, 5 the most. EXAMPLE This is a suggested test, to run it for a least an hour. crashme +2000 666 100 1:00:00 FILES crashme.c DIAGNOSTICS When a signal is caught the number and nature of the signal is indicated. Setting the environment variable CRASHLOG will cause each subprocess to record the arguments it was given. BUGS Not all signals are caught, and the state of the user program/process enviroment can be sufficiently damaged such that the program terminates before going through all [NTRIES] operations. If the architecture uses some kind of procedure descriptor but no special code has been not been added to castaway() in crashme.c then the stress test will not be as potent as it would otherwise be. Beware: This program can crash your computer if the operat- ing system or hardware of same is buggy. User data may be lost. AUTHOR George J Carrette. GJC@world.std.com VERSION 2.4 20-MAY-1994 SunOS 5.5 Last change: LOCAL 2 crashme-2.4.orig/descrip.mms100644 1750 1750 2442 6266714651 16047 0ustar jkominekjkominek! VMS MAKEFILE (for MMS) ! all depends_on crashme.exe pddet.exe !(ALL DONE) crashme.exe depends_on crashme.obj optarg = ",crashme.opt/opt" if f$getsyi("SID") .lt. 0 then optarg = "" link crashme.obj'optarg' ! re-execute the next line in your superior process: crashme == "$" + f$env("DEFAULT") + "CRASHME" crashme.obj depends_on crashme.c PF = "" if f$getsyi("SID") .lt. 0 then PF = "/PREFIX=ALL" CC/DEBUG/OPTIMIZE=(NOINLINE)'PF' CRASHME.C pddet.exe depends_on pddet.obj optarg = ",crashme.opt/opt" if f$getsyi("SID") .lt. 0 then optarg = "" link pddet.obj'optarg' ! re-execute the next line in your superior process: pddet == "$" + f$env("DEFAULT") + "PDDET" pddet.obj depends_on pddet.c PF = "" if f$getsyi("SID") .lt. 0 then PF = "/PREFIX=ALL" CC/DEBUG/OPTIMIZE=(NOINLINE)'PF' PDDET.C crashme_dbg.exe depends_on crashme.obj optarg = ",crashme.opt/opt" if f$getsyi("SID") .lt. 0 then optarg = "" link/debug/exe=crashme_dbg.exe crashme.obj'optarg' ! note: do not use continuation character here. DIST_FILES = crashme.1,crashme.c,makefile,descrip.mms,crashme.opt,read.me,shar.db,makefile.wnt,make.bat,pddet.c crashme.shar depends_on $(DIST_FILES) minishar crashme.shar shar.db crashme.1_of_1 depends_on $(DIST_FILES) define share_max_part_size 1000 vms_share $(DIST_FILES) crashme crashme-2.4.orig/make.bat100644 1750 1750 34 6266714652 15241 0ustar jkominekjkominekNMAKE /f MAKEFILE.WNT %1 %2 crashme-2.4.orig/makefile100644 1750 1750 1334 6266726730 15400 0ustar jkominekjkominekall: crashme pddet crashme: crashme.o cc -o crashme crashme.o crashme.o: crashme.c cc -c crashme.c pddet: pddet.o cc -o pddet pddet.o pddet.o: pddet.c cc -c pddet.c clean: -rm crashme pddet *.o core crashme.txt crashme.zip \ crashme.tgz # create for dist for people without nroff crashme.txt: crashme.1 nroff -man crashme.1 | col -bx > crashme.txt DIST_FILES = crashme.1 crashme.c crashme.html \ crashme.opt descrip.mms make.bat makefile \ makefile.wnt pddet.c crashme.txt crashme.zip: $(DIST_FILES) zip -k -l -u crashme.zip $(DIST_FILES) crashme.tgz: $(DIST_FILES) tar cvf - $(DIST_FILES) | gzip -v > crashme.tgz check: nsgmls -s crashme.html dist: crashme.zip crashme.tgz crashme-2.4.orig/makefile.wnt100644 1750 1750 1764 6266721023 16204 0ustar jkominekjkominek!include # Makefile for Crashme, under Microsoft Windows NT. # use the MAKE.BAT to invoke this if you want to use # the posix environment. # make posix # in order to define environment variables needed. # # NMAKE /f MAKEFILE.WNT # 9-SEP-93 George Carrette. GJC@WORLD.STD.COM all: crashme.exe crashmep.exe pddet.exe crashme.exe : crashme.obj $(link) $(ldebug) $(conflags) -out:crashme.exe crashme.obj $(conlibs) crashme.obj : crashme.c $(cc) $(cdebug) $(cflags) $(cvars) crashme.c -Focrashme.obj pddet.exe : pddet.obj $(link) $(ldebug) $(conflags) -out:pddet.exe pddet.obj $(conlibs) pddet.obj : pddet.c $(cc) $(cdebug) $(cflags) $(cvars) pddet.c -Fopddet.obj # call %mstools%\posix\setnvpsx %mstools% crashmep.exe : crashmep.obj set Lib=%%mstools%%\posix\lib;%%lib%% $(link) $(ldebug) $(psxflags) -out:crashmep.exe crashmep.obj $(psxlibs) crashmep.obj : crashme.c set Include=%%mstools%%\posix\h;%%include%% $(cc) $(cdebug) $(cflags) $(psxvars) crashme.c -Focrashmep.obj crashme-2.4.orig/pddet.c100644 1750 1750 33202 6266716333 15161 0ustar jkominekjkominek/* * COPYRIGHT (c) 1994 BY * * GEORGE J. CARRETTE, CONCORD, MASSACHUSETTS. * * ALL RIGHTS RESERVED * Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The purpose of this routine is to attempt to detect the use of procedure descriptors by making a note of how far apart the system allocates pointers to subroutines of different sizes. If all the subroutines are the same distance apart then procedure descriptors are probably in use on this architecture. This file should be compiled without any compiler optimization such as inlining that would confuse the test. Although base functions have been made somewhat complex in order to avoid that in any case. Now if a linker lays out procedures like this: [DESCRIPTOR][CODE TEXT...][DESCRIPTOR][CODE TEXT...] Then this code will be confused into thinking descriptors aren't used. But usually the hallmark of a descriptor architecture is that descriptors are in a table located away from the program code text. The -examine argument lets you see in a crude way what is contained in the pointer to a procedure data. 19-MAY-1994 GJC@WORLD.STD.COM */ #include #include #include struct v {long n;double *a;}; struct v *vcons(n,x) long n; double x; {struct v *p; long j; p = (struct v *) malloc(sizeof(struct v)); p->n = n; p->a = (double *) malloc(sizeof(double)*n); for(j=0;ja[j] = x; return(p);} struct v *vprod(x,y) struct v *x,*y; {struct v *z; long j; z = vcons(x->n); for(j=0;jn;++j) z->a[j] = x->a[j] * y->a[j]; return(z);} double vsume(x) struct v *x; {double sum = 0.0; long j; for(j=0;jn;++j) sum += x->a[j]; return(sum);} double viprod(x,y) struct v *x,*y; {return(vsume(vprod(x,y)));} double vnorm(x) struct v *x; {return(viprod(x,x));} double case10() {double acc = 0.0; acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0)); return(acc);} double case20() {double acc = 0.0; acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0)); return(acc);} double case30() {double acc = 0.0; acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(20,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(21,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(22,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(23,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(24,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(25,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(26,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(27,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(28,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(29,1.0)),2.0)); return(acc);} double case40() {double acc = 0.0; acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(20,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(21,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(22,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(23,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(24,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(25,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(26,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(27,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(28,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(29,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(30,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(31,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(32,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(33,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(34,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(35,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(36,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(37,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(38,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(39,1.0)),2.0)); return(acc);} double case50() {double acc = 0.0; acc += vnorm(vcons((long)vsume(vcons(0,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(1,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(2,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(3,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(4,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(5,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(6,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(7,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(8,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(9,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(10,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(11,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(12,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(13,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(14,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(15,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(16,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(17,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(18,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(19,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(20,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(21,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(22,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(23,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(24,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(25,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(26,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(27,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(28,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(29,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(30,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(31,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(32,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(33,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(34,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(35,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(36,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(37,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(38,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(39,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(40,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(41,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(42,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(43,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(44,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(45,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(46,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(47,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(48,1.0)),2.0)); acc += vnorm(vcons((long)vsume(vcons(49,1.0)),2.0)); return(acc);} void sayarch(x) char *x; {printf("This architecture %s procedure descriptors\n",x);} struct apair {char *name;unsigned long addr;}; struct adelt {long delta; long count;}; int apairl(a,b) struct apair *a,*b; {if (a->addr < b->addr) return(-1); else if (a->addr > b->addr) return(1); else return(0);} int adeltl(a,b) struct adelt *a,*b; {if (a->delta < b->delta) return(-1); else if (a->delta > b->delta) return(1); else return(0);} main(argc,argv) int argc; char **argv; {struct apair all[10]; struct adelt deltas[10]; long j,k,n=10,min_delta,max_delta,delta,d,ebytes=0; unsigned char *data,*prev_data; for(j=1;(j+1) 0) {printf("%10s %10s %s\n","procedure","address","examine"); for(j=0;j 0) prev_data = (unsigned char *) all[j-1].addr; else prev_data = NULL; for(k=0;k0) {delta = all[j].addr - all[j-1].addr; if (j == 1) min_delta = max_delta = delta; else {if (delta < min_delta) min_delta = delta; if (delta > max_delta) max_delta = delta;} for(k=0;k 0) {printf("%10d %d\n",deltas[k].delta,deltas[k].count); ++d;} if (d > 4) sayarch("probably does not use"); else sayarch("may be using");}}