home *** CD-ROM | disk | FTP | other *** search
Wrap
/* * $Id: monitoring.c 1.3 1998/04/13 09:59:42 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 "installpatches.h" /******************************************************************************/ STATIC VOID WaitForBreak(VOID) { STRPTR taskTypeName; taskTypeName = GetTaskTypeName(GetTaskType(NULL)); /* tell the user that a task is needing attention */ if(CANNOT GetTaskName(NULL,GlobalNameBuffer,sizeof(GlobalNameBuffer))) { DPrintf("WAITING; to continue, send ^C to %s \"%s\" (task 0x%08lx).\n",taskTypeName,GlobalNameBuffer,FindTask(NULL)); } else { DPrintf("WAITING; to continue, send ^C to this %s (task 0x%08lx).\n",taskTypeName,FindTask(NULL)); } /* wait for the wakeup signal */ SetSignal(0,SIGBREAKF_CTRL_C); Wait(SIGBREAKF_CTRL_C); DPrintf("\n"); } /******************************************************************************/ STATIC BOOL CalledFromSupervisorMode(VOID) { BOOL supervisorMode; supervisorMode = (BOOL)((GetCC() & 0x2000) != 0); /* If this routine returns TRUE, then the CPU is currently * processing an interrupt request or an exception condition * was triggered (more or less the same). */ return(supervisorMode); } /******************************************************************************/ BOOL CheckStomping(ULONG * stackFrame,struct TrackHeader * th) { BOOL wasStomped = FALSE; UBYTE * mem; LONG memSize; UBYTE * stompMem; LONG stompSize; UBYTE * body; body = ((UBYTE *)(th + 1)) + PreWallSize; mem = (UBYTE *)(th + 1); memSize = PreWallSize; /* check if the pre-allocation wall was trashed */ if(WasStompedUpon(mem,memSize,th->th_FillChar,&stompMem,&stompSize)) { if(IsActive) { VoiceComplaint(stackFrame,th,"Front wall was stomped upon\n"); DPrintf("%ld byte(s) stomped (0x%08lx..0x%08lx), allocation-%ld byte(s)\n", stompSize,stompMem,stompMem+stompSize-1, (LONG)body - (LONG)(stompMem+stompSize-1)); DumpWall(stompMem,stompSize,th->th_FillChar); } wasStomped = TRUE; } mem += PreWallSize + th->th_Size; memSize = th->th_PostSize; /* check if the post-allocation wall was trashed */ if(WasStompedUpon(mem,memSize,th->th_FillChar,&stompMem,&stompSize)) { if(IsActive) { VoiceComplaint(stackFrame,th,"Back wall was stomped upon\n"); DPrintf("%ld byte(s) stomped (0x%08lx..0x%08lx), allocation+%ld byte(s)\n", stompSize,stompMem,stompMem+stompSize-1, (LONG)stompMem - (LONG)(body + th->th_Size - 1)); DumpWall(stompMem,stompSize,th->th_FillChar); } wasStomped = TRUE; } return(wasStomped); } /******************************************************************************/ APTR ASM NewAllocMem( REG(d0) ULONG byteSize, REG(d1) ULONG attributes, REG(a2) ULONG * stackFrame) { APTR result = NULL; BOOL hit = FALSE; /* no memory allocation routine may be called from supervisor mode */ if(NOT CalledFromSupervisorMode()) { /* check if this allocation should be tracked */ if(IsActive && CanAllocate()) { if(byteSize == 0) { VoiceComplaint(stackFrame,NULL,"AllocMem(%ld,0x%08lx) called\n",byteSize,attributes); hit = TRUE; } else { /* stackFrame[16] contains the return address of the caller */ if(CANNOT PerformAllocation(stackFrame[16],NULL,byteSize,attributes,ALLOCATIONTYPE_AllocMem,&result)) { if(ShowFail) { VoiceComplaint(stackFrame,NULL,"AllocMem(%ld,0x%08lx) failed\n",byteSize,attributes); hit = TRUE; } } } } else { result = (*OldAllocMem)(byteSize,attributes,SysBase); } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"AllocMem(%ld,0x%08lx) called from interrupt/exception\n",byteSize,attributes); } } if(hit && WaitAfterHit) { WaitForBreak(); } return(result); } VOID ASM NewFreeMem( REG(a1) APTR memoryBlock, REG(d0) ULONG byteSize, REG(a2) ULONG * stackFrame) { BOOL hit = FALSE; if(NOT CalledFromSupervisorMode()) { if(memoryBlock == NULL || byteSize == NULL) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeMem(0x%08lx,%ld) called\n",memoryBlock,byteSize); hit = TRUE; } } else { struct TrackHeader * th; BOOL freeIt = TRUE; /* memory may be deallocated only from an even address */ if(IsOddAddress((ULONG)memoryBlock)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeMem(0x%08lx,%ld) on odd address\n",memoryBlock,byteSize); hit = TRUE; } freeIt = FALSE; } /* check if the address points into RAM */ if(IsInvalidAddress((ULONG)memoryBlock)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeMem(0x%08lx,%ld) on illegal address\n",memoryBlock,byteSize); hit = TRUE; } freeIt = FALSE; } /* check if the memory to free is really allocated */ if(NOT IsAllocatedMemory((ULONG)memoryBlock,byteSize)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeMem(0x%08lx,%ld) not in allocated memory\n",memoryBlock,byteSize); hit = TRUE; } freeIt = FALSE; } /* now test whether the allocation was tracked by us */ if(IsTrackedAllocation((ULONG)memoryBlock,&th)) { /* check whether the allocation walls were trashed */ if(CheckStomping(stackFrame,th)) { freeIt = FALSE; if(IsActive) { hit = TRUE; } } if(byteSize != th->th_Size) { if(IsActive) { VoiceComplaint(stackFrame,th,"Free size %ld does not match allocation size %ld\n",byteSize,th->th_Size); hit = TRUE; } freeIt = FALSE; } if(th->th_Type != ALLOCATIONTYPE_AllocMem) { if(IsActive) { VoiceComplaint(stackFrame,th,"In FreeMem(0x%08lx,%ld): Memory was not allocated with AllocMem()\n",memoryBlock,byteSize); hit = TRUE; } freeIt = FALSE; } if(freeIt) { PerformDeallocation(th); } else { /* Let it go, but don't deallocate it. */ th->th_Magic = 0; } } else { if(freeIt) { (*OldFreeMem)(memoryBlock,byteSize,SysBase); } } } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeMem(0x%08lx,%ld) called from interrupt/exception\n",memoryBlock,byteSize); } } if(hit && WaitAfterHit) { WaitForBreak(); } } /******************************************************************************/ APTR ASM NewAllocVec( REG(d0) ULONG byteSize, REG(d1) ULONG attributes, REG(a2) ULONG * stackFrame) { APTR result = NULL; BOOL hit = FALSE; if(NOT CalledFromSupervisorMode()) { if(IsActive && CanAllocate()) { if(byteSize == 0) { VoiceComplaint(stackFrame,NULL,"AllocVec(%ld,0x%08lx) called\n",byteSize,attributes); hit = TRUE; } else { if(CANNOT PerformAllocation(stackFrame[16],NULL,byteSize,attributes,ALLOCATIONTYPE_AllocVec,&result)) { if(ShowFail) { VoiceComplaint(stackFrame,NULL,"AllocVec(%ld,0x%08lx) failed\n",byteSize,attributes); hit = TRUE; } } } } else { result = (*OldAllocVec)(byteSize,attributes,SysBase); } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"AllocVec(%ld,0x%08lx) called from interrupt/exception\n",byteSize,attributes); } } if(hit && WaitAfterHit) { WaitForBreak(); } return(result); } VOID ASM NewFreeVec( REG(a1) APTR memoryBlock, REG(a2) ULONG * stackFrame) { BOOL hit = FALSE; if(NOT CalledFromSupervisorMode()) { if(memoryBlock != NULL) { struct TrackHeader * th; BOOL freeIt = TRUE; if(IsOddAddress((ULONG)memoryBlock)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeVec(0x%08lx) on odd address\n",memoryBlock); hit = TRUE; } freeIt = FALSE; } if(IsInvalidAddress((ULONG)memoryBlock)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeVec(0x%08lx) on illegal address\n",memoryBlock); hit = TRUE; } freeIt = FALSE; } /* note that in order to check the size and the place of the * allocation, the address must be valid */ if(freeIt && NOT IsAllocatedMemory(((ULONG)memoryBlock)-4,(*(ULONG *)(((ULONG)memoryBlock)-4)))) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeVec(0x%08lx) not in allocated memory\n",memoryBlock); hit = TRUE; } freeIt = FALSE; } if(IsTrackedAllocation(((ULONG)memoryBlock) - sizeof(ULONG),&th)) { if(CheckStomping(stackFrame,th)) { freeIt = FALSE; if(IsActive) { hit = TRUE; } } if(th->th_Type != ALLOCATIONTYPE_AllocVec) { if(IsActive) { VoiceComplaint(stackFrame,th,"In FreeVec(0x%08lx): Memory was not allocated with AllocVec()\n",memoryBlock); hit = TRUE; } freeIt = FALSE; } if(freeIt) { PerformDeallocation(th); } else { /* Let it go, but don't deallocate it. */ th->th_Magic = 0; } } else { if(freeIt) { (*OldFreeVec)(memoryBlock,SysBase); } } } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreeVec(0x%08lx) called from interrupt/exception\n",memoryBlock); } } if(hit && WaitAfterHit) { WaitForBreak(); } } /******************************************************************************/ APTR ASM NewCreatePool( REG(d0) ULONG memFlags, REG(d1) ULONG puddleSize, REG(d2) ULONG threshSize, REG(a2) ULONG * stackFrame) { APTR result = NULL; BOOL hit = FALSE; if(NOT CalledFromSupervisorMode()) { if(IsActive && CanAllocate()) { /* the puddle threshold size must not be larger * than the puddle size */ if(threshSize <= puddleSize) { struct PoolHeader * ph; ph = CreatePoolHeader(memFlags,puddleSize,threshSize,stackFrame[16]); if(ph != NULL) { result = ph->ph_PoolHeader; } else { if(ShowFail) { VoiceComplaint(stackFrame,NULL,"CreatePool(0x%08lx,%ld,%ld) failed\n",memFlags,puddleSize,threshSize); hit = TRUE; } } } else { VoiceComplaint(stackFrame,NULL,"Threshold size %ld must be <= puddle size %ld\n",threshSize,puddleSize); hit = TRUE; } } else { result = (*OldCreatePool)(memFlags,puddleSize,threshSize,SysBase); } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"CreatePool(0x%08lx,%ld,%ld) called from interrupt/exception\n",memFlags,puddleSize,threshSize); } } if(hit && WaitAfterHit) { WaitForBreak(); } return(result); } VOID ASM NewDeletePool( REG(a0) APTR poolHeader, REG(a2) ULONG * stackFrame) { BOOL hit = FALSE; if(NOT CalledFromSupervisorMode()) { if(poolHeader != NULL) { struct PoolHeader * ph; ph = FindPoolHeader(poolHeader); if(ph != NULL) { /* note that DeletePoolHeader() implies * HoldPoolSemaphore()..ReleasePoolSemaphore() */ if(CANNOT DeletePoolHeader(stackFrame,ph)) { if(IsActive) { hit = TRUE; } } } else { (*OldDeletePool)(poolHeader,SysBase); } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"DeletePool(NULL) called\n"); hit = TRUE; } } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"DeletePool(0x%08lx) called from interrupt/exception\n",poolHeader); } } if(hit && WaitAfterHit) { WaitForBreak(); } } /******************************************************************************/ APTR ASM NewAllocPooled( REG(a0) APTR poolHeader, REG(d0) ULONG memSize, REG(a2) ULONG * stackFrame) { APTR result = NULL; BOOL hit = FALSE; if(NOT CalledFromSupervisorMode()) { if(IsActive && CanAllocate()) { if(poolHeader != NULL && memSize > 0) { struct PoolHeader * ph; /* check whether this memory pool is being tracked */ ph = FindPoolHeader(poolHeader); if(ph != NULL) { HoldPoolSemaphore(ph,stackFrame[16]); if(CANNOT PerformAllocation(stackFrame[16],ph,memSize,ph->ph_Attributes,ALLOCATIONTYPE_AllocPooled,&result)) { if(ShowFail) { VoiceComplaint(stackFrame,NULL,"AllocPooled(0x%08lx,%ld) failed\n",poolHeader,memSize); hit = TRUE; } } ReleasePoolSemaphore(ph); } else { result = (*OldAllocPooled)(poolHeader,memSize,SysBase); } } else { VoiceComplaint(stackFrame,NULL,"AllocPooled(0x%08lx,%ld) called\n",poolHeader,memSize); hit = TRUE; } } else { result = (*OldAllocPooled)(poolHeader,memSize,SysBase); } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"AllocPooled(0x%08lx,%ld) called from interrupt/exception\n",poolHeader,memSize); } } if(hit && WaitAfterHit) { WaitForBreak(); } return(result); } VOID ASM NewFreePooled( REG(a0) APTR poolHeader, REG(a1) APTR memoryBlock, REG(d0) ULONG memSize, REG(a2) ULONG * stackFrame) { BOOL hit = FALSE; if(NOT CalledFromSupervisorMode()) { if(poolHeader != NULL && memoryBlock != NULL && memSize > 0) { struct PoolHeader * ph; BOOL freeIt = TRUE; if(IsOddAddress((ULONG)memoryBlock)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreePooled(0x%08lx,0x%08lx,%ld) on odd address\n",poolHeader,memoryBlock,memSize); hit = TRUE; } freeIt = FALSE; } if(IsInvalidAddress((ULONG)memoryBlock)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreePooled(0x%08lx,0x%08lx,%ld) on illegal address\n",poolHeader,memoryBlock,memSize); hit = TRUE; } freeIt = FALSE; } if(NOT IsAllocatedMemory((ULONG)memoryBlock,memSize)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreePooled(0x%08lx,0x%08lx,%ld) not in allocated memory\n",poolHeader,memoryBlock,memSize); hit = TRUE; } freeIt = FALSE; } ph = FindPoolHeader(poolHeader); if(ph != NULL) { struct TrackHeader * th; HoldPoolSemaphore(ph,stackFrame[16]); if(NOT PuddleIsInPool(ph,memoryBlock)) { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreePooled(0x%08lx,0x%08lx,%ld) not in pool\n",poolHeader,memoryBlock,memSize); DumpPoolOwner(ph); hit = TRUE; } freeIt = FALSE; } if(IsTrackedAllocation((ULONG)memoryBlock,&th)) { if(CheckStomping(stackFrame,th)) { freeIt = FALSE; if(IsActive) { hit = TRUE; } } if(memSize != th->th_Size) { if(IsActive) { VoiceComplaint(stackFrame,th,"Free size %ld does not match allocation size %ld\n",memSize,th->th_Size); hit = TRUE; } freeIt = FALSE; } if(th->th_PoolHeader->ph_PoolHeader != poolHeader) { if(IsActive) { struct PoolHeader * ph; VoiceComplaint(stackFrame,th,"FreePooled(0x%08lx,0x%08lx,%ld) called on puddle in wrong pool (right=0x%08lx wrong=0x%08lx)\n",poolHeader,memoryBlock,memSize,th->th_PoolHeader->ph_PoolHeader,poolHeader); hit = TRUE; DumpPoolOwner(th->th_PoolHeader); ph = FindPoolHeader(poolHeader); if(ph != NULL) DumpPoolOwner(ph); } freeIt = FALSE; } if(th->th_Type != ALLOCATIONTYPE_AllocPooled) { if(IsActive) { VoiceComplaint(stackFrame,th,"In FreePooled(0x%08lx,0x%08lx,%ld): Memory was not allocated with AllocPooled()\n",poolHeader,memoryBlock,memSize); hit = TRUE; } freeIt = FALSE; } if(freeIt) { PerformDeallocation(th); } else { /* Let it go, but don't deallocate it. */ th->th_Magic = 0; } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreePooled(0x%08lx,0x%08lx,%ld) called on puddle that is not in pool\n",poolHeader,memoryBlock,memSize); hit = TRUE; } } ReleasePoolSemaphore(ph); } else { if(freeIt) { (*OldFreePooled)(poolHeader,memoryBlock,memSize,SysBase); } } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreePooled(0x%08lx,0x%08lx,%ld) called\n",poolHeader,memoryBlock,memSize); hit = TRUE; } } } else { if(IsActive) { VoiceComplaint(stackFrame,NULL,"FreePooled(0x%08lx,0x%08lx,%ld) called from interrupt/exception\n",poolHeader,memoryBlock,memSize); } } if(hit && WaitAfterHit) { WaitForBreak(); } }