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

//++
// File:		MICmdCmdStack.cpp
//
// Overview:	CMICmdCmdStackInfoDepth			implementation.
//				CMICmdCmdStackListFrames		implementation.
//				CMICmdCmdStackListArguments		implementation.
//				CMICmdCmdStackListLocals		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>

// In-house headers:
#include "MICmnConfig.h"
#include "MICmdCmdStack.h"
#include "MICmnMIResultRecord.h"
#include "MICmnMIValueConst.h"
#include "MICmnMIOutOfBandRecord.h"
#include "MICmnLLDBDebugger.h"
#include "MICmnLLDBDebugSessionInfo.h"
#include "MICmdArgContext.h"
#include "MICmdArgValNumber.h"
#include "MICmdArgValString.h"
#include "MICmdArgValThreadGrp.h"
#include "MICmdArgValOptionLong.h"
#include "MICmdArgValOptionShort.h"
#include "MICmdArgValListOfN.h"

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackInfoDepth constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackInfoDepth::CMICmdCmdStackInfoDepth( void )
:	m_nThreadFrames( 0 )
,	m_constStrArgThread( "thread" )
,	m_constStrArgMaxDepth( "max-depth" )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "stack-info-depth";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdStackInfoDepth::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackInfoDepth destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackInfoDepth::~CMICmdCmdStackInfoDepth( 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 CMICmdCmdStackInfoDepth::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgMaxDepth, false, false ) ) );
	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 CMICmdCmdStackInfoDepth::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
	CMICMDBASE_GETOPTION( pArgMaxDepth, Number, m_constStrArgMaxDepth );
	
	// 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_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
		return MIstatus::failure;
	}

	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	m_nThreadFrames = rSessionInfo.m_lldbProcess.GetThreadByIndexID( nThreadId ).GetNumFrames();

	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 CMICmdCmdStackInfoDepth::Acknowledge( void )
{
	const CMIUtilString strDepth( CMIUtilString::Format( "%d", m_nThreadFrames ) );
	const CMICmnMIValueConst miValueConst( strDepth );
	const CMICmnMIValueResult miValueResult( "depth", miValueConst );
	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 * CMICmdCmdStackInfoDepth::CreateSelf( void )
{
	return new CMICmdCmdStackInfoDepth();
}

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

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackListFrames constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackListFrames::CMICmdCmdStackListFrames( void )
:	m_nThreadFrames( 0 )
,	m_constStrArgThread( "thread" )
,	m_constStrArgFrameLow( "low-frame" )
,	m_constStrArgFrameHigh( "high-frame" )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "stack-list-frames";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdStackListFrames::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackListFrames destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackListFrames::~CMICmdCmdStackListFrames( void )
{
	m_vecMIValueResult.clear();
}

//++ ------------------------------------------------------------------------------------
// 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 CMICmdCmdStackListFrames::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgFrameLow, false, true ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgFrameHigh, 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 CMICmdCmdStackListFrames::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
	CMICMDBASE_GETOPTION( pArgFrameLow, Number, m_constStrArgFrameLow );
	CMICMDBASE_GETOPTION( pArgFrameHigh, Number, m_constStrArgFrameHigh );
	
	// 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_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
		return MIstatus::failure;
	}

	// Frame low and high options are not mandatory
	MIuint nFrameHigh = pArgFrameHigh->GetFound() ? pArgFrameHigh->GetValue() : UINT64_MAX;
	const MIuint nFrameLow = pArgFrameLow->GetFound() ? pArgFrameLow->GetValue() : 0;

	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBThread thread = rSessionInfo.m_lldbProcess.GetThreadByIndexID( nThreadId );
	MIuint nThreadFrames = thread.GetNumFrames();

	// Adjust nThreadFrames for the nFrameHigh argument as we use nFrameHigh+1 in the min calc as the arg
    // is not an index, but a frame id value.
    if( nFrameHigh < UINT32_MAX )
	{
		nFrameHigh++;
		nThreadFrames = (nFrameHigh < nThreadFrames) ? nFrameHigh : nThreadFrames;
	}

	m_nThreadFrames = nThreadFrames;
	if( nThreadFrames == 0 )
		return MIstatus::success;

	m_vecMIValueResult.clear();
	for( MIuint nLevel = nFrameLow; nLevel < nThreadFrames; nLevel++ )
	{
		CMICmnMIValueTuple miValueTuple;
		if( !rSessionInfo.MIResponseFormFrameInfo( thread, nLevel, miValueTuple ) )
			return MIstatus::failure;

		const CMICmnMIValueResult miValueResult8( "frame", miValueTuple );
		m_vecMIValueResult.push_back( miValueResult8 );		
	}
	
	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 CMICmdCmdStackListFrames::Acknowledge( void )
{
	if( m_nThreadFrames == 0 )
	{
		// MI print "3^done,stack=[{}]"
		const CMICmnMIValueTuple miValueTuple;
		const CMICmnMIValueList miValueList( miValueTuple );
		const CMICmnMIValueResult miValueResult( "stack", miValueList );
		const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
		m_miResultRecord = miRecordResult;

		return MIstatus::success;
	}

	// Build up a list of thread information from tuples
	VecMIValueResult_t::const_iterator it = m_vecMIValueResult.begin();
	if( it == m_vecMIValueResult.end() )
	{
		// MI print "3^done,stack=[{}]"
		const CMICmnMIValueTuple miValueTuple;
		const CMICmnMIValueList miValueList( miValueTuple );
		const CMICmnMIValueResult miValueResult( "stack", miValueList );
		const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
		m_miResultRecord = miRecordResult;
		return MIstatus::success;
	}
	CMICmnMIValueList miValueList( *it );
	++it;
	while( it != m_vecMIValueResult.end() )
	{
		const CMICmnMIValueResult & rTuple( *it );
		miValueList.Add( rTuple );

		// Next
		++it;
	}
	const CMICmnMIValueResult miValueResult( "stack", 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 * CMICmdCmdStackListFrames::CreateSelf( void )
{
	return new CMICmdCmdStackListFrames();
}

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

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackListArguments constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackListArguments::CMICmdCmdStackListArguments( void )
:	m_bThreadInvalid( false )
,	m_miValueList( true )
,	m_constStrArgThread( "thread" )
,	m_constStrArgPrintValues( "print-values" )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "stack-list-arguments";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdStackListArguments::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackListArguments destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackListArguments::~CMICmdCmdStackListArguments( 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 CMICmdCmdStackListArguments::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
	bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgPrintValues, true, false ) ) );
	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 CMICmdCmdStackListArguments::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
	CMICMDBASE_GETOPTION( pArgPrintValues, Number, m_constStrArgPrintValues );

	// Retrieve the --thread option's thread ID (only 1)
	MIuint64 nThreadId = UINT64_MAX;
	if( pArgThread->GetFound() )
	{
		if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
		{
			SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
			return MIstatus::failure;
		}
	}

	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
	lldb::SBThread thread;
	if( nThreadId == UINT64_MAX )
		thread = rProcess.GetSelectedThread();
	else
		thread = rProcess.GetThreadByIndexID( nThreadId );
	m_bThreadInvalid = !thread.IsValid();
	if( m_bThreadInvalid )
		return MIstatus::success;

	const lldb::StopReason eStopReason = thread.GetStopReason();
	if( (eStopReason == lldb::eStopReasonNone) || (eStopReason == lldb::eStopReasonInvalid) )
	{
		m_bThreadInvalid = true;
		return MIstatus::success;
	}
	
	lldb::SBFrame frame = thread.GetFrameAtIndex( 0 );
	CMICmnMIValueList miValueList( true );
	const MIuint vMaskVarTypes = 0x1000;
	if( !rSessionInfo.MIResponseFormVariableInfo( frame, vMaskVarTypes, miValueList ) )
		return MIstatus::failure;

	m_miValueList = miValueList; 

	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 CMICmdCmdStackListArguments::Acknowledge( void )
{
	if( m_bThreadInvalid )
	{
		// MI print "%s^done,stack-args=[]"
		const CMICmnMIValueList miValueList( true );
		const CMICmnMIValueResult miValueResult( "stack-args", miValueList );
		const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
		m_miResultRecord = miRecordResult;
		return MIstatus::success;
	}

	// MI print "%s^done,stack-args=[frame={level=\"0\",args=[%s]}]"
	const CMICmnMIValueConst miValueConst( "0" );
	const CMICmnMIValueResult miValueResult( "level", miValueConst );
	CMICmnMIValueTuple miValueTuple( miValueResult );
	const CMICmnMIValueResult miValueResult2( "args", m_miValueList );
	miValueTuple.Add( miValueResult2 );
	const CMICmnMIValueResult miValueResult3( "frame", miValueTuple );
	const CMICmnMIValueList miValueList( miValueResult3 );
	const CMICmnMIValueResult miValueResult4( "stack-args", miValueList );
	const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult4 );
	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 * CMICmdCmdStackListArguments::CreateSelf( void )
{
	return new CMICmdCmdStackListArguments();
}

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

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackListLocals constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackListLocals::CMICmdCmdStackListLocals( void )
:	m_bThreadInvalid( false )
,	m_miValueList( true )
,	m_constStrArgThread( "thread" )
,	m_constStrArgFrame( "frame" )
,	m_constStrArgPrintValues( "print-values" )
{
	// Command factory matches this name with that received from the stdin stream
	m_strMiCmd = "stack-list-locals";
	
	// Required by the CMICmdFactory when registering *this command
	m_pSelfCreatorFn = &CMICmdCmdStackListLocals::CreateSelf;
}

//++ ------------------------------------------------------------------------------------
// Details:	CMICmdCmdStackListLocals destructor.
// Type:	Overrideable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmdCmdStackListLocals::~CMICmdCmdStackListLocals( 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 CMICmdCmdStackListLocals::ParseArgs( void )
{
	bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, true, 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 CMICmdArgValNumber( m_constStrArgPrintValues, true, false ) ) );
	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 CMICmdCmdStackListLocals::Execute( void )
{
	CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
	CMICMDBASE_GETOPTION( pArgPrintValues, Number, m_constStrArgPrintValues );

	// Retrieve the --thread option's thread ID (only 1)
	MIuint64 nThreadId = UINT64_MAX;
	if( pArgThread->GetFound() )
	{
		if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
		{
			SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
			return MIstatus::failure;
		}
	}

	CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
	lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
	lldb::SBThread thread;
	if( nThreadId == UINT64_MAX )
		thread = rProcess.GetSelectedThread();
	else
		thread = rProcess.GetThreadByIndexID( nThreadId );
	m_bThreadInvalid = !thread.IsValid();
	if( m_bThreadInvalid )
		return MIstatus::success;

	const lldb::StopReason eStopReason = thread.GetStopReason();
	if( (eStopReason == lldb::eStopReasonNone) || (eStopReason == lldb::eStopReasonInvalid) )
	{
		m_bThreadInvalid = true;
		return MIstatus::success;
	}
	
	lldb::SBFrame frame = thread.GetFrameAtIndex( 0 );
	CMICmnMIValueList miValueList( true );
	const MIuint vMaskVarTypes = 0x0100;
	if( !rSessionInfo.MIResponseFormVariableInfo( frame, vMaskVarTypes, miValueList ) )
		return MIstatus::failure;

	m_miValueList = miValueList;

	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 CMICmdCmdStackListLocals::Acknowledge( void )
{
	if( m_bThreadInvalid )
	{
		// MI print "%s^done,locals=[]"
		const CMICmnMIValueList miValueList( true );
		const CMICmnMIValueResult miValueResult( "locals", miValueList );
		const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
		m_miResultRecord = miRecordResult;
		return MIstatus::success;
	}

	// MI print "%s^done,locals=[%s]"
	const CMICmnMIValueResult miValueResult( "locals", 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 * CMICmdCmdStackListLocals::CreateSelf( void )
{
	return new CMICmdCmdStackListLocals();
}

