| //===-- MIDriver.cpp --------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| //++ |
| // File: MIDriver.cpp |
| // |
| // Overview: CMIDriver 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 <stdarg.h> // va_list, va_start, var_end |
| #include <iostream> |
| #include <lldb/API/SBError.h> |
| |
| // In-house headers: |
| #include "Driver.h" |
| #include "MIDriver.h" |
| #include "MICmnResources.h" |
| #include "MICmnLog.h" |
| #include "MICmdMgr.h" |
| #include "MICmnLLDBDebugger.h" |
| #include "MICmnMIResultRecord.h" |
| #include "MICmnMIValueConst.h" |
| #include "MICmnThreadMgrStd.h" |
| #include "MIUtilDebug.h" |
| #include "MIUtilSingletonHelper.h" |
| #include "MICmnStreamStdout.h" |
| #include "MICmnStreamStderr.h" |
| |
| // Instantiations: |
| #if _DEBUG |
| const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION_DEBUG ); |
| #else |
| const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION ); // Matches version in resources file |
| #endif // _DEBUG |
| const CMIUtilString CMIDriver::ms_constAppNameShort( MIRSRC( IDS_MI_APPNAME_SHORT ) ); |
| const CMIUtilString CMIDriver::ms_constAppNameLong( MIRSRC( IDS_MI_APPNAME_LONG ) ); |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIDriver constructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIDriver::CMIDriver( void ) |
| : m_bFallThruToOtherDriverEnabled( false ) |
| , m_bDriverIsExiting( false ) |
| , m_handleMainThread( 0 ) |
| , m_rStdin( CMICmnStreamStdin::Instance() ) |
| , m_rLldbDebugger( CMICmnLLDBDebugger::Instance() ) |
| , m_rStdOut( CMICmnStreamStdout::Instance() ) |
| , m_eCurrentDriverState( eDriverState_NotRunning ) |
| { |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIDriver destructor. |
| // Type: Overridden. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIDriver::~CMIDriver( void ) |
| { |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Set whether *this driver (the parent) is enabled to pass a command to its |
| // fall through (child) driver to interpret the command and do work instead |
| // (if *this driver decides it can't hanled the command). |
| // Type: Method. |
| // Args: vbYes - (R) True = yes fall through, false = do not pass on command. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetEnableFallThru( const bool vbYes ) |
| { |
| m_bFallThruToOtherDriverEnabled = vbYes; |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Get whether *this driver (the parent) is enabled to pass a command to its |
| // fall through (child) driver to interpret the command and do work instead |
| // (if *this driver decides it can't hanled the command). |
| // Type: Method. |
| // Args: None. |
| // Return: bool - True = yes fall through, false = do not pass on command. |
| // Throws: None. |
| //-- |
| bool CMIDriver::GetEnableFallThru( void ) const |
| { |
| return m_bFallThruToOtherDriverEnabled; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Retrieve MI's application name of itself. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString & CMIDriver::GetAppNameShort( void ) const |
| { |
| return ms_constAppNameShort; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Retrieve MI's application name of itself. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString & CMIDriver::GetAppNameLong( void ) const |
| { |
| return ms_constAppNameLong; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Retrieve MI's version description of itself. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString & CMIDriver::GetVersionDescription( void ) const |
| { |
| return ms_constMIVersion; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Initialize setup *this driver ready for use. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::Initialize( void ) |
| { |
| m_eCurrentDriverState = eDriverState_Initialising; |
| m_clientUsageRefCnt++; |
| |
| ClrErrorDescription(); |
| |
| if( m_bInitialized ) |
| return MIstatus::success; |
| |
| bool bOk = MIstatus::success; |
| CMIUtilString errMsg; |
| |
| // Initialize all of the modules we depend on |
| MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); |
| MI::ModuleInit< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg ); |
| MI::ModuleInit< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg ); |
| MI::ModuleInit< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg ); |
| MI::ModuleInit< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg ); |
| MI::ModuleInit< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg ); |
| MI::ModuleInit< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg ); |
| bOk &= m_rLldbDebugger.SetDriver( *this ); |
| MI::ModuleInit< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg ); |
| |
| #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER |
| CMIDriverMgr & rDrvMgr = CMIDriverMgr::Instance(); |
| bOk = bOk && rDrvMgr.RegisterDriver( *g_driver, "LLDB driver" ); // Will be pass thru driver |
| if( bOk ) |
| { |
| bOk = SetEnableFallThru( false ); // This is intentional at this time - yet to be fully implemented |
| bOk = bOk && SetDriverToFallThruTo( *g_driver ); |
| CMIUtilString strOtherDrvErrMsg; |
| if( bOk && GetEnableFallThru() && !g_driver->MISetup( strOtherDrvErrMsg ) ) |
| { |
| bOk = false; |
| errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_FALLTHRUDRIVER ), strOtherDrvErrMsg.c_str() ); |
| } |
| } |
| #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER |
| |
| m_bExitApp = false; |
| bOk = bOk && InitClientIDEToMIDriver(); // Init Eclipse IDE |
| |
| m_bInitialized = bOk; |
| |
| if( !bOk ) |
| { |
| const CMIUtilString msg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_DRIVER ), errMsg.c_str() ); |
| SetErrorDescription( msg ); |
| return MIstatus::failure; |
| } |
| |
| m_eCurrentDriverState = eDriverState_RunningNotDebugging; |
| |
| return bOk; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Unbind detach or release resources used by *this driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::Shutdown( void ) |
| { |
| if( --m_clientUsageRefCnt > 0 ) |
| return MIstatus::success; |
| |
| if( !m_bInitialized ) |
| return MIstatus::success; |
| |
| m_eCurrentDriverState = eDriverState_ShuttingDown; |
| |
| ClrErrorDescription(); |
| |
| bool bOk = MIstatus::success; |
| CMIUtilString errMsg; |
| |
| // Shutdown all of the modules we depend on |
| MI::ModuleShutdown< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg ); |
| MI::ModuleShutdown< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg ); |
| MI::ModuleShutdown< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg ); |
| MI::ModuleShutdown< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg ); |
| MI::ModuleShutdown< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg ); |
| MI::ModuleShutdown< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg ); |
| MI::ModuleShutdown< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg ); |
| MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); |
| |
| if( !bOk ) |
| { |
| SetErrorDescriptionn( MIRSRC( IDS_MI_SHUTDOWN_ERR ), errMsg.c_str() ); |
| } |
| |
| m_eCurrentDriverState = eDriverState_NotRunning; |
| |
| return bOk; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Work function. Client (the driver's user) is able to append their own message |
| // in to the MI's Log trace file. |
| // Type: Method. |
| // Args: vMessage - (R) Client's text message. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::WriteMessageToLog( const CMIUtilString & vMessage ) |
| { |
| CMIUtilString msg; |
| msg = CMIUtilString::Format( MIRSRC( IDS_MI_CLIENT_MSG ), vMessage.c_str() ); |
| return m_pLog->Write( msg, CMICmnLog::eLogVerbosity_ClientMsg ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CDriverMgr calls *this driver initialize setup ready for use. |
| // Type: Overridden. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoInitialize( void ) |
| { |
| return CMIDriver::Instance().Initialize(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CDriverMgr calls *this driver to unbind detach or release resources used by |
| // *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoShutdown( void ) |
| { |
| return CMIDriver::Instance().Shutdown(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Retrieve the name for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Driver name. |
| // Throws: None. |
| //-- |
| const CMIUtilString & CMIDriver::GetName( void ) const |
| { |
| const CMIUtilString & rName = GetAppNameLong(); |
| const CMIUtilString & rVsn = GetVersionDescription(); |
| static CMIUtilString strName = CMIUtilString::Format( "%s %s", rName.c_str(), rVsn.c_str() ); |
| |
| return strName; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Retrieve *this driver's last error condition. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString - Text description. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIDriver::GetError( void ) const |
| { |
| return GetErrorDescription(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Call *this driver to resize the console window. |
| // Type: Overridden. |
| // Args: vTermWidth - (R) New window column size. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| void CMIDriver::DoResizeWindow( const uint32_t vTermWidth ) |
| { |
| GetTheDebugger().SetTerminalWidth( vTermWidth ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Call *this driver to return it's debugger. |
| // Type: Overridden. |
| // Args: None. |
| // Return: lldb::SBDebugger & - LLDB debugger object reference. |
| // Throws: None. |
| //-- |
| lldb::SBDebugger & CMIDriver::GetTheDebugger( void ) |
| { |
| return m_rLldbDebugger.GetTheDebugger(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Specify another driver *this driver can call should this driver not be able |
| // to handle the client data input. DoFallThruToAnotherDriver() makes the call. |
| // Type: Overridden. |
| // Args: vrOtherDriver - (R) Reference to another driver object. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetDriverToFallThruTo( const CMIDriverBase & vrOtherDriver ) |
| { |
| m_pDriverFallThru = const_cast< CMIDriverBase * >( &vrOtherDriver ); |
| |
| return m_pDriverFallThru->SetDriverParent( *this ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this driver's |
| // implementation called from here to match the existing function name of the |
| // original LLDb driver class (the extra indirection is not necessarily required). |
| // Check the arguments that were passed to this program to make sure they are |
| // valid and to get their argument values (if any). |
| // Type: Overridden. |
| // Args: argc - (R) An integer that contains the count of arguments that follow in |
| // argv. The argc parameter is always greater than or equal to 1. |
| // argv - (R) An array of null-terminated strings representing command-line |
| // arguments entered by the user of the program. By convention, |
| // argv[0] is the command with which the program is invoked. |
| // vpStdOut - (R) Pointer to a standard output stream. |
| // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s), |
| // version information only. |
| // False = Continue to work, start debugger i.e. Command |
| // interpreter. |
| // Return: lldb::SBError - LLDB current error status. |
| // Throws: None. |
| //-- |
| lldb::SBError CMIDriver::DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting ) |
| { |
| return ParseArgs( argc, argv, vpStdOut, vwbExiting ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Check the arguments that were passed to this program to make sure they are |
| // valid and to get their argument values (if any). |
| // Type: Overridden. |
| // Args: argc - (R) An integer that contains the count of arguments that follow in |
| // argv. The argc parameter is always greater than or equal to 1. |
| // argv - (R) An array of null-terminated strings representing command-line |
| // arguments entered by the user of the program. By convention, |
| // argv[0] is the command with which the program is invoked. |
| // vpStdOut - (R) Pointer to a standard output stream. |
| // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s), |
| // version information only. |
| // False = Continue to work, start debugger i.e. Command |
| // interpreter. |
| // Return: lldb::SBError - LLDB current error status. |
| // Throws: None. |
| //-- |
| lldb::SBError CMIDriver::ParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting ) |
| { |
| lldb::SBError errStatus; |
| |
| // Do nothing - no options to handle for *this driver |
| |
| return errStatus; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: A client can ask if *this driver is GDB/MI compatible. |
| // Type: Overridden. |
| // Args: None. |
| // Return: True - GBD/MI compatible LLDB front end. |
| // False - Not GBD/MI compatible LLDB front end. |
| // Throws: None. |
| //-- |
| bool CMIDriver::GetDriverIsGDBMICompatibleDriver( void ) const |
| { |
| return true; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Callback function for monitoring stream stdin object. Part of the visitor |
| // pattern. |
| // This function is called by the CMICmnStreamStdin::CThreadStdin |
| // "stdin monitor" thread (ID). |
| // Type: Overridden. |
| // Args: vStdInBuffer - (R) Copy of the current stdin line data. |
| // vrbYesExit - (RW) True = yes exit stdin monitoring, false = continue monitor. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::ReadLine( const CMIUtilString & vStdInBuffer, bool & vrwbYesExit ) |
| { |
| // For debugging. Update prompt show stdin is working |
| //printf( "%s\n", vStdInBuffer.c_str() ); |
| //fflush( stdout ); |
| |
| // Special case look for the quit command here so stop monitoring stdin stream |
| // So we do not go back to fgetc() and wait and hang thread on exit |
| if( vStdInBuffer == "quit" ) |
| vrwbYesExit = true; |
| |
| // 1. Put new line in the queue container by stdin monitor thread |
| // 2. Then *this driver calls ReadStdinLineQueue() when ready to read the queue in its |
| // own thread |
| const bool bOk = QueueMICommand( vStdInBuffer ); |
| |
| // Check to see if the *this driver is shutting down (exit application) |
| if( !vrwbYesExit ) |
| vrwbYesExit = m_bDriverIsExiting; |
| |
| return bOk; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Start worker threads for the driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::StartWorkerThreads( void ) |
| { |
| bool bOk = MIstatus::success; |
| |
| // Grab the thread manager |
| CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance(); |
| |
| // Start the stdin thread |
| bOk &= m_rStdin.SetVisitor( *this ); |
| if( bOk && !rThreadMgr.ThreadStart< CMICmnStreamStdin >( m_rStdin )) |
| { |
| const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() ); |
| SetErrorDescriptionn( errMsg ); |
| return MIstatus::failure; |
| } |
| |
| // Start the event polling thread |
| if( bOk && !rThreadMgr.ThreadStart< CMICmnLLDBDebugger >( m_rLldbDebugger ) ) |
| { |
| const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() ); |
| SetErrorDescriptionn( errMsg ); |
| return MIstatus::failure; |
| } |
| |
| return bOk; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Stop worker threads for the driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::StopWorkerThreads( void ) |
| { |
| CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance(); |
| return rThreadMgr.ThreadAllTerminate(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Call this function puts *this driver to work. |
| // This function is used by the application's main thread. |
| // Type: Overridden. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoMainLoop( void ) |
| { |
| if( !StartWorkerThreads() ) |
| return MIstatus::failure; |
| |
| // App is not quitting currently |
| m_bExitApp = false; |
| |
| // While the app is active |
| while( !m_bExitApp ) |
| { |
| // Poll stdin queue and dispatch |
| if( !ReadStdinLineQueue() ) |
| { |
| // Something went wrong |
| break; |
| } |
| } |
| |
| // Signal that the application is shutting down |
| DoAppQuit(); |
| |
| // Close and wait for the workers to stop |
| StopWorkerThreads(); |
| |
| // Ensure that a new line is sent as the last act of the dying driver |
| m_rStdOut.WriteMIResponse( "\n", false ); |
| |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: *this driver sits and waits for input to the stdin line queue shared by *this |
| // driver and the stdin monitor thread, it queues, *this reads, interprets and |
| // reacts. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::ReadStdinLineQueue( void ) |
| { |
| // True when queue contains input |
| bool bHaveInput = false; |
| |
| // Stores the current input line |
| CMIUtilString lineText; |
| { |
| // Lock while we access the queue |
| CMIUtilThreadLock lock( m_threadMutex ); |
| if( !m_queueStdinLine.empty() ) |
| { |
| lineText = m_queueStdinLine.front(); |
| m_queueStdinLine.pop(); |
| bHaveInput = !lineText.empty(); |
| } |
| } |
| |
| // Process while we have input |
| if( bHaveInput ) |
| { |
| if( lineText == "quit" ) |
| { |
| // We want to be exiting when receiving a quit command |
| m_bExitApp = true; |
| return MIstatus::success; |
| } |
| |
| // Process the command |
| const bool bOk = InterpretCommand( lineText ); |
| |
| // Draw prompt if desired |
| if( bOk && m_rStdin.GetEnablePrompt() ) |
| m_rStdOut.WriteMIResponse( m_rStdin.GetPrompt() ); |
| |
| // Input has been processed |
| bHaveInput = false; |
| } |
| else |
| { |
| // Give resources back to the OS |
| const std::chrono::milliseconds time( 1 ); |
| std::this_thread::sleep_for( time ); |
| } |
| |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Set things in motion, set state etc that brings *this driver (and the |
| // application) to a tidy shutdown. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoAppQuit( void ) |
| { |
| bool bYesQuit = true; |
| |
| // Shutdown stuff, ready app for exit |
| { |
| CMIUtilThreadLock lock( m_threadMutex ); |
| m_bDriverIsExiting = true; |
| } |
| |
| return bYesQuit; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: *this driver passes text commands to a fall through driver is it does not |
| // understand them (the LLDB driver). |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vTextLine - (R) Text data representing a possible command. |
| // vwbCmdYesValid - (W) True = Command valid, false = command not handled. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InterpretCommandFallThruDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid ) |
| { |
| MIunused( vTextLine ); |
| MIunused( vwbCmdYesValid ); |
| |
| // ToDo: Implement when less urgent work to be done or decide remove as not required |
| //bool bOk = MIstatus::success; |
| //bool bCmdNotUnderstood = true; |
| //if( bCmdNotUnderstood && GetEnableFallThru() ) |
| //{ |
| // CMIUtilString errMsg; |
| // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg ); |
| // if( !bOk ) |
| // { |
| // errMsg = errMsg.StripCREndOfLine(); |
| // errMsg = errMsg.StripCRAll(); |
| // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo(); |
| // const MIchar * pName = pOtherDriver->GetDriverName().c_str(); |
| // const MIchar * pId = pOtherDriver->GetDriverId().c_str(); |
| // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() ) ); |
| // m_pLog->WriteMsg( msg ); |
| // } |
| //} |
| // |
| //vwbCmdYesValid = bOk; |
| //CMIUtilString strNot; |
| //if( vwbCmdYesValid) |
| // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) ); |
| //const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) ); |
| //m_pLog->WriteLog( msg ); |
| |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Retrieve the name for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Driver name. |
| // Throws: None. |
| //-- |
| const CMIUtilString & CMIDriver::GetDriverName( void ) const |
| { |
| return GetName(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Get the unique ID for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString & CMIDriver::GetDriverId( void ) const |
| { |
| return GetId(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: This function allows *this driver to call on another driver to perform work |
| // should this driver not be able to handle the client data input. |
| // SetDriverToFallThruTo() specifies the fall through to driver. |
| // Check the error message if the function returns a failure. |
| // Type: Overridden. |
| // Args: vCmd - (R) Command instruction to interpret. |
| // vwErrMsg - (W) Error description on command failing. |
| // Return: MIstatus::success - Command succeeded. |
| // MIstatus::failure - Command failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg ) |
| { |
| bool bOk = MIstatus::success; |
| |
| CMIDriverBase * pOtherDriver = GetDriverToFallThruTo(); |
| if( pOtherDriver == nullptr ) |
| return bOk; |
| |
| return pOtherDriver->DoFallThruToAnotherDriver( vCmd, vwErrMsg ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: *this driver provides a file stream to other drivers on which *this driver |
| // write's out to and they read as expected input. *this driver is passing |
| // through commands to the (child) pass through assigned driver. |
| // Type: Overrdidden. |
| // Args: None. |
| // Return: FILE * - Pointer to stream. |
| // Throws: None. |
| //-- |
| FILE * CMIDriver::GetStdin( void ) const |
| { |
| // Note this fn is called on CMIDriverMgr register driver so stream has to be |
| // available before *this driver has been initialized! Flaw? |
| |
| // This very likely to change later to a stream that the pass thru driver |
| // will read and we write to give it 'input' |
| return stdin; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: *this driver provides a file stream to other pass through assigned drivers |
| // so they know what to write to. |
| // Type: Overridden. |
| // Args: None. |
| // Return: FILE * - Pointer to stream. |
| // Throws: None. |
| //-- |
| FILE * CMIDriver::GetStdout( void ) const |
| { |
| // Note this fn is called on CMIDriverMgr register driver so stream has to be |
| // available before *this driver has been initialized! Flaw? |
| |
| // Do not want to pass through driver to write to stdout |
| return NULL; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: *this driver provides a error file stream to other pass through assigned drivers |
| // so they know what to write to. |
| // Type: Overridden. |
| // Args: None. |
| // Return: FILE * - Pointer to stream. |
| // Throws: None. |
| //-- |
| FILE * CMIDriver::GetStderr( void ) const |
| { |
| // Note this fn is called on CMIDriverMgr register driver so stream has to be |
| // available before *this driver has been initialized! Flaw? |
| |
| // This very likely to change later to a stream that the pass thru driver |
| // will write to and *this driver reads from to pass on the CMICmnLog object |
| return stderr; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Set a unique ID for *this driver. It cannot be empty. |
| // Type: Overridden. |
| // Args: vId - (R) Text description. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetId( const CMIUtilString & vId ) |
| { |
| if( vId.empty() ) |
| { |
| SetErrorDescriptionn( MIRSRC( IDS_DRIVER_ERR_ID_INVALID ), GetName().c_str(), vId.c_str() ); |
| return MIstatus::failure; |
| } |
| |
| m_strDriverId = vId; |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Get the unique ID for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString & CMIDriver::GetId( void ) const |
| { |
| return m_strDriverId; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Inject a command into the command processing system to be interpreted as a |
| // command read from stdin. The text representing the command is also written |
| // out to stdout as the command did not come from via stdin. |
| // Type: Method. |
| // Args: vMICmd - (R) Text data representing a possible command. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InjectMICommand( const CMIUtilString & vMICmd ) |
| { |
| const bool bOk = m_rStdOut.WriteMIResponse( vMICmd ); |
| |
| return bOk && QueueMICommand( vMICmd ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Add a new command candidate to the command queue to be processed by the |
| // command system. |
| // Type: Method. |
| // Args: vMICmd - (R) Text data representing a possible command. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::QueueMICommand( const CMIUtilString & vMICmd ) |
| { |
| CMIUtilThreadLock lock( m_threadMutex ); |
| m_queueStdinLine.push( vMICmd ); |
| |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Interpret the text data and match against current commands to see if there |
| // is a match. If a match then the command is issued and actioned on. The |
| // text data if not understood by *this driver is past on to the Fall Thru |
| // driver. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vTextLine - (R) Text data representing a possible command. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InterpretCommand( const CMIUtilString & vTextLine ) |
| { |
| bool bCmdYesValid = false; |
| bool bOk = InterpretCommandThisDriver( vTextLine, bCmdYesValid ); |
| if( bOk && !bCmdYesValid ) |
| bOk = InterpretCommandFallThruDriver( vTextLine, bCmdYesValid ); |
| |
| return bOk; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Interpret the text data and match against current commands to see if there |
| // is a match. If a match then the command is issued and actioned on. If a |
| // command cannot be found to match then vwbCmdYesValid is set to false and |
| // nothing else is done here. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vTextLine - (R) Text data representing a possible command. |
| // vwbCmdYesValid - (W) True = Command invalid, false = command acted on. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InterpretCommandThisDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid ) |
| { |
| vwbCmdYesValid = false; |
| |
| bool bCmdNotInCmdFactor = false; |
| SMICmdData cmdData; |
| CMICmdMgr & rCmdMgr = CMICmdMgr::Instance(); |
| if( !rCmdMgr.CmdInterpret( vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData ) ) |
| return MIstatus::failure; |
| |
| if( vwbCmdYesValid ) |
| { |
| // For debugging only |
| //m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() ); |
| |
| return ExecuteCommand( cmdData ); |
| } |
| |
| // Write to the Log that a 'command' was not valid. |
| // Report back to the MI client via MI result record. |
| CMIUtilString strNotInCmdFactory; |
| if( bCmdNotInCmdFactor ) |
| strNotInCmdFactory = CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_NOT_IN_FACTORY ), cmdData.strMiCmd.c_str() ); |
| const CMIUtilString strNot( CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) ) ); |
| const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str() ) ); |
| const CMICmnMIValueConst vconst = CMICmnMIValueConst( msg ); |
| const CMICmnMIValueResult valueResult( "msg", vconst ); |
| const CMICmnMIResultRecord miResultRecord( cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult ); |
| m_rStdOut.WriteMIResponse( miResultRecord.GetString() ); |
| |
| // Proceed to wait for or execute next command |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Having previously had the potential command validated and found valid now |
| // get the command executed. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vCmdData - (RW) Command meta data. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::ExecuteCommand( const SMICmdData & vCmdData ) |
| { |
| CMICmdMgr & rCmdMgr = CMICmdMgr::Instance(); |
| return rCmdMgr.CmdExecute( vCmdData ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Set the MI Driver's exit application flag. The application checks this flag |
| // after every stdin line is read so the exit may not be instantaneous. |
| // If vbForceExit is false the MI Driver queries its state and determines if is |
| // should exit or continue operating depending on that running state. |
| // This is related to the running state of the MI driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| void CMIDriver::SetExitApplicationFlag( const bool vbForceExit ) |
| { |
| if( vbForceExit ) |
| { |
| CMIUtilThreadLock lock( m_threadMutex ); |
| m_bExitApp = true; |
| return; |
| } |
| |
| // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM |
| // Did we receive a SIGINT from the client during a running debug program, if |
| // so then SIGINT is not to be taken as meaning kill the MI driver application |
| // but halt the inferior program being debugged instead |
| if( m_eCurrentDriverState == eDriverState_RunningDebugging ) |
| { |
| InjectMICommand( "-exec-interrupt" ); |
| return; |
| } |
| |
| m_bExitApp = true; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Get the MI Driver's exit exit application flag. |
| // This is related to the running state of the MI driver. |
| // Type: Method. |
| // Args: None. |
| // Return: bool - True = MI Driver is shutting down, false = MI driver is running. |
| // Throws: None. |
| //-- |
| bool CMIDriver::GetExitApplicationFlag( void ) const |
| { |
| return m_bExitApp; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Get the current running state of the MI Driver. |
| // Type: Method. |
| // Args: None. |
| // Return: DriverState_e - The current running state of the application. |
| // Throws: None. |
| //-- |
| CMIDriver::DriverState_e CMIDriver::GetCurrentDriverState( void ) const |
| { |
| return m_eCurrentDriverState; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Set the current running state of the MI Driver to running and currently in |
| // a debug session. The driver's state must in the state running and not in a |
| // debug session to set this new state. |
| // Type: Method. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Return: DriverState_e - The current running state of the application. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetDriverStateRunningNotDebugging( void ) |
| { |
| // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM |
| |
| if( m_eCurrentDriverState == eDriverState_RunningNotDebugging ) |
| return MIstatus::success; |
| |
| // Driver cannot be in the following states to set eDriverState_RunningNotDebugging |
| switch( m_eCurrentDriverState ) |
| { |
| case eDriverState_NotRunning: |
| case eDriverState_Initialising: |
| case eDriverState_ShuttingDown: |
| { |
| SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) ); |
| return MIstatus::failure; |
| } |
| case eDriverState_RunningDebugging: |
| case eDriverState_RunningNotDebugging: |
| break; |
| case eDriverState_count: |
| default: |
| SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CODE_ERR_INVALID_ENUMERATION_VALUE ), "SetDriverStateRunningNotDebugging()" ) ); |
| return MIstatus::failure; |
| } |
| |
| // Driver must be in this state to set eDriverState_RunningNotDebugging |
| if( m_eCurrentDriverState != eDriverState_RunningDebugging ) |
| { |
| SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) ); |
| return MIstatus::failure; |
| } |
| |
| m_eCurrentDriverState = eDriverState_RunningNotDebugging; |
| |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Set the current running state of the MI Driver to running and currently not in |
| // a debug session. The driver's state must in the state running and in a |
| // debug session to set this new state. |
| // Type: Method. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Return: DriverState_e - The current running state of the application. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetDriverStateRunningDebugging( void ) |
| { |
| // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM |
| |
| if( m_eCurrentDriverState == eDriverState_RunningDebugging ) |
| return MIstatus::success; |
| |
| // Driver cannot be in the following states to set eDriverState_RunningDebugging |
| switch( m_eCurrentDriverState ) |
| { |
| case eDriverState_NotRunning: |
| case eDriverState_Initialising: |
| case eDriverState_ShuttingDown: |
| { |
| SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) ); |
| return MIstatus::failure; |
| } |
| case eDriverState_RunningDebugging: |
| case eDriverState_RunningNotDebugging: |
| break; |
| case eDriverState_count: |
| default: |
| SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CODE_ERR_INVALID_ENUMERATION_VALUE ), "SetDriverStateRunningDebugging()" ) ); |
| return MIstatus::failure; |
| } |
| |
| // Driver must be in this state to set eDriverState_RunningDebugging |
| if( m_eCurrentDriverState != eDriverState_RunningNotDebugging ) |
| { |
| SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) ); |
| return MIstatus::failure; |
| } |
| |
| m_eCurrentDriverState = eDriverState_RunningDebugging; |
| |
| return MIstatus::success; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Prepare the client IDE so it will start working/communicating with *this MI |
| // driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InitClientIDEToMIDriver( void ) const |
| { |
| // Put other IDE init functions here |
| return InitClientIDEEclipse(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character |
| // sequence otherwise it refuses to communicate and times out. This should be |
| // sent to Eclipse before anything else. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InitClientIDEEclipse( void ) const |
| { |
| std::cout << "(gdb)" << std::endl; |
| |
| return MIstatus::success; |
| } |