Source

gb_emulator / gb_debugger_msvs / properties / frame_property.cpp

Full commit
/*  Copyright Š 2011 Chris Spencer <spencercw@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#include "stdafx.h"

#include "frame_property.h"

#include <boost/scoped_array.hpp>
#include <boost/shared_ptr.hpp>

#include "com_enum.h"
#include "copy_debug_property_info.h"
#include "properties/register_group_property.h"
#include "properties/variable_property.h"

using boost::scoped_array;
using boost::shared_ptr;
using std::vector;

// IDebugProperty2 methods

HRESULT CFrameProperty::GetPropertyInfo(
	DEBUGPROP_INFO_FLAGS dwFields,
	DWORD nRadix,
	DWORD dwTimeout,
	IDebugReference2 **rgpArgs,
	DWORD dwArgCount,
	DEBUG_PROPERTY_INFO *pPropertyInfo)
{
	(void) nRadix;
	(void) dwTimeout;
	(void) rgpArgs;
	(void) dwArgCount;

	if (!pPropertyInfo)
	{
		return E_POINTER;
	}

	memset(pPropertyInfo, 0, sizeof(*pPropertyInfo));
	
	if (dwFields & DEBUGPROP_INFO_PROP)
	{
		pPropertyInfo->dwFields |= DEBUGPROP_INFO_PROP;
		pPropertyInfo->pProperty = this;
		pPropertyInfo->pProperty->AddRef();
	}

	return S_OK;
}

HRESULT CFrameProperty::SetValueAsString(
	const OLECHAR *pszValue,
	DWORD nRadix,
	DWORD dwTimeout)
{
	(void) pszValue;
	(void) nRadix;
	(void) dwTimeout;

	return E_NOTIMPL;
}

HRESULT CFrameProperty::SetValueAsReference(
	IDebugReference2 **rgpArgs,
	DWORD dwArgCount,
	IDebugReference2 *pValue,
	DWORD dwTimeout)
{
	(void) rgpArgs;
	(void) dwArgCount;
	(void) pValue;
	(void) dwTimeout;

	return E_NOTIMPL;
}

HRESULT CFrameProperty::EnumChildren(
	DEBUGPROP_INFO_FLAGS dwFields,
	DWORD dwRadix,
	const GUID &guidFilter,
	DBG_ATTRIB_FLAGS dwAttribFilter,
	const OLECHAR *pszNameFilter,
	DWORD dwTimeout,
	IEnumDebugPropertyInfo2 **ppEnum)
{
	(void) dwTimeout;

	if (!ppEnum)
	{
		return E_POINTER;
	}

	// Enumerate the requested type
	if (guidFilter == guidFilterRegisters || guidFilter == guidFilterAutoRegisters)
	{
		return EnumerateRegisters(dwFields, dwRadix, dwAttribFilter, pszNameFilter, ppEnum);
	}
	else if (guidFilter == guidFilterLocalsPlusArgs)
	{
		return EnumerateLocals(dwFields, dwRadix, dwAttribFilter, pszNameFilter, ppEnum);
	}
	else
	{
		*ppEnum = NULL;
		return E_NOTIMPL;
	}
}

HRESULT CFrameProperty::GetParent(IDebugProperty2 **ppParent)
{
	if (!ppParent)
	{
		return E_POINTER;
	}

	*ppParent = NULL;
	return S_GETPARENT_NO_PARENT;
}

HRESULT CFrameProperty::GetDerivedMostProperty(IDebugProperty2 **ppDerivedMost)
{
	(void) ppDerivedMost;

	return E_NOTIMPL;
}

HRESULT CFrameProperty::GetMemoryBytes(IDebugMemoryBytes2 **ppMemoryBytes)
{
	(void) ppMemoryBytes;

	return E_NOTIMPL;
}

HRESULT CFrameProperty::GetMemoryContext(IDebugMemoryContext2 **ppMemory)
{
	if (!ppMemory)
	{
		return E_POINTER;
	}

	*ppMemory = NULL;
	return S_GETMEMORYCONTEXT_NO_MEMORY_CONTEXT;
}

HRESULT CFrameProperty::GetSize(DWORD *pdwSize)
{
	(void) pdwSize;

	return E_NOTIMPL;
}

HRESULT CFrameProperty::GetReference(IDebugReference2 **ppReference)
{
	(void) ppReference;

	return E_NOTIMPL;
}

HRESULT CFrameProperty::GetExtendedInfo(const GUID &guidExtendedInfo, VARIANT *pExtendedInfo)
{
	(void) guidExtendedInfo;
	(void) pExtendedInfo;

	return E_NOTIMPL;
}

// CFrameProperty methods

void CFrameProperty::Init(shared_ptr<GbStackFrame> frame)
{
	frame_ = frame;
}

HRESULT CFrameProperty::EnumerateRegisters(DWORD fields, DWORD radix, DBG_ATTRIB_FLAGS attribFilter,
	const OLECHAR *nameFilter, IEnumDebugPropertyInfo2 **enumerator)
{
	(void) attribFilter;
	(void) nameFilter;

	// Create register categories
#define DEFINE_CATEGORY(name, strName) \
	CComObject<CRegisterGroupProperty> *name; \
	CComObject<CRegisterGroupProperty>::CreateInstance(&name); \
	name->AddRef(); \
	name->Init(strName);
		
	DEFINE_CATEGORY(cpu, L"CPU")
	DEFINE_CATEGORY(flags, L"Flags")
		
	// Get the registers and save their values
#define DEFINE_REGISTER(name, strName, width) \
	CComObject<CRegisterProperty> *name; \
	CComObject<CRegisterProperty>::CreateInstance(&name); \
	name->AddRef(); \
	name->Init(cpu, strName, frame_->registers.name, width); \
	cpu->AddRegister(name);

#define DEFINE_FLAG(name, strName, bit) \
	CComObject<CRegisterProperty> *name; \
	CComObject<CRegisterProperty>::CreateInstance(&name); \
	name->AddRef(); \
	name->Init(flags, strName, (frame_->registers.af & (1 << bit)) ? 1 : 0, 1); \
	flags->AddRegister(name);

	DEFINE_REGISTER(af, L"AF", 4)
	DEFINE_REGISTER(bc, L"BC", 4)
	DEFINE_REGISTER(de, L"DE", 4)
	DEFINE_REGISTER(hl, L"HL", 4)
	DEFINE_REGISTER(sp, L"SP", 4)
	DEFINE_REGISTER(pc, L"PC", 4)
	DEFINE_REGISTER(ime, L"IME", 1)
		
	DEFINE_FLAG(z, L"Z", 7)
	DEFINE_FLAG(n, L"N", 6)
	DEFINE_FLAG(h, L"H", 5)
	DEFINE_FLAG(c, L"C", 4)

#undef DEFINE_CATEGORY
#undef DEFINE_REGISTER
#undef DEFINE_FLAG

	DEBUG_PROPERTY_INFO properties[2];
	cpu->PopulatePropertyInfo(&properties[0], fields, radix);
	flags->PopulatePropertyInfo(&properties[1], fields, radix);

	// Create the enumerator
	typedef CComEnumWithCount<
		IEnumDebugPropertyInfo2,
		&IID_IEnumDebugPropertyInfo2,
		DEBUG_PROPERTY_INFO,
		CopyDebugPropertyInfo> CEnumDebugPropertyInfo;
	CComObject<CEnumDebugPropertyInfo> *theEnumerator;
	CComObject<CEnumDebugPropertyInfo>::CreateInstance(&theEnumerator);
	theEnumerator->AddRef();

	theEnumerator->Init(properties, properties + 2, NULL, AtlFlagCopy);
	*enumerator = theEnumerator;
		
	CopyDebugPropertyInfo::destroy(&properties[0]);
	CopyDebugPropertyInfo::destroy(&properties[1]);

	af->Release();
	bc->Release();
	de->Release();
	hl->Release();
	sp->Release();
	pc->Release();

	z->Release();
	n->Release();
	h->Release();
	c->Release();
		
	cpu->Release();
	flags->Release();

	return S_OK;
}

HRESULT CFrameProperty::EnumerateLocals(DWORD fields, DWORD radix, DBG_ATTRIB_FLAGS attribFilter,
	const OLECHAR *nameFilter, IEnumDebugPropertyInfo2 **enumerator)
{
	(void) attribFilter;
	(void) nameFilter;

	if (!frame_->hasDebugInfo || !frame_->sourceLocation.function)
	{
		return E_FAIL;
	}

	// Copy the variable data into an array of debug properties
	vector<CComPtr<CVariableProperty> > properties;
	properties.reserve(frame_->sourceLocation.function->locals.size());

	for (vector<shared_ptr<CdbFile::Symbol> >::const_iterator
		variable = frame_->sourceLocation.function->locals.begin(),
		end = frame_->sourceLocation.function->locals.end(); variable != end; ++variable)
	{
		// Create the property if the variable is in scope. Note this algorithm isn't quite
		// accurate; any variables at a lower level to the current line will appear, even if they
		// are not in scope. There is not enough information to be able to determine what blocks a
		// block resides in.
		if ((*variable)->block == frame_->sourceLocation.line->block ||
			(*variable)->level < frame_->sourceLocation.line->level)
		{
			CComObject<CVariableProperty> *variableProperty;
			CComObject<CVariableProperty>::CreateInstance(&variableProperty);
			properties.push_back(variableProperty);
			variableProperty->Init(frame_, *variable);
		}
	}

	// Populate the property info structures
	size_t propertyCount = properties.size();
	scoped_array<DEBUG_PROPERTY_INFO> propertyInfo(new DEBUG_PROPERTY_INFO[propertyCount]);
	size_t i = 0;
	for (vector<CComPtr<CVariableProperty> >::const_iterator prop = properties.begin(),
		end = properties.end(); prop != end; ++prop, ++i)
	{
		(*prop)->PopulatePropertyInfo(&propertyInfo[i], fields, radix);
	}

	// Create the enumerator
	typedef CComEnumWithCount<
		IEnumDebugPropertyInfo2,
		&IID_IEnumDebugPropertyInfo2,
		DEBUG_PROPERTY_INFO,
		CopyDebugPropertyInfo> CEnumDebugPropertyInfo;
	CComObject<CEnumDebugPropertyInfo> *theEnumerator;
	CComObject<CEnumDebugPropertyInfo>::CreateInstance(&theEnumerator);
	theEnumerator->AddRef();

	theEnumerator->Init(propertyInfo.get(), propertyInfo.get() + propertyCount, NULL, AtlFlagCopy);
	*enumerator = theEnumerator;
		
	// Clean up
	for (size_t i = 0; i != propertyCount; ++i)
	{
		CopyDebugPropertyInfo::destroy(&propertyInfo[i]);
	}

	return S_OK;
}