Source

gb_emulator / gb_debugger_msvs / stack_frame.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 <iomanip>
#include <sstream>

#include <boost/scoped_array.hpp>

#include "disassembly_stream.h"
#include "expression_context.h"
#include "stack_frame.h"

namespace fs = boost::filesystem;
using boost::shared_ptr;
using std::dec;
using std::hex;
using std::setfill;
using std::setw;
using std::wostringstream;
using std::wstring;

// IDebugStackFrame2 methods

HRESULT CGbVsStackFrame::GetCodeContext(IDebugCodeContext2 **ppCodeCxt)
{
	*ppCodeCxt = codeContext_;
	(*ppCodeCxt)->AddRef();

	return S_OK;
}

HRESULT CGbVsStackFrame::GetDocumentContext(IDebugDocumentContext2 **ppCxt)
{
	if (documentContext_)
	{
		*ppCxt = documentContext_;
		(*ppCxt)->AddRef();
		return S_OK;
	}
	else
	{
		return E_FAIL;
	}
}

HRESULT CGbVsStackFrame::GetName(BSTR * /*pbstrName*/)
{
	return E_NOTIMPL;
}

HRESULT CGbVsStackFrame::GetInfo(FRAMEINFO_FLAGS dwFieldSpec, UINT nRadix, FRAMEINFO *pFrameInfo)
{
	PopulateFrameInfo(pFrameInfo, dwFieldSpec, nRadix);
	return S_OK;
}

HRESULT CGbVsStackFrame::GetPhysicalStackRange(UINT64 * /*paddrMin*/, UINT64 * /*paddrMax*/)
{
	return E_NOTIMPL;
}

HRESULT CGbVsStackFrame::GetExpressionContext(IDebugExpressionContext2 **ppExprCxt)
{
	CComObject<CExpressionContext> *context;
	CComObject<CExpressionContext>::CreateInstance(&context);
	context->AddRef();
	context->Init(frame_);

	*ppExprCxt = context;
	return S_OK;
}

HRESULT CGbVsStackFrame::GetLanguageInfo(BSTR *pbstrLanguage, GUID *pguidLanguage)
{
	// {4BC19A8F-8423-4A8B-89CC-EE95FE9FBBB2}
	static const GUID assemblyGuid =
		{ 0x4bc19a8f, 0x8423, 0x4a8b, { 0x89, 0xcc, 0xee, 0x95, 0xfe, 0x9f, 0xbb, 0xb2 } };

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

	switch (frame_->sourceLocation.line->language)
	{
	case CdbFile::ASSEMBLY:
		*pbstrLanguage = SysAllocString(L"Assembly");
		*pguidLanguage = assemblyGuid;
		break;
	case CdbFile::C:
		*pbstrLanguage = SysAllocString(L"C");
		*pguidLanguage = guidCLang;
		break;
	default:
		assert(!"all languages should have been handled");
	}

	return S_OK;
}

HRESULT CGbVsStackFrame::GetDebugProperty(IDebugProperty2 **ppDebugProp)
{
	if (!ppDebugProp)
	{
		return E_POINTER;
	}

	*ppDebugProp = properties_;
	(*ppDebugProp)->AddRef();
	return S_OK;
}

HRESULT CGbVsStackFrame::EnumProperties(
	DEBUGPROP_INFO_FLAGS dwFields,
	UINT nRadix,
	const GUID &guidFilter,
	DWORD dwTimeout,
	ULONG *pcelt,
	IEnumDebugPropertyInfo2 **ppepi)
{
	if (!pcelt || !ppepi)
	{
		return E_POINTER;
	}

	HRESULT hr = properties_->EnumChildren(dwFields, nRadix, guidFilter, DBG_ATTRIB_ALL, NULL,
		dwTimeout, ppepi);

	if (hr == S_OK)
	{
		hr = (*ppepi)->GetCount(pcelt);
		return hr;
	}
	else
	{
		*pcelt = 0;
		*ppepi = NULL;
		return hr;
	}
}

HRESULT CGbVsStackFrame::GetThread(IDebugThread2 ** /*ppThread*/)
{
	return E_NOTIMPL;
}

// CGbVsStackFrame methods

void CGbVsStackFrame::Init(shared_ptr<GbStackFrame> frame, CCodeContext *codeContext,
	CDocumentContext *documentContext)
{
	frame_ = frame;
	codeContext_ = codeContext;
	codeContext_->AddRef();
	documentContext_ = documentContext;

	CComObject<CFrameProperty> *properties;
	CComObject<CFrameProperty>::CreateInstance(&properties);
	properties_ = properties;
	properties_->Init(frame_);

	CComObject<CGbVsModule> *module;
	CComObject<CGbVsModule>::CreateInstance(&module);
	module_ = module;
	module_->Init(frame_->module);
}

void CGbVsStackFrame::PopulateFrameInfo(FRAMEINFO *frameInfo, FRAMEINFO_FLAGS fields, UINT)
{
	memset(frameInfo, 0, sizeof(*frameInfo));
	fs::path module = frame_->module.first.filename();

	if (fields & FIF_FUNCNAME)
	{
		// Format the function name
		wostringstream oss;
		oss << setfill(L'0');

		// Module
		if (fields & FIF_FUNCNAME_MODULE)
		{
			oss << module.native() << L"!";
		}

		// Function name (or address if not available)
		if (frame_->hasDebugInfo && frame_->sourceLocation.function)
		{
			CComBSTR str(frame_->sourceLocation.function->name.c_str());
			oss << str.m_str;
		}
		else
		{
			oss << hex << setw(6) << frame_->functionAddr;
		}
		oss << L"()";

		// Offset
		if (fields & FIF_FUNCNAME_LINES && frame_->hasDebugInfo)
		{
			oss << dec << L"  Line " << frame_->sourceLocation.line->line + 1;
			if (fields & FIF_FUNCNAME_OFFSET && frame_->sourceLocation.lineOffset)
			{
				if (frame_->sourceLocation.lineOffset > 0)
				{
					oss << hex << L" + 0x" << frame_->sourceLocation.lineOffset << L" bytes";
				}
				else
				{
					oss << hex << L" - 0x" << -frame_->sourceLocation.lineOffset << L" bytes";
				}
			}
		}
		else if (fields & FIF_FUNCNAME_OFFSET && frame_->functionAddr != frame_->instructionAddr)
		{
			int64_t offset;
			if (frame_->hasDebugInfo)
			{
				offset = frame_->sourceLocation.functionOffset;
			}
			else
			{
				offset = frame_->instructionAddr - frame_->functionAddr;
			}

			if (offset > 0)
			{
				oss << hex << L"  + 0x" << offset << L" bytes";
			}
			else if (offset < 0)
			{
				oss << hex << L"  - 0x" << -offset << L" bytes";
			}
		}

		wstring functionName = oss.str();

		frameInfo->m_dwValidFields |= FIF_FUNCNAME;
		frameInfo->m_bstrFuncName = SysAllocString(functionName.c_str());
	}
	if (fields & FIF_LANGUAGE && frame_->hasDebugInfo && frame_->sourceLocation.line)
	{
		frameInfo->m_dwValidFields |= FIF_LANGUAGE;
		switch (frame_->sourceLocation.line->language)
		{
		case CdbFile::ASSEMBLY:
			frameInfo->m_bstrLanguage = SysAllocString(L"Assembly");
			break;
		case CdbFile::C:
			frameInfo->m_bstrLanguage = SysAllocString(L"C");
			break;
		default:
			assert(!"all languages should have been handled");
		}
	}
	if (fields & FIF_MODULE)
	{
		frameInfo->m_dwValidFields |= FIF_MODULE;
		frameInfo->m_bstrModule = SysAllocString(module.c_str());
	}
	if (fields & FIF_STACKRANGE)
	{
		frameInfo->m_dwValidFields |= FIF_STACKRANGE;
		frameInfo->m_addrMin = frame_->stackAddrMin;
		frameInfo->m_addrMax = frame_->stackAddrMax;
	}
	if (fields & FIF_FRAME)
	{
		frameInfo->m_dwValidFields |= FIF_FRAME;
		frameInfo->m_pFrame = this;
		frameInfo->m_pFrame->AddRef();
	}
	if (fields & FIF_DEBUGINFO)
	{
		frameInfo->m_dwValidFields |= FIF_DEBUGINFO;
		frameInfo->m_fHasDebugInfo = frame_->hasDebugInfo;
	}
	if (fields & FIF_DEBUG_MODULEP)
	{
		frameInfo->m_dwValidFields |= FIF_DEBUG_MODULEP;
		frameInfo->m_pModule = module_;
		frameInfo->m_pModule->AddRef();
	}
}