//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/***
*rtcpriv.h - declarations and definitions for RTC use
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
*       Contains the declarations and definitions for all RunTime Check
*       support.
*
*Revision History:
*       ??-??-??  KBF   Created implementation header for RTC
*       05-26-99  KBF   Removed RTCl & RTCv, added _RTC_ADVMEM stuff
*       10-14-99  PML   Replace InitializeCriticalSection with wrapper function
*                       __crtInitCritSecAndSpinCount
*       10-17-03  SJ    Added UNICODE RTC Reporting
*       11-18-03  CSP   Added _alloca checking support.
*       04-07-04  MSL   Double slash removal
*       10-01-04  AGH   New prototype for _RTC_AllocaFailure
*       11-11-04  MR    Add support for special handles in C# - VSW#272079
*       11-18-04  ATC   SAL Annotations for CRT Headers
*       03-23-05  MSL   _P removal - not needed
*                       New deprecation warning with function name
*                       Packing fix
*
****/

#ifndef _INC_RTCPRIV
#define _INC_RTCPRIV

#include <crtdefs.h>

#pragma pack(push,_CRT_PACKING)

#ifdef  _RTC

#include <windows.h>
#include <winbase.h>
#include <malloc.h>

#include "rtcapi.h"

#pragma warning(disable:4710)
#pragma warning(disable:4711)
#ifndef __cplusplus
#error This header is only for use with the C++ compiler while building the RTC library code.
#endif

#pragma pack(push, 4)

#ifndef _RTC_DEBUG
#pragma optimize("gb1", on)
#endif

/* Multithreaded code locking stuff...
*/

#define INIT_LOCK   InitializeCriticalSectionAndSpinCount(&_RTC_memlock, _CRT_SPINCOUNT)
#define LOCK        EnterCriticalSection(&_RTC_memlock)
#define UNLOCK      LeaveCriticalSection(&_RTC_memlock)
#define DEL_LOCK    DeleteCriticalSection(&_RTC_memlock)
#define TRY_LOCK    TryEnterCriticalSection(&_RTC_memlock)
extern CRITICAL_SECTION _RTC_memlock;

/* Typedefs
*/
struct  _RTC_globals;

#ifdef _RTC_ADVMEM
class   _RTC_SimpleHeap;
class   _RTC_Container;
class   _RTC_HeapBlock;    
class   _RTC_BinaryTree;
template<class T> class HashTable;
typedef unsigned char shadowtag;
typedef unsigned char index_elem;

#endif

/* General global functions & symbols
*/
extern int          _RTC_ErrorLevels[_RTC_ILLEGAL];
extern _RTC_globals *_RTC_globptr;

bool                _RTC_Lock();
void                _RTC_Unlock();
void                _RTC_Failure(void *retaddr, int errnum);
_RTC_error_fn       _RTC_GetErrorFunc(LPCVOID addr);
_RTC_error_fnW      _RTC_GetErrorFuncW(LPCVOID addr);
void                _RTC_StackFailure(void *retaddr, const char *varname);
void                _RTC_AllocaFailure(void *retaddr, _RTC_ALLOCA_NODE * pn, int num);
BOOL                _RTC_GetSrcLine(LPBYTE address, _Out_writes_(sourcelen) wchar_t* source, DWORD sourcelen,
                                    int* pline, _Out_writes_(modulelen) wchar_t* moduleName, DWORD modulelen);
extern "C" {
void __fastcall     _RTC_APISet(int on_off);
}
void                _RTC_NotifyOthersOfChange(void *addr);


/* When this changes, you'd better be sure that everything still works with the old stuff!
*/
#define _RTC_CURRENT_VERSION 1

/* The order of the initial stuff here can't change AT ALL!!!
*/
struct _RTC_Funcs {
    _RTC_error_fn err;
    void (*notify)(void);
    void *allocationBase;
    _RTC_Funcs *next;
#ifdef _RTC_ADVMEM
    int  (*shadowoff)(void);
#endif
};

/* definitions of library globals
The order of this stuff MUST STAY THE SAME BETWEEN VERSION!!!
*/
struct _RTC_globals {
    int                         version;
    CRITICAL_SECTION            memlock;
    _RTC_Funcs                  *callbacks;
#ifdef _RTC_ADVMEM
    _RTC_SimpleHeap             *heap2;
    _RTC_SimpleHeap             *heap4;
    _RTC_SimpleHeap             *heap8;
    _RTC_Container              *memhier;
    shadowtag                   *shadow;
    index_elem                  *pageidx;
    HashTable<_RTC_HeapBlock>   *heapblocks;
    bool                        *pi_array;
    bool                        shadowmemory;
#endif
};
#define _RTC_GLOBALS_SIZE 1024

/* Shadow Memory stuff */
#ifdef _RTC_ADVMEM

void            _RTC_MS_Init();
void            _RTC_MemFailure(void *retaddr, int errnum, const void *assign);
short           _RTC_MSAllocShadow(memptr addr, unsigned size, unsigned state);
void            _RTC_MSRestoreShadow(memptr addr, unsigned size, short id);
short           _RTC_MSRenumberShadow(memptr addr, unsigned size, short notID);
void            _RTC_MSFreeShadow(memptr addr, unsigned size);
void __cdecl    _RTC_MSAllocateGlobals(void);
void            _RTC_MSDecommitRange(memptr addr, unsigned size);
void            _RTC_MSCommitRange(memptr addr, unsigned size, unsigned state);
extern "C" {
void __fastcall _RTC_CheckMem_API(memref addr, unsigned size);
}

/* Unknown MUST be 0
*/
#define IDX_STATE_UNKNOWN         0
#define IDX_STATE_ILLEGAL         1
#define IDX_STATE_PARTIALLY_KNOWN 2
#define IDX_STATE_FULLY_KNOWN     3

extern _RTC_Container               *_RTC_memhier;
extern HashTable<_RTC_HeapBlock>    *_RTC_heapblocks;
extern _RTC_SimpleHeap              *_RTC_heap2;
extern _RTC_SimpleHeap              *_RTC_heap4;
extern _RTC_SimpleHeap              *_RTC_heap8;
extern shadowtag                    *_RTC_shadow;
extern index_elem                   *_RTC_pageidx;
extern bool                         *_RTC_pi_array;
extern bool                         _RTC_shadowmemory;


/**********************************/

#define ALLOC_SIZE 65536

class _RTC_SimpleHeap 
{
    struct FreeList 
    {
        FreeList *next;
    };
    struct HeapNode 
    {
        HeapNode *next; /* next page in list (not necessarily free) */
        FreeList *free; /* node-local free-list */
        union info 
        {
            struct topStuff 
            {   /* Stuff that pertains only to the top node */
                HeapNode *nxtFree;  /* Pointer to node containing free items */
                short wordSize;     /* The size of blocks in this heap */
                bool  freePage;     /* True if there's a 100% free page */
            } top;

            struct nonTopStuff 
            {   /* Stuff that pertais only to non-top nodes */
                unsigned freeCount; /* The free count for this node */
                HeapNode *prev;     /* previous link */
            } nontop;
        } inf;
    } head;

public:
    
    _RTC_SimpleHeap(unsigned blockSize) throw();
    ~_RTC_SimpleHeap() throw();

    void *operator new(unsigned) throw();
    void operator delete(void *addr) throw();
    
    void *alloc() throw();
    void free(void *addr) throw();
};

extern _RTC_SimpleHeap *_RTC_heap2;
extern _RTC_SimpleHeap *_RTC_heap4;
extern _RTC_SimpleHeap *_RTC_heap8;


#define DATA(type, name) \
private: \
    type _##name; \
public: \
    type name() const { return _##name; }\
    void name(type a) { _##name = a; }

class _RTC_HeapBlock
{
    DATA(void *, addr);             /* The memory block address */
    DATA(unsigned, size);           /* The size of the block */
    DATA(_RTC_HeapBlock *, next);   /* The next element */
    DATA(_RTC_HeapBlock **,list);   /* The head list pointer */
    DATA(short, id);                /* The level ID of the block (for tiers) */
    DATA(short, tag);               /* The shadow tag of the block in shadow memory */

public:

    _RTC_HeapBlock(void *address, short lev) 
        : _addr(address), _id(lev) , _next(0), _list(0) {}
    
    _RTC_HeapBlock(void *MemAddress, short Identifier, unsigned Size)
        : _addr(MemAddress), _id(Identifier), _size(Size), _next(0), _list(0) {}

    ~_RTC_HeapBlock() throw() 
    {
        if (_list) del(_list); 
    }

    void *operator new(unsigned) throw() 
    { 
        return _RTC_heap8->alloc(); 
    }
    
    void operator delete(void *addr) throw() 
    {
       _RTC_heap8->free(addr); 
    }
           
    int operator<(const _RTC_HeapBlock &h) const
    {
        return _addr < h._addr;
    }

    int operator==(const _RTC_HeapBlock &h) const
    {
        return h._addr == _addr && h._id == _id;
    }
    
    bool contains(const _RTC_HeapBlock &h) const 
    {
        return ((unsigned)_addr <= (unsigned)h._addr) &&
                ((unsigned)h._addr < (unsigned)_addr + _size);
    }
    
    unsigned hash(unsigned sz) const 
    {
        return (((unsigned)_addr) ^ _id) % sz;
    }

    void add(_RTC_HeapBlock **lstHead) throw() 
    {
        this->next(*lstHead);
        this->list(lstHead);
        *lstHead = this;
    }

    void del(_RTC_HeapBlock **lstHead) throw() 
    {
        _RTC_HeapBlock *head = *lstHead;
        _RTC_HeapBlock *prev = 0;
        while (head != this)
        {
            prev = head;
            head = head->next();
        }
        if (prev)
            prev->next(this->next());
        else
            *lstHead = this->next();
        next(0);
        list(0);
    }
};

#undef DATA

class _RTC_BinaryTree 
{
public:

    class BinaryNode 
    {
    public:
        BinaryNode *l, *r;
        _RTC_Container *val;

        void *operator new(unsigned) throw()
        { 
            return _RTC_heap4->alloc();      
        }

        void operator delete(void *addr) throw() 
        { 
            _RTC_heap4->free(addr); 
        }
        
        BinaryNode(BinaryNode *L, BinaryNode *R, _RTC_Container *V)
            : l(L), r(R), val(V) {}

        void kill() throw();
    };

private:

    BinaryNode *tree;

public:

    _RTC_BinaryTree(_RTC_Container *i) throw() 
        : tree(new BinaryNode(0, 0,  i)) {}
    
    ~_RTC_BinaryTree() throw() 
    { 
        if (tree) 
        {
            tree->kill(); 
            delete tree;
        } 
    }

    void *operator new(unsigned) throw() 
    { 
        return _RTC_heap2->alloc(); 
    }
    
    void operator delete(void *addr) throw() { _RTC_heap2->free(addr); }

    /* This will return either the container or null */
    _RTC_Container *get(_RTC_HeapBlock *) throw();

    /* This just adds to the current sib list */
    _RTC_Container* add(_RTC_HeapBlock *) throw();

    /* This just removes the item from the current sib list */
    _RTC_Container *del(_RTC_HeapBlock *) throw();

    /* Here's an iterator */
    class iter 
    {
        _RTC_Container **allSibs;
        int curSib;
        int totSibs;
        friend class _RTC_BinaryTree;
    
    public:
        /* This thing should never be allocated... */
        void *operator new(unsigned) 
        { 
            return 0; 
        }
    };

    _RTC_Container *FindFirst(iter *) throw();
    _RTC_Container *FindNext(iter *) throw();
};

class _RTC_Container 
{
    /* kids - the item that has all the children */
    _RTC_BinaryTree *kids;
    /* inf - the item that specifies containment */
    _RTC_HeapBlock *inf;

    /* This kills this container, and all contained info */
    void kill() throw();
public:
    _RTC_Container(_RTC_HeapBlock *hb) 
        : inf(hb), kids(0) {}
    
    ~_RTC_Container() throw() 
    {
        if (inf || kids)
            kill();
    }
    
    _RTC_HeapBlock *info() const 
    {
        return inf;
    }

    bool contains(const _RTC_HeapBlock *i) const throw() 
    {
        return inf ? inf->contains(*i) : true;
    }

    /* Returns the parent container */
    _RTC_Container *DelChild(_RTC_HeapBlock *i) throw();

    /* Add this item as a child inside this container */
    /* It may or may not be a direct child */
    /* It returns the parent container */
    _RTC_Container *AddChild(_RTC_HeapBlock *i) throw();

    /* Find the container that contains the data given */
    _RTC_Container *FindChild(_RTC_HeapBlock *i) throw();

    typedef _RTC_HeapBlock data;
    void *operator new(unsigned) throw() { return _RTC_heap2->alloc(); }
    void operator delete(void *addr) throw() { _RTC_heap2->free(addr); }
};


template <class T>
class HashTable 
{
    unsigned size;
    T **elems;

public:

    HashTable(unsigned s, void *mem) 
        : elems((T**)mem), size(s) 
    {
        memset(elems, 0, size * sizeof(T*)); 
    }
    
    ~HashTable() {}

    void *operator new(unsigned) throw() 
    { 
        return _RTC_heap2->alloc(); 
    }
    
    void operator delete(void *addr) throw() 
    { 
        _RTC_heap2->free(addr); 
    }
    
    T *find(T *key) throw() 
    {
        unsigned hkey = key->hash(size);
        T *elem = elems[hkey];
        while (elem && !(*elem == *key))
            elem = elem->next();
        return elem;
    }
    
    void add(T *itm) throw() 
    {
        unsigned hkey = itm->hash(size);
        itm->add(&elems[hkey]);
    }   
    
    void del(T *key) throw() 
    {
        unsigned hkey = key->hash(size);
        T *elem = elems[hkey];
        while (elem && !(*elem == *key))
            elem = elem->next();
        elem->del(&elems[hkey]);
    }
};
#endif


/* Stuff for the debugger exception mechanism */
/* Swiped fro vcexcept.h in the LangAPI */
#if !defined(_vcexcept_h)
#define _vcexcept_h

#ifdef _WIN32_WCE //it has defined in winerror.h also
#define FACILITY_VISUALCPP               109  
#endif // _WIN32_WCE

#define VcppException(sev,err)  ((sev) | (FACILITY_VISUALCPP<<16) | err)

/* define all exceptions here, so we don't mess with each other */

/* used by CRTs for C++ exceptions, really defined in ehdata.h */
/*#define EH_EXCEPTION_NUMBER   VcppException( 3<<30, 0x7363 )       SEV_ERROR, used by CRTs for C++ */

/* used by debugger to do e.g. SetThreadName call */
#define EXCEPTION_VISUALCPP_DEBUGGER    VcppException(1<<30, 5000)      /* SEV_INFORMATIONAL */

#endif  /* _vcexcept_h */

/* Ping the VC debugger */
#define HelloVC( exinfo )   \
    RaiseException( EXCEPTION_VISUALCPP_DEBUGGER, 0, sizeof(exinfo)/sizeof(DWORD), (ULONG_PTR *)&exinfo )

enum EXCEPTION_DEBUGGER_ENUM
{
    EXCEPTION_DEBUGGER_NAME_THREAD  =   0x1000,
    EXCEPTION_DEBUGGER_PROBE        =   0x1001,
    EXCEPTION_DEBUGGER_RUNTIMECHECK =   0x1002,
    EXCEPTION_DEBUGGER_FIBER        =   0x1003,
    EXCEPTION_DEBUGGER_HANDLECHECK  =   0x1004,

    EXCEPTION_DEBUGGER_MAX = 0x1004 /* largest value this debugger understands */
};

/* must use pack 8 on 64 bits platforms */
#if defined(_WIN64)
#pragma pack(push, 8)
#endif  /* _WIN64 */

/* must be convertible to DWORDs for use by RaiseException */
typedef struct tagEXCEPTION_VISUALCPP_DEBUG_INFO
{
    DWORD   dwType;                     /* one of the enums from above */
    union
    {
        struct
        {
            LPCSTR  szName;             /* pointer to name (in user addr space) */
            DWORD   dwThreadID;         /* thread ID (-1=caller thread) */
            DWORD   dwFlags;            /* reserved for future use (eg User thread, System thread) */
        } SetName;

        struct
        {
            DWORD   dwLevelRequired;    /* 0 = do you understand this private exception, else max value of enum */
            PBYTE   pbDebuggerPresent;  /* debugger puts a non-zero value in this address if there */
        } DebuggerProbe;

        struct
        {
            DWORD   dwRuntimeNumber;    /* the type of the runtime check */
            BOOL    bRealBug;           /* TRUE if never a false-positive */
            PVOID   pvReturnAddress;    /* caller puts a return address in here */
            PBYTE   pbDebuggerPresent;  /* debugger puts a non-zero value in this address if handled it */
            LPCWSTR pwRuntimeMessage;   /* pointer to Unicode message (or NULL) */
        } RuntimeError;
    };
} EXCEPTION_VISUALCPP_DEBUG_INFO;

#if defined(_WIN64)
#pragma pack(pop)
#endif  /* _WIN64 */

#pragma pack(pop)

#endif

#pragma pack(pop)

#endif  /* _INC_RTCPRIV */
