/*++

Copyright (C) 1999-2001 Microsoft Corporation

Module Name:

Abstract:

History:

--*/

#include <windows.h>
#include <stdio.h>


#ifdef _MT
  #undef _MT
  #include <yvals.h>
  #define _MT
#endif

#include <arena.h>

#include <sync.h>
#include <flexarry.h>
#include <time.h>
#include <stdio.h>
#include <arrtempl.h>
#include <sync.h>
#include <malloc.h>
#include <imagehlp.h>
#include <execq.h>
#include "stackcom.h"

void* CStackRecord::mstatic_apReturns[1000];

void CStackRecord::Create(int nIgnore, BOOL bStatic)
{
	m_dwNumItems = GetStackLen() - nIgnore;
	if(bStatic)
	{
		m_apReturns = (void**)mstatic_apReturns;
		m_bDelete = FALSE;
	}
	else
	{
		m_apReturns = new void*[m_dwNumItems];
		m_bDelete = TRUE;
	}

	ReadStack(nIgnore, m_apReturns);
}

CStackRecord::~CStackRecord() 
{
	if(m_bDelete)
		delete m_apReturns;
}

void CStackRecord::MakeCopy(CStackRecord& Other)
{
	m_dwNumItems = Other.GetNumItems();
	DWORD dwLen = Other.GetNumItems() * sizeof(void*);
	m_apReturns = new void*[Other.GetNumItems()];
	memcpy(m_apReturns, Other.GetItems(), dwLen);
	m_bDelete = TRUE;
}

int CStackRecord::Compare(const CStackRecord& Other) const
{
	int nDiff = GetNumItems()- Other.GetNumItems();
	if(nDiff)
		return nDiff;

	return memcmp(GetItems(), Other.GetItems(), sizeof(void*) * GetNumItems());
}

DWORD CStackRecord::GetStackLen()
{
    void* pFrame;
    __asm
    {
        mov pFrame, ebp
    }

    CStackContinuation* pPrev = CStackContinuation::Get();
    void* pEnd = NULL;
    if(pPrev)
        pEnd = pPrev->m_pThisStackEnd;

	DWORD dwLen = 0;
    while(!IsBadReadPtr(pFrame, sizeof(DWORD)))
    {
		dwLen++;
        void** ppReturn = (void**)pFrame + 1;
        void* pReturn = *ppReturn;
		if(pReturn == pEnd)
			break;
        void* pNewFrame = *(void**)pFrame;
		if(pNewFrame <= pFrame)
			break;
		pFrame = pNewFrame;
    }

    if(pPrev != NULL)
        dwLen += pPrev->m_pPrevStack->GetNumItems();

	return dwLen;
}

void CStackRecord::ReadStack(int nIgnore, void** apReturns)
{
    void* pFrame;
    __asm
    {
        mov pFrame, ebp
    }

    CStackContinuation* pPrev = CStackContinuation::Get();
	void* pEnd = NULL;
    if(pPrev)
        pEnd = pPrev->m_pThisStackEnd;

    while(!IsBadReadPtr(pFrame, sizeof(DWORD)))
    {
        void** ppReturn = (void**)pFrame + 1;
        void* pReturn = *ppReturn;
		if(pReturn == pEnd)
			break;

		if(nIgnore == 0)
			*(apReturns++) = pReturn;
		else
			nIgnore--;

        void* pNewFrame = *(void**)pFrame;
		if(pNewFrame <= pFrame)
			break;
		pFrame = pNewFrame;
    }

    if(pPrev != NULL)
    {
        memcpy(apReturns, pPrev->m_pPrevStack->m_apReturns, 
                sizeof(void*) * pPrev->m_pPrevStack->GetNumItems());
    }
}

void CStackRecord::Dump(FILE* f) const
{
	fwrite(&m_dwNumItems, sizeof(DWORD), 1, f);
	fwrite(m_apReturns, sizeof(void*), m_dwNumItems, f);
}

BOOL CStackRecord::Read(FILE* f, BOOL bStatic)
{
	if(fread(&m_dwNumItems, sizeof(DWORD), 1, f) == 0)
		return FALSE;

	if(bStatic)
	{
		m_apReturns = (void**)mstatic_apReturns;
		m_bDelete = FALSE;
	}
	else
	{
		m_apReturns = new void*[m_dwNumItems];
		m_bDelete = TRUE;
	}

	return (fread(m_apReturns, sizeof(void*), m_dwNumItems, f) != 0);
}



void CAllocRecord::Dump(FILE* f) const
{
	fwrite(&m_dwTotalAlloc, sizeof(DWORD), 1, f);
	fwrite(&m_dwNumTimes, sizeof(DWORD), 1, f);
	m_Stack.Dump(f);
    DWORD dwNumBuffers = m_apBuffers.Size();
    fwrite(&dwNumBuffers, sizeof(DWORD), 1, f);
    fwrite(m_apBuffers.GetArrayPtr(), sizeof(void*), dwNumBuffers, f);
}

void CAllocRecord::Subtract(CAllocRecord& Other)
{
    m_dwTotalAlloc -= Other.m_dwTotalAlloc;
    m_dwNumTimes -= Other.m_dwNumTimes;
    for(int i = 0; i < m_apBuffers.Size(); i++)
    {
        for(int j = 0; j < Other.m_apBuffers.Size(); j++)
            if(Other.m_apBuffers[j] == m_apBuffers[i])
                break;
        if(j < Other.m_apBuffers.Size())
        {
            m_apBuffers.RemoveAt(i);
            i--;
        }
    }
}

CTls CStackContinuation::mtls_CurrentCont;
CStackContinuation* CStackContinuation::Set(CStackContinuation* pNew)
{
    CStackContinuation* pPrev = (CStackContinuation*)(void*)mtls_CurrentCont;
    mtls_CurrentCont = pNew;
	if(pNew)
	{
		void* p;
		__asm
		{
			mov eax, [ebp]
			mov eax, [eax+4]
			mov p, eax
		}
		pNew->m_pThisStackEnd = p;
	}
    return pPrev;
}
    
CStackContinuation* CStackContinuation::Get()
{
    CStackContinuation* pPrev = (CStackContinuation*)(void*)mtls_CurrentCont;
    return pPrev;
}
