/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* |_o_o|\\ Copyright (c) 1986 The Software Distillery. All Rights Reserved */ /* |. o.| || This program may not be distributed without the permission of */ /* | . | || the authors. BBS: */ /* | o | || Dave Baker Ed Burnette Stan Chow (919)-471-6436 */ /* | . |// Jay Denebeim Gordon Keener Jack Rouse Voice: */ /* ====== John Toebes Mary Ellen Toebes Doug Walker (919)-469-4210 */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This program watches the first 0x100 bytes of memory for random trashing, */ /* attempts repair of the damage and then puts up an alert indicating the */ /* damage that was done. Many thanks to EA for suggesting this program at */ /* the developer's conference. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * INCLUDE FILES * * * * * * * * * * * */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* * * * * * * * * * * STRUCTURES * * * * * * * * * * * * */ typedef struct stomped { long data; /* value that was thrown into address wildly */ long address; /* address that was changed */ } STOMPED; /* * * * * * * * * * * CONSTANTS * * * * * * * * * * * * */ #define TIMEINTERVAL 2500L /* in micro seconds */ #define LOWLIMIT 20L /* smallest safe interval */ #define BANNER "\x9B0;33mMemWatch\x9B0m by John Toebes - Copyright © 1986 The Software Distillery\n 235 Trillingham Ln, Cary NC 27511 BBS:(919)-471-6436\n" #define BANNER1 "Usage: \x9B1mRUN MemWatch\x9B0m [n]\nWhere n is the optional interval between watch checks (Default 2500ms)\n" /* * * * * * * * * * * EXTERNAL ROUTINES * * * * * * * * * */ struct IntuitionBase *IntuitionBase = NULL; extern APTR AllocMem(long, long); /* ok so I lied about these tasks - it is true as long as we are working with */ /* DOS processes */ extern struct Process *FindTask(char *); extern void SetTaskPri(struct Process *, long); extern long OpenDevice(char *, long, struct IORequest*, long); extern void SaveMem(); extern int ValidateMem(struct stomped *); int DOSBase; /* * * * * * * * * * * Alert definition structure* * * * * * * * * */ /* we want to display the message: */ /* Someone stepped on Low memory $nnnnnnnn with $nnnnnnnn cccc! */ /* Press either Mouse button to continue */ /* 345678901234567890123456789012345678901234567890123456789012 */ /* 11111111112222222222333333333344444444445555555555666 */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define ALERTHEIGHT 25 /* height of alert in pixals */ #define ADDR_OFF 34 /* location of address substitution */ #define DATA_OFF 49 /* Location of data val substitution */ #define CHAR_OFF 58 /* Location of data text substitution */ static char AlertString[] = { 0, 84, /* 2 byte x absolute offset of first string */ 10, /* 1 byte y absolute offset of first string */ 'S', 'o', 'm', 'e', 'o', 'n', 'e', ' ', /* first message string */ 'S', 't', 'e', 'p', 'p', 'e', 'd', ' ', 'o', 'n', ' ', 'L', 'o', 'w', ' ', 'm', 'e', 'm', 'o', 'r', 'y', ' ', '$', 'h', 'h', 'h', 'h', 'h', 'h', 'h', 'h', ' ', /* address we substitute */ 'w', 'i', 't', 'h', ' ', '$', 'h', 'h', 'h', 'h', 'h', 'h', 'h', 'h', ' ', /* data we substitute */ 'c', 'c', 'c', 'c', '!', /* chars we substitute */ 0, /* null terminator on string */ 1, /* flag to indicate another alert string */ 0, 164, /* 2 byte x absolute offset of second string */ 18, /* 1 byte y absolute offset of second string */ 'P', 'r', 'e', 's', 's', ' ', /* second message string */ 'e', 'i', 't', 'h', 'e', 'r', ' ', 'M', 'o', 'u', 's', 'e', ' ', 'B', 'u', 't', 't', 'o', 'n', ' ', 't', 'o', ' ', 'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', 0, /* null terminator on string */ 0 }; /* flag to indicate no more strings */ /************************************************************************/ /* The main program to watch the memory */ /************************************************************************/ void _main(cmd) char *cmd; { register struct timerequest *timerreq = NULL; /* request structure for timer waits*/ struct stomped rslt; /* information on memory stomps */ register int i; /* general index variable */ register long v; /* temporary for formatting display */ register long interval = TIMEINTERVAL; /* how long to wait between checks */ register char *p; /* display formatting index */ /* NOTE: The declarations for i anv v MUST come before that of interval */ /* because DOIO trashes D6 and D7 which are the first ones selected for */ /* register variables. It doesn't matter if i and v are trashed but */ /* interval MUST be maintained across the lifetime of the loop */ /* if we were run from CLI then output our banner and process parameters */ if (cmd) { /* get our default output device */ v = Output(); /* display our copyright */ Write(v, BANNER, sizeof(BANNER)); /* skip over any leading spaces in the command line */ while(*cmd == ' ') cmd++; /* now see if they gave us a number to control the interval of checking */ interval = 0; while ((*cmd >= '0') && (*cmd <= '9')) interval = ((short)interval*(short)10) + *cmd++ - '0'; /* if they gave us nothing (or something we didn't parse well */ /* such as a VERY large number or just plain trash, give them a */ /* short usage message for the program */ if (interval <= 0) Write(v, BANNER1, sizeof(BANNER1)); /* now do the magic that allows the window to be closed */ if (v != Input()) Close(Input()); Close(v); /* just incase we got a very low number (or a 0) from the command line */ /* apply a minimum rule to keep from killing the system performance */ /* note that since tasks switch at about every 20mili seconds or so */ /* (not sure where that information is from) making it less than 20000 */ /* really isn't much of a gain (but it sure feels nice) */ if (interval < LOWLIMIT) interval = LOWLIMIT; } /* now we are ready to go - push up our priority with the best of them */ SetTaskPri( FindTask(NULL), 20); /* open up intuition - we only use this for the alert but we must do it */ /* anyway */ if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0)) == NULL) goto abort; /* create a request structure to send the messages with */ if ((timerreq = (struct timerequest *) AllocMem(sizeof(struct timerequest), MEMF_CLEAR | MEMF_PUBLIC)) == NULL) goto abort; /* fill in the struture with what we are dealing with */ timerreq->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE; timerreq->tr_node.io_Message.mn_Node.ln_Pri = 0; timerreq->tr_node.io_Message.mn_ReplyPort = &(FindTask(NULL)->pr_MsgPort); /* and open us a timer. Note that we are using VBLANK since it is the */ /* lowest system overhead. We are not critical on the timing and only */ /* want to run as often as possible without killing the system */ if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest*)timerreq, 0)) goto abort; /* let our assembler stub squirel away a copy of the low memory */ SaveMem(); /* go until they hit us with a ^C - kind of a simple way to stop it */ while(!(SetSignal(0,0) & SIGBREAKF_CTRL_C)) { /* Use the timer to wait our required number of seconds */ timerreq->tr_node.io_Command = TR_ADDREQUEST; timerreq->tr_time.tv_secs = 0; /* seconds */ timerreq->tr_time.tv_micro = interval; /* micro seconds */ DoIO(timerreq); /* Now have our buddy check and fix any memory */ /* if something was wrong, he will tell us about it */ if (ValidateMem(&rslt)) { /* format the failure data to be displayed */ *(long *)(&AlertString[CHAR_OFF]) = rslt.data; /* replace any nulls so they don't screw up the message */ for (i=CHAR_OFF; i= 0; i--) { *p-- = "0123456789ABCDEF"[v&15]; v >>= 4; } /* format the data value for them */ p = &AlertString[DATA_OFF+7]; v = rslt.data; for (i = 7; i>= 0; i--) { *p-- = "0123456789ABCDEF"[v&15]; v >>= 4; } /* put up a requester to indicate it failed */ DisplayAlert(0xBADC0DE, AlertString, ALERTHEIGHT); } } CloseDevice(timerreq); abort: if (timerreq != NULL) FreeMem (timerreq, sizeof(struct timerequest)); if (IntuitionBase != NULL) CloseLibrary(IntuitionBase); XCEXIT(-1); }