diff options
Diffstat (limited to 'tools/lldb-mi/MICmdCmdMiscellanous.cpp')
-rw-r--r-- | tools/lldb-mi/MICmdCmdMiscellanous.cpp | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/tools/lldb-mi/MICmdCmdMiscellanous.cpp b/tools/lldb-mi/MICmdCmdMiscellanous.cpp new file mode 100644 index 000000000000..b09f585598a4 --- /dev/null +++ b/tools/lldb-mi/MICmdCmdMiscellanous.cpp @@ -0,0 +1,588 @@ +//===-- 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. +// CMICmdCmdInferiorTtySet 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 "MICmdCmdMiscellanous.h" +#include "MICmnMIResultRecord.h" +#include "MICmnMIValueConst.h" +#include "MICmnMIOutOfBandRecord.h" +#include "MICmnLLDBDebugger.h" +#include "MICmnLLDBDebugSessionInfo.h" +#include "MIDriverBase.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 ) ) ); + return (bOk && ParseValidateCmdOptions() ); +} + +//++ ------------------------------------------------------------------------------------ +// 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.MIResponseFormThreadInfo2( 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() ); + if (rSessionInfo.m_lldbProcess.IsValid ()) + { + 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() ); + if (rSessionInfo.m_lldbProcess.IsValid ()) + { + 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 ); + } + + if (rSessionInfo.m_lldbTarget.IsValid ()) + { + 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 ) ) ); + return (bOk && ParseValidateCmdOptions() ); +} + +//++ ------------------------------------------------------------------------------------ +// 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 ); + + // Handle the interpreter parameter by do nothing on purpose (set to 'handled' in + // the arg definition above) + const CMIUtilString & rStrInterpreter( pArgInterpreter->GetValue() ); MIunused( rStrInterpreter ); + + const CMIUtilString & rStrCommand( pArgCommand->GetValue() ); + CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); + const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand( rStrCommand.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 ); + + // Send the LLDB result message to console so the user can see the result of the + // command they typed. It is not necessary an error message. + CMICmnStreamStderr::LLDBMsgToConsole( strMsg ); + } + if( m_lldbResult.GetErrorSize() > 0 ) + { + CMIUtilString strMsg( m_lldbResult.GetError() ); + strMsg = strMsg.StripCREndOfLine(); + CMICmnStreamStderr::LLDBMsgToConsole( strMsg ); + + // Send LLDB's error message to the MI Driver's Log file + CMICmnStreamStdout::TextToStdout( 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(); +} + +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdInferiorTtySet constructor. +// Type: Method. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdInferiorTtySet::CMICmdCmdInferiorTtySet( void ) +{ + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "inferior-tty-set"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdInferiorTtySet::CreateSelf; +} + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdInferiorTtySet destructor. +// Type: Overrideable. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdInferiorTtySet::~CMICmdCmdInferiorTtySet( 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 CMICmdCmdInferiorTtySet::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 CMICmdCmdInferiorTtySet::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 * CMICmdCmdInferiorTtySet::CreateSelf( void ) +{ + return new CMICmdCmdInferiorTtySet(); +} |