#include "StdAfx.h"
#include "VBoxTarget.h"
#include "registers-i386.h"

using namespace GDBServerFoundation;
using namespace VBoxGDB;


VBoxGDB::VBoxTarget32::VBoxTarget32( VBoxClient *pClient, bool own )
	: m_pClient(pClient)
	, m_bOwn(own)
{
	pClient->RequestStopAsync();
	pClient->WaitForStop();
}

VBoxGDB::VBoxTarget32::~VBoxTarget32()
{
	if (m_bOwn)
		delete m_pClient;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::ReadTargetRegisters( int threadID, RegisterSetContainer &registers )
{
	std::map<BazisLib::DynamicStringA, ULONGLONG> rawRegs = m_pClient->ReadRegisters();
	if (rawRegs.empty())
		return kGDBUnknownError;

	for (size_t i = 0; i < i386::RegisterList.RegisterCount; i++)
	{
		std::map<BazisLib::DynamicStringA, ULONGLONG>::iterator it = rawRegs.find(i386::RegisterList.Registers[i].RegisterName);
		if (it == rawRegs.end())
			continue;
		registers[i386::RegisterList.Registers[i].RegisterIndex] = RegisterValue((unsigned)it->second, i386::RegisterList.Registers[i].SizeInBits / 8);
	}
	
	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::WriteTargetRegisters( int threadID, const RegisterSetContainer &registers )
{
	for (size_t i = 0; i < i386::RegisterList.RegisterCount; i++)
	{
		if (registers[i].Valid)
			if (!m_pClient->WriteRegister(i386::RegisterList.Registers[i].RegisterName, registers[i].ToUInt32()))
				return kGDBUnknownError;
	}

	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::ReadTargetMemory( ULONGLONG Address, void *pBuffer, size_t *pSizeInBytes )
{
	if (!Address)
		return kGDBUnknownError;
	if (!m_pClient->ReadMemory(Address, pBuffer, pSizeInBytes))
		return kGDBUnknownError;
	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::WriteTargetMemory( ULONGLONG Address, const void *pBuffer, size_t sizeInBytes )
{
	if (!Address)
		return kGDBUnknownError;
	if (!m_pClient->WriteMemory(Address, pBuffer, sizeInBytes))
		return kGDBUnknownError;
	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::GetLastStopRecord( TargetStopRecord *pRec )
{
	pRec->ThreadID = 0;
	pRec->Reason = kSignalReceived;
	pRec->Extension.SignalNumber = SIGTRAP;
	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::ResumeAndWait( int threadID )
{
	if (!m_pClient->ContinueAndWait())
		return kGDBUnknownError;
	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::Step( int threadID )
{
	if (!m_pClient->StepAndWait())
		return kGDBUnknownError;
	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::SendBreakInRequestAsync()
{
	m_pClient->RequestStopAsync();
	return kGDBSuccess;
}

const PlatformRegisterList * VBoxGDB::VBoxTarget32::GetRegisterList()
{
	return &GDBServerFoundation::i386::RegisterList;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::ExecuteRemoteCommand( const std::string &command, std::string &output )
{
	std::vector<BazisLib::DynamicStringA> result = m_pClient->ExecuteCommand(command.c_str());
	for (size_t i = 0; i < result.size(); i++)
	{
		output += result[i].c_str();
		output += "\n";
	}
	return kGDBSuccess;
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::CreateBreakpoint( BreakpointType type, ULONGLONG Address, unsigned kind, OUT INT_PTR *pCookie )
{
	int bpID;
	switch(type)
	{
	case bptSoftwareBreakpoint:
		bpID = m_pClient->CreateBreakpoint(Address);
		if (bpID == -1)
			return kGDBUnknownError;
		*pCookie = bpID;
		return kGDBSuccess;
	default:
		return kGDBNotSupported;
	}
}

GDBServerFoundation::GDBStatus VBoxGDB::VBoxTarget32::RemoveBreakpoint( BreakpointType type, ULONGLONG Address, INT_PTR Cookie )
{
	switch(type)
	{
	case bptSoftwareBreakpoint:
		if (!m_pClient->RemoveBreakpoint(Cookie))
			return kGDBUnknownError;
		return kGDBSuccess;
	default:
		return kGDBNotSupported;
	}
}

void VBoxGDB::VBoxTarget32::CloseSessionSafely()
{
	m_pClient->Disconnect();
}

