home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 August - Disc 3
/
chip_20018103_hu.iso
/
amiga
/
chiputil
/
wipeout.lha
/
source
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-02-06
|
19KB
|
857 lines
/*
* $Id: main.c 1.21 2000/12/18 16:23:37 olsen Exp olsen $
*
* :ts=4
*
* Wipeout -- Traces and munges memory and detects memory trashing
*
* Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
* Public Domain
*/
#ifndef _GLOBAL_H
#include "global.h"
#endif /* _GLOBAL_H */
/******************************************************************************/
#include "Wipeout_rev.h"
/******************************************************************************/
const STRPTR VersTag = VERSTAG;
/******************************************************************************/
STATIC const STRPTR Separator = "======================================="
"=======================================";
/******************************************************************************/
STATIC struct WipeoutSemaphore * WipeoutSemaphore;
STATIC BOOL WipeoutSemaphoreCreated;
/******************************************************************************/
STATIC BOOL ShowBannerMessage = TRUE;
/******************************************************************************/
STATIC BYTE TimerSignal;
/******************************************************************************/
STATIC LONG ASM
ControlFunc(REG(a0) struct TagItem *tags)
{
struct TagItem * list = tags;
struct TagItem * ti;
struct TrackHeader * th;
APTR address = NULL;
LONG result = 0;
Forbid();
while((ti = NextTagItem(&list)) != NULL)
{
switch(ti->ti_Tag)
{
case WOT_Address:
address = (APTR)ti->ti_Data;
break;
case WOT_SetPC:
if(IsTrackedAllocation((ULONG)address,&th) ||
IsTrackedAllocation((ULONG)(address)-sizeof(LONG),&th))
{
th->th_PC = ti->ti_Data;
th->th_ShowPC = TRUE;
FixTrackHeaderChecksum(th);
}
break;
}
}
Permit();
return(result);
}
/******************************************************************************/
STATIC struct WipeoutSemaphore *
FindWipeoutSemaphore(VOID)
{
struct WipeoutSemaphore * ws;
ws = (struct WipeoutSemaphore *)FindSemaphore(WIPEOUTSEMAPHORENAME);
return(ws);
}
STATIC VOID
DeleteWipeoutSemaphore(struct WipeoutSemaphore * ws)
{
if(ws != NULL)
{
/* remove the semaphore from the public list */
RemSemaphore((struct SignalSemaphore *)ws);
/* gain ownership over it */
ObtainSemaphore((struct SignalSemaphore *)ws);
ReleaseSemaphore((struct SignalSemaphore *)ws);
/* and release it */
FreeMem(ws,sizeof(*ws));
}
}
STATIC struct WipeoutSemaphore *
CreateWipeoutSemaphore(VOID)
{
struct WipeoutSemaphore * ws;
ws = AllocMem(sizeof(*ws),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
if(ws != NULL)
{
/* fill in name and priority; AddSemaphore() will take
* care of the rest
*/
ws->ws_SignalSemaphore.ss_Link.ln_Name = ws->ws_SemaphoreName;
ws->ws_SignalSemaphore.ss_Link.ln_Pri = 1;
strcpy(ws->ws_SemaphoreName,WIPEOUTSEMAPHORENAME);
/* for compatibility checking, if the semaphore
* needs to grow
*/
ws->ws_Version = WIPEOUTSEMAPHOREVERSION;
ws->ws_Revision = WIPEOUTSEMAPHOREREVISION;
/* fill in references to changeable parameters */
ws->ws_IsActive = &IsActive;
ws->ws_ShowFail = &ShowFail;
ws->ws_WaitAfterHit = &WaitAfterHit;
ws->ws_NameTag = &NameTag;
ws->ws_NameTag = &NameTag;
ws->ws_CheckConsistency = &CheckConsistency;
ws->ws_ARegCheck = &ARegCheck;
ws->ws_DRegCheck = &DRegCheck;
ws->ws_StackCheck = &StackCheck;
ws->ws_StackLines = &StackLines;
ws->ws_CheckDelay = &CheckDelay;
ws->ws_WipeoutTask = FindTask(NULL);
ws->ws_WakeupMask = (1UL << WakeupSignal);
ws->ws_ControlFunc = (WipeoutControlFunc)ControlFunc;
/* and finally make the semaphore public */
AddSemaphore((struct SignalSemaphore *)ws);
}
return(ws);
}
/******************************************************************************/
STATIC LONG
SendWipeoutCmd(LONG command,APTR parameter)
{
WipeoutSemaphore->ws_Client = FindTask(NULL);
WipeoutSemaphore->ws_Command = command;
WipeoutSemaphore->ws_Parameter = parameter;
WipeoutSemaphore->ws_Error = OK;
/* wake up the wipeout semaphore owner and exchange
* data or information with it
*/
SetSignal(0,SIG_Handshake);
Signal(WipeoutSemaphore->ws_WipeoutTask,WipeoutSemaphore->ws_WakeupMask);
Wait(SIG_Handshake);
return(WipeoutSemaphore->ws_Error);
}
/******************************************************************************/
STATIC VOID
Cleanup(VOID)
{
/* shut down the timer */
DeleteTimer();
/* dispose of the semaphore */
if(WipeoutSemaphoreCreated)
{
DeleteWipeoutSemaphore(WipeoutSemaphore);
WipeoutSemaphore = NULL;
}
/* release the semaphore */
if(WipeoutSemaphore != NULL)
{
ReleaseSemaphore((struct SignalSemaphore *)WipeoutSemaphore);
WipeoutSemaphore = NULL;
}
/* clear the allocation filters */
ClearFilterList();
/* get rid of the wakeup signal */
if(WakeupSignal != -1)
{
FreeSignal(WakeupSignal);
WakeupSignal = -1;
}
/* close utility.library, if this is necessary */
#if !defined(__SASC) || defined(_M68020)
{
if(UtilityBase != NULL)
{
CloseLibrary(UtilityBase);
UtilityBase = NULL;
}
}
#endif
}
STATIC BOOL
Setup(VOID)
{
LONG error = OK;
int i;
WakeupSignal = -1;
InitFilterList();
/* Kickstart 2.04 or higher required */
if(SysBase->LibNode.lib_Version < 37)
{
const STRPTR message = "This program requires Kickstart 2.04 or better.\n";
Write(Output(),message,strlen(message));
return(FAILURE);
}
/* determine the program name */
StrcpyN(sizeof(ProgramName),ProgramName,VERS);
for(i = strlen(ProgramName) - 1 ; i >= 0 ; i--)
{
if(ProgramName[i] == ' ')
{
ProgramName[i] = '\0';
break;
}
}
/* open utility.library, if this is necessary */
#if !defined(__SASC) || defined(_M68020)
{
UtilityBase = OpenLibrary("utility.library",37);
if(UtilityBase == NULL)
{
Printf("%s: Could not open utility.library V37.\n",ProgramName);
return(FAILURE);
}
}
#endif
/* allocate the timer data */
TimerSignal = CreateTimer();
if(TimerSignal == -1)
{
Printf("%s: Could not create timer.\n",ProgramName);
return(FAILURE);
}
/* allocate the wakeup signal */
WakeupSignal = AllocSignal(-1);
if(WakeupSignal == -1)
{
Printf("%s: Could not allocate wakeup signal.\n",ProgramName);
return(FAILURE);
}
/* establish default options */
PreWallSize = 32;
PostWallSize = 32;
IsActive = TRUE;
StackLines = 2;
Forbid();
/* try to find the global wipeout semaphore */
WipeoutSemaphore = FindWipeoutSemaphore();
if(WipeoutSemaphore == NULL)
{
/* it does not exist yet; create it */
WipeoutSemaphore = CreateWipeoutSemaphore();
if(WipeoutSemaphore != NULL)
{
WipeoutSemaphoreCreated = TRUE;
}
else
{
error = ERROR_NO_FREE_STORE;
}
}
else if (WipeoutSemaphore->ws_Version != WIPEOUTSEMAPHOREVERSION)
{
error = ERROR_OBJECT_WRONG_TYPE;
}
else
{
/* obtain ownership of the semaphore */
ObtainSemaphore((struct SignalSemaphore *)WipeoutSemaphore);
}
Permit();
if(error == OK)
{
struct RDArgs * rda;
/* these are the command line parameters, later
* filled in by ReadArgs() below
*/
struct
{
/* the following options control the startup defaults
* and cannot be changed by subsequent invocations
* of Wipeout
*/
NUMBER PreSize;
NUMBER PostSize;
KEY FillChar;
SWITCH Parallel;
SWITCH NoBanner;
/* the following options can be changed at run-time */
SWITCH Remunge;
SWITCH Check;
SWITCH Mark;
SWITCH Unmark;
SWITCH ShowUnmarked;
KEY Name;
SWITCH NameTag;
SWITCH NoNameTag;
SWITCH Active;
SWITCH Inactive;
SWITCH Wait;
SWITCH NoWait;
SWITCH ConsistenceCheck;
SWITCH NoConsistenceCheck;
SWITCH Reuse;
SWITCH NoReuse;
SWITCH ShowFail;
SWITCH NoShowFail;
SWITCH ARegCheck;
SWITCH NoARegCheck;
SWITCH DRegCheck;
SWITCH NoDRegCheck;
SWITCH StackCheck;
SWITCH NoStackCheck;
NUMBER StackLines;
NUMBER CheckDelay;
} params;
/* this is the command template, as required by ReadArgs() below;
* its contents must match the "params" data structure above
*/
const STRPTR cmdTemplate =
"PRESIZE/K/N,"
"POSTSIZE/K/N,"
"FILLCHAR/K,"
"PARALLEL/S,"
"QUIET=NOBANNER/S,"
"REMUNGE=REMUNG/S,"
"CHECK/S,"
"MARK/S,"
"UNMARK/S,"
"SHOWUNMARKED/S,"
"NAME=TASK/K,"
"NAMETAG/S,"
"NONAMETAG/S,"
"ACTIVE=ENABLE/S,"
"INACTIVE=DISABLE/S,"
"WAIT/S,"
"NOWAIT/S,"
"CONSISTENCECHECK/S,"
"NOCONSISTENCECHECK/S,"
"REUSE/S,"
"NOREUSE/S,"
"SHOWFAIL/S,"
"NOSHOWFAIL/S,"
"AREGCHECK/S,"
"NOAREGCHECK/S,"
"DREGCHECK/S,"
"NODREGCHECK/S,"
"STACKCHECK/S,"
"NOSTACKCHECK/S,"
"STACKLINES/K/N,"
"CHECKDELAY/K/N";
memset(¶ms,0,sizeof(params));
/* read the command line parameters */
rda = ReadArgs((STRPTR)cmdTemplate,(LONG *)¶ms,NULL);
if(rda != NULL)
{
struct WipeoutSemaphore * ws = WipeoutSemaphore;
/* set the pre-wall allocation size */
if(params.PreSize != NULL)
{
LONG value;
value = (*params.PreSize);
if(value < MEM_BLOCKSIZE)
value = MEM_BLOCKSIZE;
else if (value > 65536)
value = 65536;
PreWallSize = (value + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
}
/* set the post-wall allocation size */
if(params.PostSize != NULL)
{
LONG value;
value = (*params.PostSize);
if(value < MEM_BLOCKSIZE)
value = MEM_BLOCKSIZE;
else if (value > 65536)
value = 65536;
PostWallSize = (value + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
}
/* use a special fill character? */
if(params.FillChar != NULL)
{
LONG number;
/* this can either be a decimal or a
* hexadecimal number; the latter is
* indicated by a preceding "$" or "0x"
*/
if(DecodeNumber(params.FillChar,&number))
{
if(0 <= number && number <= 255)
SetFillChar(number);
else
error = ERROR_BAD_NUMBER;
}
else
{
error = ERROR_BAD_NUMBER;
}
}
/* enable parallel port output? */
if(params.Parallel)
ChooseParallelOutput();
/* do not show the banner message? */
if(params.NoBanner)
ShowBannerMessage = FALSE;
/* remunge memory? */
if(params.Remunge)
{
/* tell the semaphore owner to munge the memory */
if(NO WipeoutSemaphoreCreated)
SendWipeoutCmd(WIPEOUTCMD_Remunge,NULL);
}
/* trigger a memory check? */
if(params.Check)
Signal(ws->ws_WipeoutTask,SIG_Check);
/* mark all allocations? */
if(params.Mark)
{
/* tell the semaphore owner to mark the allocations */
if(NO WipeoutSemaphoreCreated)
SendWipeoutCmd(WIPEOUTCMD_Mark,NULL);
}
/* clear all allocation marks? */
if(params.Unmark)
{
/* tell the semaphore owner to clear the marks */
if(NO WipeoutSemaphoreCreated)
SendWipeoutCmd(WIPEOUTCMD_Unmark,NULL);
}
/* show all unmarked allocations? */
if(params.ShowUnmarked)
{
/* tell the semaphore owner to clear the marks */
if(NO WipeoutSemaphoreCreated)
SendWipeoutCmd(WIPEOUTCMD_ShowUnmarked,NULL);
}
/* put together a list of tasks to filter out
* when making memory allocations?
*/
if(params.Name != NULL)
{
if(WipeoutSemaphoreCreated)
{
/* we created the semaphore, so we can
* fill in the filter lists all by
* ourselves.
*/
if(CANNOT UpdateFilter(params.Name))
error = ERROR_NO_FREE_STORE;
}
else
{
/* we did not create the semaphore,
* so we will have to tell the semaphore
* owner to update the filter lists.
*/
error = SendWipeoutCmd(WIPEOUTCMD_UpdateFilterList,params.Name);
}
}
if(params.NameTag)
(*ws->ws_NameTag) = TRUE;
if(params.NoNameTag)
(*ws->ws_NameTag) = FALSE;
/* enable wipeout? */
if(params.Active)
Signal(ws->ws_WipeoutTask,SIG_Enable);
/* disable wipeout? */
if(params.Inactive)
Signal(ws->ws_WipeoutTask,SIG_Disable);
if(params.Wait)
(*ws->ws_WaitAfterHit) = TRUE;
if(params.NoWait)
(*ws->ws_WaitAfterHit) = FALSE;
if(params.ConsistenceCheck)
(*ws->ws_CheckConsistency) = TRUE;
if(params.NoConsistenceCheck)
(*ws->ws_CheckConsistency) = FALSE;
if(params.Reuse)
(*ws->ws_NoReuse) = FALSE;
if(params.NoReuse)
(*ws->ws_NoReuse) = TRUE;
if(params.ShowFail)
(*ws->ws_ShowFail) = TRUE;
if(params.NoShowFail)
(*ws->ws_ShowFail) = FALSE;
if(params.ARegCheck)
(*ws->ws_ARegCheck) = TRUE;
if(params.NoARegCheck)
(*ws->ws_ARegCheck) = FALSE;
if(params.DRegCheck)
(*ws->ws_DRegCheck) = TRUE;
if(params.NoDRegCheck)
(*ws->ws_DRegCheck) = FALSE;
if(params.StackCheck)
(*ws->ws_StackCheck) = TRUE;
if(params.NoStackCheck)
(*ws->ws_StackCheck) = FALSE;
if(params.StackLines != NULL)
{
LONG value;
value = (*params.StackLines);
if(value < 0)
value = 0;
(*ws->ws_StackLines) = value;
}
/* set or update the automatic check delay? */
if(params.CheckDelay != NULL)
{
LONG value;
value = (*params.CheckDelay);
if(value < 0)
value = 0;
CheckDelay = value;
/* notify the semaphore owner of the
* new check delay; this will automatically
* trigger a new memory check
*/
if(NO WipeoutSemaphoreCreated)
error = SendWipeoutCmd(WIPEOUTCMD_NewCheckDelay,(APTR)CheckDelay);
}
FreeArgs(rda);
}
else
{
error = IoErr();
}
}
if(error == OK)
{
/* set up the tracking lists */
SetupAllocationList();
SetupPoolList();
return(SUCCESS);
}
else
{
if(error == ERROR_OBJECT_WRONG_TYPE)
Printf("%s: Global semaphore version mismatch; please reinstall 'Wipeout' and reboot.\n",ProgramName);
else
PrintFault(error,ProgramName);
return(FAILURE);
}
}
/******************************************************************************/
int
main(
int argc,
char ** argv)
{
int result = RETURN_FAIL;
/* set up all the data we need */
if(Setup())
{
result = RETURN_OK;
/* are we the owner of the semaphore? if
* so, do something useful
*/
if(WipeoutSemaphoreCreated)
{
ULONG signalsReceived;
ULONG sigWakeup = (1UL<<WakeupSignal);
ULONG sigTimer = (1UL<<TimerSignal);
/* munge all free memory */
if(ShowBannerMessage)
{
DPrintf("%s -- Traces and munges memory and detects memory trashing\n",ProgramName);
DPrintf("Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>\n");
DPrintf("Public Domain\n\n");
DPrintf("Munging memory... ");
}
BeginMemMung();
if(ShowBannerMessage)
{
struct timeval tv;
Forbid();
GetSysTime(&tv);
ConvertTimeAndDate(&tv,GlobalDateTimeBuffer);
DPrintf("done (%s).\n",GlobalDateTimeBuffer);
Permit();
}
/* plant the monitoring patches */
InstallPatches();
/* if we are to check the memory list periodically,
* start the timer now
*/
if(CheckDelay > 0)
StartTimer(CheckDelay / 10,(CheckDelay % 10) * (MILLION / 10));
while(TRUE)
{
/* wait for something to happen */
signalsReceived = Wait(SIG_Check | SIG_Disable | SIG_Enable | sigWakeup | sigTimer);
/* received a command? */
if(FLAG_IS_SET(signalsReceived,sigWakeup))
{
APTR parameter = WipeoutSemaphore->ws_Parameter;
LONG error = OK;
/* what are we to do now? */
switch(WipeoutSemaphore->ws_Command)
{
/* update the filter list? */
case WIPEOUTCMD_UpdateFilterList:
if(CANNOT UpdateFilter((STRPTR)parameter))
error = ERROR_NO_FREE_STORE;
break;
/* change the check timer delay? */
case WIPEOUTCMD_NewCheckDelay:
CheckDelay = (LONG)parameter;
/* re-check the check timer delay */
signalsReceived |= sigTimer;
break;
/* remunge unallocated memory? */
case WIPEOUTCMD_Remunge:
DPrintf("Remunging memory... ");
BeginMemMung();
DPrintf("done.\n");
break;
/* mark all "current" memory allocations? */
case WIPEOUTCMD_Mark:
DPrintf("Marking memory... ");
ChangeMemoryMarks(TRUE);
ChangePuddleMarks(TRUE);
DPrintf("done.\n");
break;
/* clear all memory marks? */
case WIPEOUTCMD_Unmark:
DPrintf("Clearing memory marks... ");
ChangeMemoryMarks(FALSE);
ChangePuddleMarks(FALSE);
DPrintf("done.\n");
break;
/* show all memory marks? */
case WIPEOUTCMD_ShowUnmarked:
DPrintf("%s\nShowing all unmarked memory allocations\n",Separator);
ShowUnmarkedMemory();
ShowUnmarkedPools();
DPrintf("%s\n\n",Separator);
break;
}
/* let the client task go */
WipeoutSemaphore->ws_Error = error;
Signal(WipeoutSemaphore->ws_Client,SIG_Handshake);
}
/* start or stop the timer, depending on the
* check delay length
*/
if(FLAG_IS_SET(signalsReceived,sigTimer))
{
if(CheckDelay > 0)
{
StartTimer(CheckDelay / 10,(CheckDelay % 10) * (MILLION / 10));
signalsReceived |= SIG_Check;
}
else
{
StopTimer();
}
}
/* check all memory allocations */
if(FLAG_IS_SET(signalsReceived,SIG_Check))
{
struct timeval tv;
Forbid();
GetSysTime(&tv);
ConvertTimeAndDate(&tv,GlobalDateTimeBuffer);
DPrintf("%s\nChecking all memory allocations (%s)\n%s\n",
Separator,GlobalDateTimeBuffer,Separator);
CheckAllocatedMemory();
CheckPools();
CheckFilter();
DPrintf("%s\n\n",Separator);
Permit();
}
/* stop monitoring memory allocations */
if(FLAG_IS_SET(signalsReceived,SIG_Disable))
{
if(IsActive)
{
struct timeval tv;
Forbid();
GetSysTime(&tv);
ConvertTimeAndDate(&tv,GlobalDateTimeBuffer);
DPrintf("%s\n%s deactivated (%s)\n%s\n",
Separator,ProgramName,GlobalDateTimeBuffer,Separator);
IsActive = FALSE;
Permit();
}
}
/* restart monitoring memory allocations */
if(FLAG_IS_SET(signalsReceived,SIG_Enable))
{
if(NOT IsActive)
{
struct timeval tv;
Forbid();
GetSysTime(&tv);
ConvertTimeAndDate(&tv,GlobalDateTimeBuffer);
DPrintf("%s\n%s activated (%s)\n%s\n",
Separator,ProgramName,GlobalDateTimeBuffer,Separator);
IsActive = TRUE;
Permit();
}
}
}
}
}
/* note that we never arrive here if we are the owner
* of the wipeout semaphore
*/
Cleanup();
return(result);
}