//===-- MICmdCmdData.cpp ----------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

//++
// File:		MICmdCmdData.cpp
//
// Overview:	CMICmdCmdDataEvaluateExpression		implementation.
//				CMICmdCmdDataDisassemble			implementation.
//				CMICmdCmdDataReadMemoryBytes		implementation.
//				CMICmdCmdDataReadMemory				implementation.
//				CMICmdCmdDataListRegisterNames		implementation.
//				CMICmdCmdDataListRegisterValues		implementation.
//				CMICmdCmdDataListRegisterChanged	implementation.
//				CMICmdCmdDataWriteMemoryBytes		implementation.
//				CMICmdCmdDataWriteMemory			implementation.
//
// Environment:	Compilers:	Visual C++ 12.
//							gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
//				Libraries:	See MIReadmetxt. 
//
// Copyright:	None.
//--

// Third Party Headers:
#include <lldb/API/SBThread.h>
#include <lldb/API/SBInstruction.h>
#include <lldb/API/SBInstructionList.h>
#include <lldb/API/SBStream.h>

// In-house headers:
#include "MICmnConfig.h"
#include "MICmdCmdData.h"
#include "MICmnMIResultRecord.h"
#include "MICmnMIValueConst.h"
#include "MICmnLLDBDebugger.h"
#include "MICmnLLDBDebugSessionInfo.h"
#include "MICmnLLDBProxySBValue.h"
#include "MICmdArgContext.h"
#include "MICmdArgValNumber.h"
#include "MICmdArgValString.h"
#include "MICmdArgValThreadGrp.h"
#include "MICmdArgValOptionLong.h"
#include "MICmdArgValOptionShort.h"
#include "MICmdArgValListOfN.h"
#include "MICmdArgValConsume.h"
#include "MICmnLLDBDebugSessionInfoVarObj.h"

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataEvaluateExpression constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataEvaluateExpression::CMICmdCmdDataEvaluateExpression( void )
:	m_bExpressionValid( true )
,	m_bEvaluatedExpression( true )
,	m_strValue( "??" )
,	m_bCompositeVarType( false )
,	m_constStrArgThread( "thread" )
,	m_constStrArgFrame( "frame" )
,	m_constStrArgExpr( "expr" )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-evaluate-expression";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataEvaluateExpression::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataEvaluateExpression destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataEvaluateExpression::~CMICmdCmdDataEvaluateExpression( void )
{
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The parses the command line options 
//			arguments to extract values for each of those arguments.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataEvaluateExpression::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgExpr, true, true, true, true ) ) );
	CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
	if( bOk && !m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
		return MIstatus::failure;
	}

	return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataEvaluateExpression::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgExpr, String, m_constStrArgExpr );

	const CMIUtilString & rExpression( pArgExpr->GetValue() );
	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
	lldb::SBThread thread = rProcess.GetSelectedThread();
	m_bExpressionValid = (thread.GetNumFrames() > 0);
	if( !m_bExpressionValid )
		return MIstatus::success;
	
	lldb::SBFrame frame = thread.GetSelectedFrame();
	lldb::SBValue value = frame.EvaluateExpression( rExpression.c_str() );
	if( !value.IsValid() )
		value = frame.FindVariable( rExpression.c_str() );
	if( !value.IsValid() )
	{
		m_bEvaluatedExpression = false;
		return MIstatus::success;
	}

	MIuint64 nNumber = 0;
	if( CMICmnLLDBProxySBValue::GetValueAsUnsigned( value, nNumber ) == MIstatus::success )
	{
		const lldb::ValueType eValueType = value.GetValueType(); MIunused( eValueType );
		m_strValue = (value.GetValue() != nullptr) ? value.GetValue() : "??";

		CMIUtilString strCString;
		if( CMICmnLLDBProxySBValue::GetCString( value, strCString ) )
		{
			m_strValue += CMIUtilString::Format( " '%s'", strCString.c_str() );
		}
		return MIstatus::success;
	}

	// Composite type i.e. struct
	m_bCompositeVarType = true;
	MIuint nChild = value.GetNumChildren();
	for( MIuint i = 0; i < nChild; i++ )
	{
		lldb::SBValue member = value.GetChildAtIndex( i );
		const bool bValid = member.IsValid();
		CMIUtilString strType( MIRSRC( IDS_WORD_UNKNOWNTYPE_BRKTS ) );
		if( bValid )
		{
			const CMIUtilString strValue( CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted( member, CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Natural ) );
			const char * pTypeName = member.GetName();
			if( pTypeName != nullptr )
				strType = pTypeName;

			// MI print "{variable = 1, variable2 = 3, variable3 = 5}"
			const bool bNoQuotes = true;
			const CMICmnMIValueConst miValueConst( strValue, bNoQuotes );
			const bool bUseSpaces = true;
			const CMICmnMIValueResult miValueResult( strType, miValueConst, bUseSpaces );
			m_miValueTuple.Add( miValueResult, bUseSpaces );
		}
	}
		
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataEvaluateExpression::Acknowledge( void )
{
	if( m_bExpressionValid )
	{
		if( m_bEvaluatedExpression )
		{
			if( m_bCompositeVarType )
			{
				const CMICmnMIValueConst miValueConst( m_miValueTuple.GetString() );
				const CMICmnMIValueResult miValueResult( "value", miValueConst );
				const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
				m_miResultRecord = miRecordResult;
				return MIstatus::success;
			}
			
			const CMICmnMIValueConst miValueConst( m_strValue );
			const CMICmnMIValueResult miValueResult( "value", miValueConst );
			const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
			m_miResultRecord = miRecordResult;
			return MIstatus::success;
		}

		const CMICmnMIValueConst miValueConst( "could not evaluate expression" );
		const CMICmnMIValueResult miValueResult( "msg", miValueConst );
		const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
		m_miResultRecord = miRecordResult;
		return MIstatus::success;
	}

	const CMICmnMIValueConst miValueConst( "invalid expression" );
	const CMICmnMIValueResult miValueResult( "msg", miValueConst );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
	m_miResultRecord = miRecordResult;
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataEvaluateExpression::CreateSelf( void )
{
	return new CMICmdCmdDataEvaluateExpression();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataDisassemble constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataDisassemble::CMICmdCmdDataDisassemble( void )
:	m_constStrArgThread( "thread" )
,	m_constStrArgAddrStart( "s" )	
,	m_constStrArgAddrEnd( "e" )	
,	m_constStrArgConsume( "--" )
,	m_constStrArgMode( "mode" )	
,	m_miValueList( true )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-disassemble";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataDisassemble::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataDisassemble destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataDisassemble::~CMICmdCmdDataDisassemble( void )
{
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The parses the command line options 
//			arguments to extract values for each of those arguments.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataDisassemble::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgAddrEnd, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValConsume( m_constStrArgConsume, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgMode, true, true ) ) );
	CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
	if( bOk && !m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
		return MIstatus::failure;
	}

	return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataDisassemble::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
	CMICMDBASE_GETOPTION( pArgAddrStart, OptionShort, m_constStrArgAddrStart );
	CMICMDBASE_GETOPTION( pArgAddrEnd, OptionShort, m_constStrArgAddrEnd );
	CMICMDBASE_GETOPTION( pArgMode, Number, m_constStrArgMode );

	// Retrieve the --thread option's thread ID (only 1)
	MIuint64 nThreadId = UINT64_MAX;
	if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_THREAD_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
		return MIstatus::failure;
	}
	CMIUtilString strAddrStart;
	if( !pArgAddrStart->GetExpectedOption< CMICmdArgValString, CMIUtilString >( strAddrStart ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_START_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrStart.c_str() ) );
		return MIstatus::failure;
	}
	MIint64 nAddrStart = 0;
	if( !strAddrStart.ExtractNumber( nAddrStart ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_START_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrStart.c_str() ) );
		return MIstatus::failure;
	}
	
	CMIUtilString strAddrEnd;
	if( !pArgAddrEnd->GetExpectedOption< CMICmdArgValString, CMIUtilString >( strAddrEnd ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_END_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str() ) );
		return MIstatus::failure;
	}
	MIint64 nAddrEnd = 0;
	if( !strAddrEnd.ExtractNumber( nAddrEnd ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_END_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str() ) );
		return MIstatus::failure;
	}
	const MIuint nDisasmMode = pArgMode->GetValue();

	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBTarget & rTarget = rSessionInfo.m_lldbTarget;
	lldb::addr_t lldbStartAddr = static_cast< lldb::addr_t >( nAddrStart );
	lldb::SBInstructionList instructions = rTarget.ReadInstructions( lldb::SBAddress( lldbStartAddr, rTarget ), nAddrEnd - nAddrStart );
	const MIuint nInstructions = instructions.GetSize();
	for( size_t i = 0; i < nInstructions; i++ )
	{
		const MIchar * pUnknown = "??";
		lldb::SBInstruction instrt = instructions.GetInstructionAtIndex( i );
		const MIchar * pStrMnemonic = instrt.GetMnemonic( rTarget );
		pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown;
		lldb::SBAddress address = instrt.GetAddress();
		lldb::addr_t addr = address.GetLoadAddress( rTarget );
		const MIchar * pFnName = address.GetFunction().GetName();
		pFnName = (pFnName != nullptr) ? pFnName : pUnknown;
		lldb::addr_t addrOffSet = address.GetOffset();
		const MIchar * pStrOperands = instrt.GetOperands( rTarget );
		pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown;

		// MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}"
		const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "0x%08llx", addr ) );
		const CMICmnMIValueResult miValueResult( "address", miValueConst );
		CMICmnMIValueTuple miValueTuple( miValueResult );
		const CMICmnMIValueConst miValueConst2( pFnName );
		const CMICmnMIValueResult miValueResult2( "func-name", miValueConst2 );
		miValueTuple.Add( miValueResult2 );
		const CMICmnMIValueConst miValueConst3( CMIUtilString::Format( "0x%lld", addrOffSet ) );
		const CMICmnMIValueResult miValueResult3( "offset", miValueConst3 );
		miValueTuple.Add( miValueResult3 );
		const CMICmnMIValueConst miValueConst4( CMIUtilString::Format( "%s %s", pStrMnemonic, pStrOperands ) );
		const CMICmnMIValueResult miValueResult4( "inst", miValueConst4 );
		miValueTuple.Add( miValueResult4 );
		
		if( nDisasmMode == 1 )
		{
			lldb::SBLineEntry lineEntry = address.GetLineEntry();
			const MIuint nLine = lineEntry.GetLine();
			const MIchar * pFileName = lineEntry.GetFileSpec().GetFilename();
			pFileName = (pFileName != nullptr) ? pFileName : pUnknown;

			// MI "src_and_asm_line={line=\"%u\",file=\"%s\",line_asm_insn=[ ]}"
			const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "0x%u", nLine ) );
			const CMICmnMIValueResult miValueResult( "line", miValueConst );
			CMICmnMIValueTuple miValueTuple2( miValueResult );
			const CMICmnMIValueConst miValueConst2( pFileName );
			const CMICmnMIValueResult miValueResult2( "file", miValueConst2 );
			miValueTuple2.Add( miValueResult2 );		
			const CMICmnMIValueList miValueList( miValueTuple );
			const CMICmnMIValueResult miValueResult3( "line_asm_insn", miValueList );
			miValueTuple2.Add( miValueResult3 );
			const CMICmnMIValueResult miValueResult4( "src_and_asm_line", miValueTuple2 );
			m_miValueList.Add( miValueResult4 );
		}
		else
		{
			m_miValueList.Add( miValueTuple );
		}
	}

	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataDisassemble::Acknowledge( void )
{
	const CMICmnMIValueResult miValueResult( "asm_insns", m_miValueList );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
	m_miResultRecord = miRecordResult;
				
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataDisassemble::CreateSelf( void )
{
	return new CMICmdCmdDataDisassemble();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataReadMemoryBytes constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataReadMemoryBytes::CMICmdCmdDataReadMemoryBytes( void )
:	m_constStrArgThread( "thread" )
,	m_constStrArgByteOffset( "o" )	
,	m_constStrArgAddrStart( "address" )	
,	m_constStrArgNumBytes( "count" )	
,	m_pBufferMemory( nullptr )
,	m_nAddrStart( 0 )
,	m_nAddrNumBytesToRead( 0 )
,	m_nAddrOffset( 0 )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-read-memory-bytes";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataReadMemoryBytes::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataReadMemoryBytes destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataReadMemoryBytes::~CMICmdCmdDataReadMemoryBytes( void )
{
	if( m_pBufferMemory != nullptr )
	{
		delete [] m_pBufferMemory;
		m_pBufferMemory = nullptr;
	}
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The parses the command line options 
//			arguments to extract values for each of those arguments.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataReadMemoryBytes::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgAddrStart, true, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumBytes, true, true ) ) );
	CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
	if( bOk && !m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
		return MIstatus::failure;
	}

	return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataReadMemoryBytes::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgAddrStart, Number, m_constStrArgAddrStart );
	CMICMDBASE_GETOPTION( pArgAddrOffset, Number, m_constStrArgByteOffset );
	CMICMDBASE_GETOPTION( pArgNumBytes, Number, m_constStrArgNumBytes );

	const MIuint64 nAddrStart = pArgAddrStart->GetValue(); 
	const MIuint64 nAddrNumBytes = pArgNumBytes->GetValue();
	if( pArgAddrOffset->GetFound() )
		m_nAddrOffset = pArgAddrOffset->GetValue();
	
	m_pBufferMemory = new MIuchar[ nAddrNumBytes ];
	if( m_pBufferMemory == nullptr )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_MEMORY_ALLOC_FAILURE ), m_cmdData.strMiCmd.c_str(), nAddrNumBytes ) );
		return MIstatus::failure;
	}
	
	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
	lldb::SBError error;
	const MIuint64 nReadBytes = rProcess.ReadMemory( static_cast< lldb::addr_t >( nAddrStart ), (void *) m_pBufferMemory, nAddrNumBytes, error );
	if( nReadBytes != nAddrNumBytes )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK ), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart ) );
		return MIstatus::failure;
	}
	if( error.Fail() )
	{
		lldb::SBStream err;
		const bool bOk = error.GetDescription( err ); MIunused( bOk );
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES ), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart, err.GetData() ) );
		return MIstatus::failure;
	}

	m_nAddrStart = nAddrStart;
	m_nAddrNumBytesToRead = nAddrNumBytes;
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataReadMemoryBytes::Acknowledge( void )
{
	// MI: memory=[{begin=\"0x%08x\",offset=\"0x%08x\",end=\"0x%08x\",contents=\" \" }]"
	const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "0x%08x", m_nAddrStart ) );
	const CMICmnMIValueResult miValueResult( "begin", miValueConst );
	CMICmnMIValueTuple miValueTuple( miValueResult );
	const CMICmnMIValueConst miValueConst2( CMIUtilString::Format( "0x%08x", m_nAddrOffset ) );
	const CMICmnMIValueResult miValueResult2( "offset", miValueConst2 );
	miValueTuple.Add( miValueResult2 ); 
	const CMICmnMIValueConst miValueConst3( CMIUtilString::Format( "0x%08x", m_nAddrStart + m_nAddrNumBytesToRead ) );
	const CMICmnMIValueResult miValueResult3( "end", miValueConst3 );
	miValueTuple.Add( miValueResult3 );

	// MI: contents=\" \"
	CMIUtilString strContent;
	strContent.reserve( (m_nAddrNumBytesToRead << 1) + 1 );
	for( MIuint64 i = 0; i < m_nAddrNumBytesToRead; i ++ )
	{
		strContent += CMIUtilString::Format( "%02x", m_pBufferMemory[ i ] );
	}
	const CMICmnMIValueConst miValueConst4( strContent );
	const CMICmnMIValueResult miValueResult4( "contents", miValueConst4 );
	miValueTuple.Add( miValueResult4 );
	const CMICmnMIValueList miValueList( miValueTuple );
	const CMICmnMIValueResult miValueResult5( "memory", miValueList );
	
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult5 );
	m_miResultRecord = miRecordResult;
				
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataReadMemoryBytes::CreateSelf( void )
{
	return new CMICmdCmdDataReadMemoryBytes();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataReadMemory constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataReadMemory::CMICmdCmdDataReadMemory( void )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-read-memory";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataReadMemory::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataReadMemory destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataReadMemory::~CMICmdCmdDataReadMemory( void )
{
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataReadMemory::Execute( void )
{
	// Do nothing - command deprecated use "data-read-memory-bytes" command
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataReadMemory::Acknowledge( void )
{
	// Command CMICmdCmdSupportListFeatures sends "data-read-memory-bytes" which causes this command not to be called
	const CMICmnMIValueConst miValueConst( MIRSRC( IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED ) );
	const CMICmnMIValueResult miValueResult( "msg", miValueConst );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
	m_miResultRecord = miRecordResult;
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataReadMemory::CreateSelf( void )
{
	return new CMICmdCmdDataReadMemory();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataListRegisterNames constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataListRegisterNames::CMICmdCmdDataListRegisterNames( void )
:	m_constStrArgThreadGroup( "thread-group" )
,	m_constStrArgRegNo( "regno" )
,	m_miValueList( true )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-list-register-names";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataListRegisterNames::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataReadMemoryBytes destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataListRegisterNames::~CMICmdCmdDataListRegisterNames( void )
{
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The parses the command line options 
//			arguments to extract values for each of those arguments.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterNames::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThreadGroup, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgRegNo, false, false, CMICmdArgValListBase::eArgValType_Number ) ) );
	CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
	if( bOk && !m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
		return MIstatus::failure;
	}

	return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterNames::Execute( void )
{
	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
	if( !rProcess.IsValid() )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_PROCESS ), m_cmdData.strMiCmd.c_str() ) );
		return MIstatus::failure;
	}
	
	lldb::SBThread thread = rProcess.GetSelectedThread();
	lldb::SBFrame frame = thread.GetSelectedFrame();
	lldb::SBValueList registers = frame.GetRegisters();
	const MIuint nRegisters = registers.GetSize();
	for( MIuint i = 0; i < nRegisters; i++ )
	{
		lldb::SBValue value = registers.GetValueAtIndex( i );
		const MIchar * pRegName = value.GetName();
		const MIchar * pUnknown = "??";
		pRegName = (pRegName != nullptr) ? pRegName : pUnknown;
		const MIuint nRegChildren = value.GetNumChildren();
		for( MIuint j = 0; j < nRegChildren; j++ )
		{
			lldb::SBValue value2 = value.GetChildAtIndex( j );
			if( value2.IsValid() )
			{
				const MIchar * pRegName = value2.GetName();
				pRegName = (pRegName != nullptr) ? pRegName : pUnknown;
				const CMICmnMIValueConst miValueConst( pRegName );
				m_miValueList.Add( miValueConst );
			}
		}
	}
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterNames::Acknowledge( void )
{
	const CMICmnMIValueResult miValueResult( "register-names", m_miValueList );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
	m_miResultRecord = miRecordResult;
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataListRegisterNames::CreateSelf( void )
{
	return new CMICmdCmdDataListRegisterNames();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataListRegisterValues constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataListRegisterValues::CMICmdCmdDataListRegisterValues( void )
:	m_constStrArgThread( "thread" )
,	m_constStrArgSkip( "skip-unavailable" )
,	m_constStrArgFormat( "fmt" )
,	m_constStrArgRegNo( "regno" )
,	m_miValueList( true )
,	m_pProcess( nullptr )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-list-register-values";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataListRegisterValues::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataListRegisterValues destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataListRegisterValues::~CMICmdCmdDataListRegisterValues( void )
{
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The parses the command line options 
//			arguments to extract values for each of those arguments.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterValues::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgSkip, false, false ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgFormat, true, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgRegNo, false, true, CMICmdArgValListBase::eArgValType_Number ) ) );
	CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
	if( bOk && !m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
		return MIstatus::failure;
	}

	return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterValues::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgFormat, String, m_constStrArgFormat );
	CMICMDBASE_GETOPTION( pArgRegNo, ListOfN, m_constStrArgRegNo );
	
	const CMIUtilString & rStrFormat( pArgFormat->GetValue() );
	if( rStrFormat.length() != 1 )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_FORMAT_TYPE ), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str() ) );
		return MIstatus::failure;
	}
	const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat = CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar( rStrFormat[ 0 ] );
	if( eFormat == CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_FORMAT_TYPE ), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str() ) );
		return MIstatus::failure;
	}

	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
	if( !rProcess.IsValid() )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_PROCESS ), m_cmdData.strMiCmd.c_str() ) );
		return MIstatus::failure;
	}
	m_pProcess = &rProcess;

	const CMICmdArgValListBase::VecArgObjPtr_t & rVecRegNo( pArgRegNo->GetExpectedOptions() );
	CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin();
	while( it != rVecRegNo.end() )
	{
		const CMICmdArgValNumber * pRegNo = static_cast< CMICmdArgValNumber * >( *it );
		const MIuint nReg = pRegNo->GetValue();
		lldb::SBValue regValue = GetRegister( nReg );
		const CMIUtilString strRegValue( CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted( regValue, eFormat ) );

		const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%u", nReg ) );
		const CMICmnMIValueResult miValueResult( "number", miValueConst );
		CMICmnMIValueTuple miValueTuple( miValueResult );
		const CMICmnMIValueConst miValueConst2( strRegValue );
		const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
		miValueTuple.Add( miValueResult2 );
		m_miValueList.Add( miValueTuple );

		// Next
		++it;
	}
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterValues::Acknowledge( void )
{
	const CMICmnMIValueResult miValueResult( "register-values", m_miValueList );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
	m_miResultRecord = miRecordResult;
				
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataListRegisterValues::CreateSelf( void )
{
	return new CMICmdCmdDataListRegisterValues();
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Method.
// Args:	None.
// Return:	lldb::SBValue - LLDB SBValue object.
// Throws:	None.
//--
lldb::SBValue CMICmdCmdDataListRegisterValues::GetRegister( const MIuint vRegisterIndex ) const
{
	lldb::SBThread thread = m_pProcess->GetSelectedThread();
	lldb::SBFrame frame = thread.GetSelectedFrame();
	lldb::SBValueList registers = frame.GetRegisters();
	const MIuint nRegisters = registers.GetSize();
	for( MIuint i = 0; i < nRegisters; i++ )
	{
		lldb::SBValue value = registers.GetValueAtIndex( i );
		const MIuint nRegChildren = value.GetNumChildren();
		if( nRegChildren > 0 )
		{
			lldb::SBValue value2 = value.GetChildAtIndex( vRegisterIndex );
			if( value2.IsValid() )
			{
				return value2;
			}
		}
	}

	return lldb::SBValue();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataListRegisterChanged constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataListRegisterChanged::CMICmdCmdDataListRegisterChanged( void )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-list-changed-registers";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataListRegisterChanged::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataListRegisterChanged destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataListRegisterChanged::~CMICmdCmdDataListRegisterChanged( void )
{
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterChanged::Execute( void )
{
	// Do nothing
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataListRegisterChanged::Acknowledge( void )
{
	const CMICmnMIValueConst miValueConst( MIRSRC( IDS_WORD_NOT_IMPLEMENTED ) );
	const CMICmnMIValueResult miValueResult( "msg", miValueConst );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
	m_miResultRecord = miRecordResult;

	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataListRegisterChanged::CreateSelf( void )
{
	return new CMICmdCmdDataListRegisterChanged();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataWriteMemoryBytes constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataWriteMemoryBytes::CMICmdCmdDataWriteMemoryBytes( void )
:	m_constStrArgThread( "thread" )
,	m_constStrArgAddr( "address" )	
,	m_constStrArgContents( "contents" )	
,	m_constStrArgCount( "count" )	
,	m_nAddr( 0 )
,	m_nCount( 0 )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-write-memory-bytes";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataWriteMemoryBytes::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataWriteMemoryBytes destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataWriteMemoryBytes::~CMICmdCmdDataWriteMemoryBytes( void )
{
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The parses the command line options 
//			arguments to extract values for each of those arguments.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataWriteMemoryBytes::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgAddr, true, true, false, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgContents, true, true, true, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgCount, false, true, false, true ) ) );
	CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
	if( bOk && !m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
		return MIstatus::failure;
	}

	return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataWriteMemoryBytes::Execute( void )
{
	// Do nothing - not reproduceable (yet) in Eclipse
	//CMICMDBASE_GETOPTION( pArgOffset, OptionShort, m_constStrArgOffset );
	//CMICMDBASE_GETOPTION( pArgAddr, String, m_constStrArgAddr );
	//CMICMDBASE_GETOPTION( pArgNumber, String, m_constStrArgNumber );
	//CMICMDBASE_GETOPTION( pArgContents, String, m_constStrArgContents );
	// 
	// Numbers extracts as string types as they could be hex numbers
	// '&' is not recognised and so has to be removed

	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataWriteMemoryBytes::Acknowledge( void )
{
	const CMICmnMIValueConst miValueConst( MIRSRC( IDS_WORD_NOT_IMPLEMENTED ) );
	const CMICmnMIValueResult miValueResult( "msg", miValueConst );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
	m_miResultRecord = miRecordResult;

	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataWriteMemoryBytes::CreateSelf( void )
{
	return new CMICmdCmdDataWriteMemoryBytes();
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataWriteMemory constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataWriteMemory::CMICmdCmdDataWriteMemory( void )
:	m_constStrArgThread( "thread" )
,	m_constStrArgOffset( "o" )
,	m_constStrArgAddr( "address" )	
,	m_constStrArgD( "d" )
,	m_constStrArgNumber( "a number" )
,	m_constStrArgContents( "contents" )	
,	m_nAddr( 0 )
,	m_nCount( 0 )
,	m_pBufferMemory( nullptr )	
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "data-write-memory";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdDataWriteMemory::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdDataWriteMemory destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdDataWriteMemory::~CMICmdCmdDataWriteMemory( void )
{
	if( m_pBufferMemory != nullptr )
	{
		delete [] m_pBufferMemory;
		m_pBufferMemory = nullptr;
	}
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The parses the command line options 
//			arguments to extract values for each of those arguments.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataWriteMemory::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgOffset, false, true,  CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgAddr, true, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgD, true, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumber, true, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgContents, true, true ) ) );
	CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
	if( bOk && !m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
		return MIstatus::failure;
	}

	return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command does work in this function.
//			The command is likely to communicate with the LLDB SBDebugger in here.
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataWriteMemory::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgOffset, OptionShort, m_constStrArgOffset );
	CMICMDBASE_GETOPTION( pArgAddr, Number, m_constStrArgAddr );
	CMICMDBASE_GETOPTION( pArgNumber, Number, m_constStrArgNumber );
	CMICMDBASE_GETOPTION( pArgContents, Number, m_constStrArgContents );

	MIuint nAddrOffset = 0;
	if( pArgOffset->GetFound() && !pArgOffset->GetExpectedOption< CMICmdArgValNumber, MIuint>( nAddrOffset ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_VALIDATION_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddr.c_str() ) );
		return MIstatus::failure;
	}
	m_nAddr = pArgAddr->GetValue();
	m_nCount = pArgNumber->GetValue();
	const MIuint64 nValue = pArgContents->GetValue();

	m_pBufferMemory = new MIuchar [ m_nCount ];
	if( m_pBufferMemory == nullptr )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_MEMORY_ALLOC_FAILURE ), m_cmdData.strMiCmd.c_str(), m_nCount ) );
		return MIstatus::failure;
	}
	*m_pBufferMemory = static_cast< MIchar >( nValue );

	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
	lldb::SBError error;
	lldb::addr_t addr = static_cast< lldb::addr_t >( m_nAddr + nAddrOffset );
	const size_t nBytesWritten = rProcess.WriteMemory( addr, (const void *) m_pBufferMemory, (size_t) m_nCount, error ); 
	if( nBytesWritten != static_cast< size_t >( m_nCount ) )
	{
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK ), m_cmdData.strMiCmd.c_str(), m_nCount, addr ) );
		return MIstatus::failure;
	}
	if( error.Fail() )
	{
		lldb::SBStream err;
		const bool bOk = error.GetDescription( err ); MIunused( bOk );
		SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES ), m_cmdData.strMiCmd.c_str(), m_nCount, addr, err.GetData() ) );
		return MIstatus::failure;
	}
	
	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	The invoker requires this function. The command prepares a MI Record Result
//			for the work carried out in the Execute().
// Type:	Overridden.
// Args:	None.
// Return:	MIstatus::success - Functional succeeded.
//			MIstatus::failure - Functional failed.
// Throws:	None.
//--
bool CMICmdCmdDataWriteMemory::Acknowledge( void )
{
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
	m_miResultRecord = miRecordResult;

	return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details:	Required by the CMICmdFactory when registering *this command. The factory
//			calls this function to create an instance of *this command.
// Type:	Static method.
// Args:	None.
// Return:	CMICmdBase * - Pointer to a new command.
// Throws:	None.
//--
CMICmdBase * CMICmdCmdDataWriteMemory::CreateSelf( void )
{
	return new CMICmdCmdDataWriteMemory();
}
