aboutsummaryrefslogtreecommitdiff
path: root/tools/lldb-mi/MICmdInvoker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lldb-mi/MICmdInvoker.cpp')
-rw-r--r--tools/lldb-mi/MICmdInvoker.cpp333
1 files changed, 333 insertions, 0 deletions
diff --git a/tools/lldb-mi/MICmdInvoker.cpp b/tools/lldb-mi/MICmdInvoker.cpp
new file mode 100644
index 000000000000..41f9f77542a3
--- /dev/null
+++ b/tools/lldb-mi/MICmdInvoker.cpp
@@ -0,0 +1,333 @@
+//===-- MICmdInvoker.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdInvoker.cpp
+//
+// Overview: CMICmdInvoker implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdInvoker.h"
+#include "MICmdBase.h"
+#include "MICmdMgr.h"
+#include "MICmnLog.h"
+#include "MICmnStreamStdout.h"
+#include "MIDriver.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdInvoker constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdInvoker::CMICmdInvoker( void )
+: m_rStreamOut( CMICmnStreamStdout::Instance() )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdInvoker destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdInvoker::~CMICmdInvoker( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Command Invoker.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = true;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ CmdDeleteAll();
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Empty the map of invoked commands doing work. Command objects are deleted too.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdInvoker::CmdDeleteAll( void )
+{
+ CMICmdMgr & rMgr = CMICmdMgr::Instance();
+ MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
+ while( it != m_mapCmdIdToCmd.end() )
+ {
+ const MIuint cmdId( (*it).first ); MIunused( cmdId );
+ CMICmdBase * pCmd = (*it).second;
+ const CMIUtilString & rCmdName( pCmd->GetCmdData().strMiCmd ); MIunused( rCmdName );
+ rMgr.CmdDelete( pCmd->GetCmdData() );
+
+ // Next
+ ++it;
+ }
+ m_mapCmdIdToCmd.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove from the map of invoked commands doing work a command that has finished
+// its work. The command object is deleted too.
+// Type: Method.
+// Args: vId - (R) Command object's unique ID.
+// vbYesDeleteCmd - (R) True = Delete command object, false = delete via the Command Manager.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdDelete( const MIuint vId, const bool vbYesDeleteCmd /*= false*/ )
+{
+ CMICmdMgr & rMgr = CMICmdMgr::Instance();
+ MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find( vId );
+ if( it != m_mapCmdIdToCmd.end() )
+ {
+ CMICmdBase * pCmd = (*it).second;
+ if( vbYesDeleteCmd )
+ {
+ // Via registered interest command manager callback *this object to delete the command
+ m_mapCmdIdToCmd.erase( it );
+ delete pCmd;
+ }
+ else
+ // Notify other interested object of this command's pending deletion
+ rMgr.CmdDelete( pCmd->GetCmdData() );
+ }
+
+ if( m_mapCmdIdToCmd.empty() )
+ rMgr.CmdUnregisterForDeleteNotification( *this );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add to the map of invoked commands doing work a command that is about to
+// start to do work.
+// Type: Method.
+// Args: vCmd - (R) Command object.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdAdd( const CMICmdBase & vCmd )
+{
+ if( m_mapCmdIdToCmd.empty() )
+ {
+ CMICmdMgr & rMgr = CMICmdMgr::Instance();
+ rMgr.CmdRegisterForDeleteNotification( *this );
+ }
+
+ const MIuint & cmdId( vCmd.GetCmdData().id );
+ MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find( cmdId );
+ if( it != m_mapCmdIdToCmd.end() )
+ return MIstatus::success;
+
+ MapPairCmdIdToCmd_t pr( cmdId, const_cast< CMICmdBase *>( &vCmd ));
+ m_mapCmdIdToCmd.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Having previously had the potential command validated and found valid now
+// get the command executed.
+// If the Functionalityity returns MIstatus::failure call GetErrorDescription().
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: vCmd - (RW) Command object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdExecute( CMICmdBase & vCmd )
+{
+ bool bOk = CmdAdd( vCmd );
+
+ if( bOk && !vCmd.ParseArgs() )
+ {
+ // Report command execution failed
+ const SMICmdData cmdData( vCmd.GetCmdData() );
+ CmdStdout( cmdData );
+ CmdCauseAppExit( vCmd );
+ CmdDelete( cmdData.id );
+
+ // Proceed to wait or execute next command
+ return MIstatus::success;
+ }
+
+ if( bOk && !vCmd.Execute() )
+ {
+ // Report command execution failed
+ const SMICmdData cmdData( vCmd.GetCmdData() );
+ CmdStdout( cmdData );
+ CmdCauseAppExit( vCmd );
+ CmdDelete( cmdData.id );
+
+ // Proceed to wait or execute next command
+ return MIstatus::success;
+ }
+
+ bOk = CmdExecuteFinished( vCmd );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Called when a command has finished its Execution() work either synchronously
+// because the command executed was the type a non event type or asynchronoulsy
+// via the command's callback (because of an SB Listener event). Needs to be called
+// so that *this invoker call do some house keeping and then proceed to call
+// the command's Acknowledge() function.
+// Type: Method.
+// Args: vCmd - (R) Command object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdExecuteFinished( CMICmdBase & vCmd )
+{
+ // Command finished now get the command to gather it's information and form the MI
+ // Result record
+ if( !vCmd.Acknowledge() )
+ {
+ // Report command acknowledge functionality failed
+ const SMICmdData cmdData( vCmd.GetCmdData() );
+ CmdStdout( cmdData );
+ CmdCauseAppExit( vCmd );
+ CmdDelete( cmdData.id );
+
+ // Proceed to wait or execute next command
+ return MIstatus::success;
+ }
+
+ // Retrieve the command's latest data/information. Needed for commands of the event type so have
+ // a record of commands pending finishing execution.
+ const CMIUtilString & rMIResultRecord( vCmd.GetMIResultRecord() );
+ SMICmdData cmdData( vCmd.GetCmdData() ); // Make a copy as the command will be deleted soon
+ cmdData.strMiCmdResultRecord = rMIResultRecord; // Precautionary copy as the command might forget to do this
+ if( vCmd.HasMIResultRecordExtra() )
+ {
+ cmdData.bHasResultRecordExtra = true;
+ const CMIUtilString & rMIExtra( vCmd.GetMIResultRecordExtra() );
+ cmdData.strMiCmdResultRecordExtra = rMIExtra; // Precautionary copy as the command might forget to do this
+ }
+
+ // Send command's MI response to the client
+ bool bOk = CmdStdout( cmdData );
+
+ // Delete the command object as do not require anymore
+ bOk = bOk && CmdDelete( vCmd.GetCmdData().id );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: If the MI Driver is not operating via a client i.e. Eclipse check the command
+// on failure suggests the application exits. A command can be such that a
+// failure cannot the allow the application to continue operating.
+// Args: vCmd - (R) Command object.
+// Return: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdInvoker::CmdCauseAppExit( const CMICmdBase & vCmd ) const
+{
+ if( vCmd.GetExitAppOnCommandFailure() )
+ {
+ CMIDriver & rDriver( CMIDriver::Instance() );
+ if( rDriver.IsDriverDebuggingArgExecutable() )
+ {
+ rDriver.SetExitApplicationFlag( true );
+ }
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write to stdout and the Log file the command's MI formatted result.
+// Type: vCmdData - (R) A command's information.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdStdout( const SMICmdData & vCmdData ) const
+{
+ bool bOk = m_pLog->WriteLog( vCmdData.strMiCmdAll );
+ const bool bLock = bOk && m_rStreamOut.Lock();
+ bOk = bOk && bLock && m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecord );
+ if( bOk && vCmdData.bHasResultRecordExtra )
+ {
+ bOk = m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecordExtra );
+ }
+ bOk = bLock && m_rStreamOut.Unlock();
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is registered
+// with the Command Manager to receive callbacks when a command is being deleted.
+// An object, *this invoker, does not delete a command object itself but calls
+// the Command Manager to delete a command object. This function is the Invoker's
+// called.
+// The Invoker owns the command objects and so can delete them but must do it
+// via the manager so other objects can be notified of the deletion.
+// Type: Method.
+// Args: vCmd - (RW) Command.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdInvoker::Delete( SMICmdData & vCmd )
+{
+ CmdDelete( vCmd.id, true );
+}