| //===-- MICmdCmdMiscellanous.cpp --------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| //++ |
| // File: MICmdCmdMiscellanous.cpp |
| // |
| // Overview: CMICmdCmdGdbExit implementation. |
| // CMICmdCmdListThreadGroups implementation. |
| // CMICmdCmdInterpreterExec 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/SBCommandInterpreter.h> |
| #include <lldb/API/SBThread.h> |
| |
| // In-house headers: |
| #include "MICmnConfig.h" |
| #include "MICmdCmdMiscellanous.h" |
| #include "MICmnMIResultRecord.h" |
| #include "MICmnMIValueConst.h" |
| #include "MICmnMIOutOfBandRecord.h" |
| #include "MICmnLLDBDebugger.h" |
| #include "MICmnLLDBDebugSessionInfo.h" |
| #include "MIDriverBase.h" |
| #include "MICmdArgContext.h" |
| #include "MICmdArgValFile.h" |
| #include "MICmdArgValNumber.h" |
| #include "MICmdArgValString.h" |
| #include "MICmdArgValThreadGrp.h" |
| #include "MICmdArgValOptionLong.h" |
| #include "MICmdArgValOptionShort.h" |
| #include "MICmdArgValListOfN.h" |
| #include "MICmnStreamStdout.h" |
| #include "MICmnStreamStderr.h" |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMICmdCmdGdbExit constructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmdCmdGdbExit::CMICmdCmdGdbExit( void ) |
| { |
| // Command factory matches this name with that received from the stdin stream |
| m_strMiCmd = "gdb-exit"; |
| |
| // Required by the CMICmdFactory when registering *this command |
| m_pSelfCreatorFn = &CMICmdCmdGdbExit::CreateSelf; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMICmdCmdGdbExit destructor. |
| // Type: Overrideable. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmdCmdGdbExit::~CMICmdCmdGdbExit( 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 CMICmdCmdGdbExit::Execute( void ) |
| { |
| CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag( true ); |
| const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); |
| // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() |
| |
| 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 CMICmdCmdGdbExit::Acknowledge( void ) |
| { |
| const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Exit ); |
| m_miResultRecord = miRecordResult; |
| |
| // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger |
| // Give the client '=thread-group-exited,id="i1"' |
| m_bHasResultRecordExtra = true; |
| const CMICmnMIValueConst miValueConst2( "i1" ); |
| const CMICmnMIValueResult miValueResult2( "id", miValueConst2 ); |
| const CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupExited, miValueResult2 ); |
| m_miResultRecordExtra = miOutOfBand.GetString(); |
| |
| 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 * CMICmdCmdGdbExit::CreateSelf( void ) |
| { |
| return new CMICmdCmdGdbExit(); |
| } |
| |
| //--------------------------------------------------------------------------------------- |
| //--------------------------------------------------------------------------------------- |
| //--------------------------------------------------------------------------------------- |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMICmdCmdListThreadGroups constructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmdCmdListThreadGroups::CMICmdCmdListThreadGroups( void ) |
| : m_bIsI1( false ) |
| , m_bHaveArgOption( false ) |
| , m_bHaveArgRecurse( false ) |
| , m_constStrArgNamedAvailable( "available" ) |
| , m_constStrArgNamedRecurse( "recurse" ) |
| , m_constStrArgNamedGroup( "group" ) |
| , m_constStrArgNamedThreadGroup( "i1" ) |
| { |
| // Command factory matches this name with that received from the stdin stream |
| m_strMiCmd = "list-thread-groups"; |
| |
| // Required by the CMICmdFactory when registering *this command |
| m_pSelfCreatorFn = &CMICmdCmdListThreadGroups::CreateSelf; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMICmdCmdListThreadGroups destructor. |
| // Type: Overrideable. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmdCmdListThreadGroups::~CMICmdCmdListThreadGroups( void ) |
| { |
| m_vecMIValueTuple.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 CMICmdCmdListThreadGroups::ParseArgs( void ) |
| { |
| bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedAvailable, false, true ) ) ); |
| bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedRecurse, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) ); |
| bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgNamedGroup, false, true, CMICmdArgValListBase::eArgValType_Number ) ) ); |
| bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValThreadGrp( m_constStrArgNamedThreadGroup, 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. |
| // Synopis: -list-thread-groups [ --available ] [ --recurse 1 ] [ group ... ] |
| // This command does not follow the MI documentation exactly. Has an extra |
| // argument "i1" to handle. |
| // Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Miscellaneous-Commands.html#GDB_002fMI-Miscellaneous-Commands |
| // Type: Overridden. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMICmdCmdListThreadGroups::Execute( void ) |
| { |
| if( m_setCmdArgs.IsArgContextEmpty() ) |
| // No options so "top level thread groups" |
| return MIstatus::success; |
| |
| CMICMDBASE_GETOPTION( pArgAvailable, OptionLong, m_constStrArgNamedAvailable ); |
| CMICMDBASE_GETOPTION( pArgRecurse, OptionLong, m_constStrArgNamedRecurse ); |
| CMICMDBASE_GETOPTION( pArgThreadGroup, ThreadGrp, m_constStrArgNamedThreadGroup ); |
| |
| // Got some options so "threads" |
| if( pArgAvailable->GetFound() ) |
| { |
| if( pArgRecurse->GetFound() ) |
| { |
| m_bHaveArgRecurse = true; |
| return MIstatus::success; |
| } |
| |
| m_bHaveArgOption = true; |
| return MIstatus::success; |
| } |
| // "i1" as first argument (pos 0 of possible arg) |
| if( !pArgThreadGroup->GetFound() ) |
| return MIstatus::success; |
| m_bIsI1 = true; |
| |
| CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); |
| lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess; |
| |
| // Note do not check for rProcess is IsValid(), continue |
| |
| m_vecMIValueTuple.clear(); |
| const MIuint nThreads = rProcess.GetNumThreads(); |
| for( MIuint i = 0; i < nThreads; i++ ) |
| { |
| // GetThreadAtIndex() uses a base 0 index |
| // GetThreadByIndexID() uses a base 1 index |
| lldb::SBThread thread = rProcess.GetThreadAtIndex( i ); |
| |
| if( thread.IsValid() ) |
| { |
| CMICmnMIValueTuple miTuple; |
| if( !rSessionInfo.MIResponseFormThreadInfo( m_cmdData, thread, miTuple ) ) |
| return MIstatus::failure; |
| |
| m_vecMIValueTuple.push_back( miTuple ); |
| } |
| } |
| |
| 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 CMICmdCmdListThreadGroups::Acknowledge( void ) |
| { |
| if( m_bHaveArgOption ) |
| { |
| if( m_bHaveArgRecurse ) |
| { |
| const CMICmnMIValueConst miValueConst( MIRSRC( IDS_WORD_NOT_IMPLEMENTED_BRKTS ) ); |
| const CMICmnMIValueResult miValueResult( "msg", miValueConst ); |
| const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult ); |
| m_miResultRecord = miRecordResult; |
| |
| return MIstatus::success; |
| } |
| |
| const CMICmnMIValueConst miValueConst1( "i1" ); |
| const CMICmnMIValueResult miValueResult1( "id", miValueConst1 ); |
| CMICmnMIValueTuple miTuple( miValueResult1 ); |
| |
| const CMICmnMIValueConst miValueConst2( "process" ); |
| const CMICmnMIValueResult miValueResult2( "type", miValueConst2 ); |
| miTuple.Add( miValueResult2 ); |
| |
| CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); |
| const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); |
| const CMIUtilString strPid( CMIUtilString::Format( "%lld", pid ) ); |
| const CMICmnMIValueConst miValueConst3( strPid ); |
| const CMICmnMIValueResult miValueResult3( "pid", miValueConst3 ); |
| miTuple.Add( miValueResult3 ); |
| |
| const CMICmnMIValueConst miValueConst4( MIRSRC( IDS_WORD_NOT_IMPLEMENTED_BRKTS ) ); |
| const CMICmnMIValueResult miValueResult4( "num_children", miValueConst4 ); |
| miTuple.Add( miValueResult4 ); |
| |
| const CMICmnMIValueConst miValueConst5( MIRSRC( IDS_WORD_NOT_IMPLEMENTED_BRKTS ) ); |
| const CMICmnMIValueResult miValueResult5( "cores", miValueConst5 ); |
| miTuple.Add( miValueResult5 ); |
| |
| const CMICmnMIValueList miValueList( miTuple ); |
| const CMICmnMIValueResult miValueResult6( "groups", miValueList ); |
| const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult6 ); |
| m_miResultRecord = miRecordResult; |
| |
| return MIstatus::success; |
| } |
| |
| if( !m_bIsI1 ) |
| { |
| const CMICmnMIValueConst miValueConst1( "i1" ); |
| const CMICmnMIValueResult miValueResult1( "id", miValueConst1 ); |
| CMICmnMIValueTuple miTuple( miValueResult1 ); |
| |
| const CMICmnMIValueConst miValueConst2( "process" ); |
| const CMICmnMIValueResult miValueResult2( "type", miValueConst2 ); |
| miTuple.Add( miValueResult2 ); |
| |
| CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); |
| const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); |
| const CMIUtilString strPid( CMIUtilString::Format( "%lld", pid ) ); |
| const CMICmnMIValueConst miValueConst3( strPid ); |
| const CMICmnMIValueResult miValueResult3( "pid", miValueConst3 ); |
| miTuple.Add( miValueResult3 ); |
| |
| lldb::SBTarget & rTrgt = rSessionInfo.m_lldbTarget; |
| const MIchar * pDir = rTrgt.GetExecutable().GetDirectory(); |
| const MIchar * pFileName = rTrgt.GetExecutable().GetFilename(); |
| const CMIUtilString strFile( CMIUtilString::Format( "%s/%s", pDir, pFileName ) ); |
| const CMICmnMIValueConst miValueConst4( strFile ); |
| const CMICmnMIValueResult miValueResult4( "executable", miValueConst4 ); |
| miTuple.Add( miValueResult4 ); |
| |
| const CMICmnMIValueList miValueList( miTuple ); |
| const CMICmnMIValueResult miValueResult5( "groups", miValueList ); |
| const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult5 ); |
| m_miResultRecord = miRecordResult; |
| return MIstatus::success; |
| } |
| |
| // Build up a list of thread information from tuples |
| VecMIValueTuple_t::const_iterator it = m_vecMIValueTuple.begin(); |
| if( it == m_vecMIValueTuple.end() ) |
| { |
| const CMICmnMIValueConst miValueConst( "[]" ); |
| const CMICmnMIValueResult miValueResult( "threads", miValueConst ); |
| const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult ); |
| m_miResultRecord = miRecordResult; |
| return MIstatus::success; |
| } |
| CMICmnMIValueList miValueList( *it ); |
| ++it; |
| while( it != m_vecMIValueTuple.end() ) |
| { |
| const CMICmnMIValueTuple & rTuple( *it ); |
| miValueList.Add( rTuple ); |
| |
| // Next |
| ++it; |
| } |
| |
| const CMICmnMIValueResult miValueResult( "threads", 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 * CMICmdCmdListThreadGroups::CreateSelf( void ) |
| { |
| return new CMICmdCmdListThreadGroups(); |
| } |
| |
| //--------------------------------------------------------------------------------------- |
| //--------------------------------------------------------------------------------------- |
| //--------------------------------------------------------------------------------------- |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMICmdCmdInterpreterExec constructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmdCmdInterpreterExec::CMICmdCmdInterpreterExec( void ) |
| : m_constStrArgNamedInterpreter( "intepreter" ) |
| , m_constStrArgNamedCommand( "command" ) |
| { |
| // Command factory matches this name with that received from the stdin stream |
| m_strMiCmd = "interpreter-exec"; |
| |
| // Required by the CMICmdFactory when registering *this command |
| m_pSelfCreatorFn = &CMICmdCmdInterpreterExec::CreateSelf; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMICmdCmdInterpreterExec destructor. |
| // Type: Overrideable. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmdCmdInterpreterExec::~CMICmdCmdInterpreterExec( 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 CMICmdCmdInterpreterExec::ParseArgs( void ) |
| { |
| bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedInterpreter, true, true ) ) ); |
| bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedCommand, 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 CMICmdCmdInterpreterExec::Execute( void ) |
| { |
| CMICMDBASE_GETOPTION( pArgInterpreter, String, m_constStrArgNamedInterpreter ); |
| CMICMDBASE_GETOPTION( pArgCommand, String, m_constStrArgNamedCommand ); |
| const CMIUtilString & rStrInterpreter( pArgInterpreter->GetValue() ); |
| const CMIUtilString & rStrCommand( pArgCommand->GetValue() ); |
| const CMIUtilString strCmd( CMIUtilString::Format( "%s %s", rStrInterpreter.c_str(), rStrCommand.c_str() ) ); |
| CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); |
| const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand( strCmd.c_str(), m_lldbResult, true ); MIunused( rtn ); |
| |
| 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 CMICmdCmdInterpreterExec::Acknowledge( void ) |
| { |
| if( m_lldbResult.GetOutputSize() > 0 ) |
| { |
| CMIUtilString strMsg( m_lldbResult.GetOutput() ); |
| strMsg = strMsg.StripCREndOfLine(); |
| CMICmnStreamStdout::TextToStdout( strMsg ); |
| } |
| if( m_lldbResult.GetErrorSize() > 0 ) |
| { |
| CMIUtilString strMsg( m_lldbResult.GetError() ); |
| strMsg = strMsg.StripCREndOfLine(); |
| CMICmnStreamStderr::TextToStderr( strMsg ); |
| } |
| |
| 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 * CMICmdCmdInterpreterExec::CreateSelf( void ) |
| { |
| return new CMICmdCmdInterpreterExec(); |
| } |