/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/src/sgx/core/helpers/memwatch.cpp

*/

#include "sgx/core/core.hpp"

namespace {

class CWatchLocation {
public:
	tBYTE		*pWatchStart;
	tBYTE		*pWatchEnd;         // actually one byte beyond the end
	tUINT32 	Checksum;
    
    
	CWatchLocation(void *ptr, tMEM_SIZE size);

    tUINT32 CalcCheckSum();
	};

sgxVector<CWatchLocation> g_WatchLocations;

CWatchLocation::CWatchLocation(void *ptr, tMEM_SIZE size)
{
    pWatchStart = (tBYTE *)ptr; 
    pWatchEnd = pWatchStart + size;
    Checksum = CalcCheckSum(); 
}

tUINT32 CWatchLocation::CalcCheckSum()
{
    tBYTE *ptr = pWatchStart;
    tUINT32 check = 0;

    while(ptr != pWatchEnd) {
        check += *ptr++;
    }

    return check;
}

}	// namespace

#if defined(SGX_DEBUG) || defined(SGX_FORCE_MEMORY_HELPERS)

/**
Specifies an arbitrary block of memory to 'watch'. The data within
every block is noted by its checksum, and compared with the current
value on each call to sgxCheckForOverwrites.
*/
void sgxRegisterMemoryBlock(void *ptr, tMEM_SIZE size)
{
	g_WatchLocations.push_back(CWatchLocation(ptr, size));
}

void sgxCheckCheckSums()
{
    sgxVector<CWatchLocation>::iterator it = g_WatchLocations.begin();

    for(;it != g_WatchLocations.end(); ++it) {
        if ((*it).CalcCheckSum() != (*it).Checksum) {
            sgxTrace("Checksum error!");
        }
    }
}

/**
Checks for any watched blocks within the range of ptr to 
ptr+size-1.

This checking is co-operative checking, since it requires the developer
to explicitly call this method to perform such checks. It is recommended
this call is made only in debug, and before each object is updated.
  */
void sgxCheckForOverwrites(void *ptr, tMEM_SIZE size)
{
    tBYTE *pStart = (tBYTE *)ptr;
    tBYTE *pEnd = pStart + size;// actually one beyond the end

    sgxVector<CWatchLocation>::iterator it = g_WatchLocations.begin();

    for(;it != g_WatchLocations.end(); ++it) {
        if ((pStart < (*it).pWatchStart && pEnd > (*it).pWatchStart) ||
            ((*it).pWatchStart < pStart && (*it).pWatchEnd > pStart)) {
            sgxTrace("Memory overlap! 0x%x (%d)", ptr, size);
        }
    }
}

#endif

