1 //===-- MIDriver.cpp --------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
13 // Overview: CMIDriver implementation.
15 // Environment: Compilers: Visual C++ 12.
16 // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
17 // Libraries: See MIReadmetxt.
22 // Third party headers:
23 #include <stdarg.h> // va_list, va_start, var_end
25 #include <lldb/API/SBError.h>
30 #include "MICmnResources.h"
33 #include "MICmnLLDBDebugger.h"
34 #include "MICmnMIResultRecord.h"
35 #include "MICmnMIValueConst.h"
36 #include "MICmnThreadMgrStd.h"
37 #include "MIUtilDebug.h"
38 #include "MIUtilSingletonHelper.h"
39 #include "MICmnStreamStdout.h"
40 #include "MICmnStreamStderr.h"
41 #include "MICmdArgValFile.h"
42 #include "MICmdArgValString.h"
43 #include "MICmnConfig.h"
47 const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION_DEBUG );
49 const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION ); // Matches version in resources file
51 const CMIUtilString CMIDriver::ms_constAppNameShort( MIRSRC( IDS_MI_APPNAME_SHORT ) );
52 const CMIUtilString CMIDriver::ms_constAppNameLong( MIRSRC( IDS_MI_APPNAME_LONG ) );
54 //++ ------------------------------------------------------------------------------------
55 // Details: CMIDriver constructor.
61 CMIDriver::CMIDriver( void )
62 : m_bFallThruToOtherDriverEnabled( false )
63 , m_bDriverIsExiting( false )
64 , m_handleMainThread( 0 )
65 , m_rStdin( CMICmnStreamStdin::Instance() )
66 , m_rLldbDebugger( CMICmnLLDBDebugger::Instance() )
67 , m_rStdOut( CMICmnStreamStdout::Instance() )
68 , m_eCurrentDriverState( eDriverState_NotRunning )
69 , m_bHaveExecutableFileNamePathOnCmdLine( false )
70 , m_bDriverDebuggingArgExecutable( false )
74 //++ ------------------------------------------------------------------------------------
75 // Details: CMIDriver destructor.
81 CMIDriver::~CMIDriver( void )
85 //++ ------------------------------------------------------------------------------------
86 // Details: Set whether *this driver (the parent) is enabled to pass a command to its
87 // fall through (child) driver to interpret the command and do work instead
88 // (if *this driver decides it can't hanled the command).
90 // Args: vbYes - (R) True = yes fall through, false = do not pass on command.
91 // Return: MIstatus::success - Functional succeeded.
92 // MIstatus::failure - Functional failed.
95 bool CMIDriver::SetEnableFallThru( const bool vbYes )
97 m_bFallThruToOtherDriverEnabled = vbYes;
98 return MIstatus::success;
101 //++ ------------------------------------------------------------------------------------
102 // Details: Get whether *this driver (the parent) is enabled to pass a command to its
103 // fall through (child) driver to interpret the command and do work instead
104 // (if *this driver decides it can't hanled the command).
107 // Return: bool - True = yes fall through, false = do not pass on command.
110 bool CMIDriver::GetEnableFallThru( void ) const
112 return m_bFallThruToOtherDriverEnabled;
115 //++ ------------------------------------------------------------------------------------
116 // Details: Retrieve MI's application name of itself.
119 // Return: CMIUtilString & - Text description.
122 const CMIUtilString & CMIDriver::GetAppNameShort( void ) const
124 return ms_constAppNameShort;
127 //++ ------------------------------------------------------------------------------------
128 // Details: Retrieve MI's application name of itself.
131 // Return: CMIUtilString & - Text description.
134 const CMIUtilString & CMIDriver::GetAppNameLong( void ) const
136 return ms_constAppNameLong;
139 //++ ------------------------------------------------------------------------------------
140 // Details: Retrieve MI's version description of itself.
143 // Return: CMIUtilString & - Text description.
146 const CMIUtilString & CMIDriver::GetVersionDescription( void ) const
148 return ms_constMIVersion;
151 //++ ------------------------------------------------------------------------------------
152 // Details: Initialize setup *this driver ready for use.
155 // Return: MIstatus::success - Functional succeeded.
156 // MIstatus::failure - Functional failed.
159 bool CMIDriver::Initialize( void )
161 m_eCurrentDriverState = eDriverState_Initialising;
162 m_clientUsageRefCnt++;
164 ClrErrorDescription();
167 return MIstatus::success;
169 bool bOk = MIstatus::success;
170 CMIUtilString errMsg;
172 // Initialize all of the modules we depend on
173 MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
174 MI::ModuleInit< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg );
175 MI::ModuleInit< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg );
176 MI::ModuleInit< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg );
177 MI::ModuleInit< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg );
178 MI::ModuleInit< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg );
179 MI::ModuleInit< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg );
180 bOk &= m_rLldbDebugger.SetDriver( *this );
181 MI::ModuleInit< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg );
183 #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
184 CMIDriverMgr & rDrvMgr = CMIDriverMgr::Instance();
185 bOk = bOk && rDrvMgr.RegisterDriver( *g_driver, "LLDB driver" ); // Will be pass thru driver
188 bOk = SetEnableFallThru( false ); // This is intentional at this time - yet to be fully implemented
189 bOk = bOk && SetDriverToFallThruTo( *g_driver );
190 CMIUtilString strOtherDrvErrMsg;
191 if( bOk && GetEnableFallThru() && !g_driver->MISetup( strOtherDrvErrMsg ) )
194 errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_FALLTHRUDRIVER ), strOtherDrvErrMsg.c_str() );
197 #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
201 m_bInitialized = bOk;
205 const CMIUtilString msg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_DRIVER ), errMsg.c_str() );
206 SetErrorDescription( msg );
207 return MIstatus::failure;
210 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
215 //++ ------------------------------------------------------------------------------------
216 // Details: Unbind detach or release resources used by *this driver.
219 // Return: MIstatus::success - Functional succeeded.
220 // MIstatus::failure - Functional failed.
223 bool CMIDriver::Shutdown( void )
225 if( --m_clientUsageRefCnt > 0 )
226 return MIstatus::success;
228 if( !m_bInitialized )
229 return MIstatus::success;
231 m_eCurrentDriverState = eDriverState_ShuttingDown;
233 ClrErrorDescription();
235 bool bOk = MIstatus::success;
236 CMIUtilString errMsg;
238 // Shutdown all of the modules we depend on
239 MI::ModuleShutdown< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg );
240 MI::ModuleShutdown< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg );
241 MI::ModuleShutdown< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg );
242 MI::ModuleShutdown< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg );
243 MI::ModuleShutdown< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg );
244 MI::ModuleShutdown< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg );
245 MI::ModuleShutdown< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg );
246 MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
250 SetErrorDescriptionn( MIRSRC( IDS_MI_SHUTDOWN_ERR ), errMsg.c_str() );
253 m_eCurrentDriverState = eDriverState_NotRunning;
258 //++ ------------------------------------------------------------------------------------
259 // Details: Work function. Client (the driver's user) is able to append their own message
260 // in to the MI's Log trace file.
262 // Args: vMessage - (R) Client's text message.
263 // Return: MIstatus::success - Functional succeeded.
264 // MIstatus::failure - Functional failed.
267 bool CMIDriver::WriteMessageToLog( const CMIUtilString & vMessage )
270 msg = CMIUtilString::Format( MIRSRC( IDS_MI_CLIENT_MSG ), vMessage.c_str() );
271 return m_pLog->Write( msg, CMICmnLog::eLogVerbosity_ClientMsg );
274 //++ ------------------------------------------------------------------------------------
275 // Details: CDriverMgr calls *this driver initialize setup ready for use.
278 // Return: MIstatus::success - Functional succeeded.
279 // MIstatus::failure - Functional failed.
282 bool CMIDriver::DoInitialize( void )
284 return CMIDriver::Instance().Initialize();
287 //++ ------------------------------------------------------------------------------------
288 // Details: CDriverMgr calls *this driver to unbind detach or release resources used by
292 // Return: MIstatus::success - Functional succeeded.
293 // MIstatus::failure - Functional failed.
296 bool CMIDriver::DoShutdown( void )
298 return CMIDriver::Instance().Shutdown();
301 //++ ------------------------------------------------------------------------------------
302 // Details: Retrieve the name for *this driver.
305 // Return: CMIUtilString & - Driver name.
308 const CMIUtilString & CMIDriver::GetName( void ) const
310 const CMIUtilString & rName = GetAppNameLong();
311 const CMIUtilString & rVsn = GetVersionDescription();
312 static CMIUtilString strName = CMIUtilString::Format( "%s %s", rName.c_str(), rVsn.c_str() );
317 //++ ------------------------------------------------------------------------------------
318 // Details: Retrieve *this driver's last error condition.
321 // Return: CMIUtilString - Text description.
324 CMIUtilString CMIDriver::GetError( void ) const
326 return GetErrorDescription();
329 //++ ------------------------------------------------------------------------------------
330 // Details: Call *this driver to resize the console window.
332 // Args: vTermWidth - (R) New window column size.
333 // Return: MIstatus::success - Functional succeeded.
334 // MIstatus::failure - Functional failed.
337 void CMIDriver::DoResizeWindow( const uint32_t vTermWidth )
339 GetTheDebugger().SetTerminalWidth( vTermWidth );
342 //++ ------------------------------------------------------------------------------------
343 // Details: Call *this driver to return it's debugger.
346 // Return: lldb::SBDebugger & - LLDB debugger object reference.
349 lldb::SBDebugger & CMIDriver::GetTheDebugger( void )
351 return m_rLldbDebugger.GetTheDebugger();
354 //++ ------------------------------------------------------------------------------------
355 // Details: Specify another driver *this driver can call should this driver not be able
356 // to handle the client data input. DoFallThruToAnotherDriver() makes the call.
358 // Args: vrOtherDriver - (R) Reference to another driver object.
359 // Return: MIstatus::success - Functional succeeded.
360 // MIstatus::failure - Functional failed.
363 bool CMIDriver::SetDriverToFallThruTo( const CMIDriverBase & vrOtherDriver )
365 m_pDriverFallThru = const_cast< CMIDriverBase * >( &vrOtherDriver );
367 return m_pDriverFallThru->SetDriverParent( *this );
370 //++ ------------------------------------------------------------------------------------
371 // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this driver's
372 // implementation called from here to match the existing function name of the
373 // original LLDb driver class (the extra indirection is not necessarily required).
374 // Check the arguments that were passed to this program to make sure they are
375 // valid and to get their argument values (if any).
377 // Args: argc - (R) An integer that contains the count of arguments that follow in
378 // argv. The argc parameter is always greater than or equal to 1.
379 // argv - (R) An array of null-terminated strings representing command-line
380 // arguments entered by the user of the program. By convention,
381 // argv[0] is the command with which the program is invoked.
382 // vpStdOut - (R) Pointer to a standard output stream.
383 // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
384 // version information only.
385 // False = Continue to work, start debugger i.e. Command
387 // Return: lldb::SBError - LLDB current error status.
390 lldb::SBError CMIDriver::DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting )
392 return ParseArgs( argc, argv, vpStdOut, vwbExiting );
395 //++ ------------------------------------------------------------------------------------
396 // Details: Check the arguments that were passed to this program to make sure they are
397 // valid and to get their argument values (if any). The following are options
398 // that are only handled by *this driver:
400 // The application's options --interpreter and --executable in code act very similar.
401 // The --executable is necessary to differentiate whither the MI Driver is being
402 // using by a client i.e. Eclipse or from the command line. Eclipse issues the option
403 // --interpreter and also passes additional arguments which can be interpreted as an
404 // executable if called from the command line. Using --executable tells the MI
405 // Driver is being called the command line and that the executable argument is indeed
406 // a specified executable an so actions commands to set up the executable for a
407 // debug session. Using --interpreter on the commnd line does not action additional
408 // commands to initialise a debug session and so be able to launch the process.
410 // Args: argc - (R) An integer that contains the count of arguments that follow in
411 // argv. The argc parameter is always greater than or equal to 1.
412 // argv - (R) An array of null-terminated strings representing command-line
413 // arguments entered by the user of the program. By convention,
414 // argv[0] is the command with which the program is invoked.
415 // vpStdOut - (R) Pointer to a standard output stream.
416 // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
417 // version information only.
418 // False = Continue to work, start debugger i.e. Command
420 // Return: lldb::SBError - LLDB current error status.
423 lldb::SBError CMIDriver::ParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting )
425 lldb::SBError errStatus;
426 const bool bHaveArgs( argc >= 2 );
428 // *** Add any args handled here to GetHelpOnCmdLineArgOptions() ***
430 // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
431 // Look for the command line options
432 bool bHaveExecutableFileNamePath = false;
433 bool bHaveExecutableLongOption = false;
437 // Search right to left to look for the executable
438 for( MIint i = argc - 1; i > 0; i-- )
440 const CMIUtilString strArg( argv[ i ] );
441 const CMICmdArgValFile argFile;
442 if( argFile.IsFilePath( strArg ) ||
443 CMICmdArgValString( true, false, true ).IsStringArg( strArg ))
445 bHaveExecutableFileNamePath = true;
446 m_strCmdLineArgExecuteableFileNamePath = argFile.GetFileNamePath( strArg );
447 m_bHaveExecutableFileNamePathOnCmdLine = true;
449 // This argument is also check for in CMIDriverMgr::ParseArgs()
450 if( 0 == strArg.compare( "--executable" ) ) // Used to specify that there is executable argument also on the command line
451 { // See fn description.
452 bHaveExecutableLongOption = true;
457 if( bHaveExecutableFileNamePath && bHaveExecutableLongOption )
459 // CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
460 #if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
461 SetDriverDebuggingArgExecutable();
464 errStatus.SetErrorString( MIRSRC( IDS_DRIVER_ERR_LOCAL_DEBUG_NOT_IMPL ) );
465 #endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
471 //++ ------------------------------------------------------------------------------------
472 // Details: A client can ask if *this driver is GDB/MI compatible.
475 // Return: True - GBD/MI compatible LLDB front end.
476 // False - Not GBD/MI compatible LLDB front end.
479 bool CMIDriver::GetDriverIsGDBMICompatibleDriver( void ) const
484 //++ ------------------------------------------------------------------------------------
485 // Details: Callback function for monitoring stream stdin object. Part of the visitor
487 // This function is called by the CMICmnStreamStdin::CThreadStdin
488 // "stdin monitor" thread (ID).
490 // Args: vStdInBuffer - (R) Copy of the current stdin line data.
491 // vrbYesExit - (RW) True = yes exit stdin monitoring, false = continue monitor.
492 // Return: MIstatus::success - Functional succeeded.
493 // MIstatus::failure - Functional failed.
496 bool CMIDriver::ReadLine( const CMIUtilString & vStdInBuffer, bool & vrwbYesExit )
498 // For debugging. Update prompt show stdin is working
499 //printf( "%s\n", vStdInBuffer.c_str() );
502 // Special case look for the quit command here so stop monitoring stdin stream
503 // So we do not go back to fgetc() and wait and hang thread on exit
504 if( vStdInBuffer == "quit" )
507 // 1. Put new line in the queue container by stdin monitor thread
508 // 2. Then *this driver calls ReadStdinLineQueue() when ready to read the queue in its
510 const bool bOk = QueueMICommand( vStdInBuffer );
512 // Check to see if the *this driver is shutting down (exit application)
514 vrwbYesExit = m_bDriverIsExiting;
519 //++ ------------------------------------------------------------------------------------
520 // Details: Start worker threads for the driver.
523 // Return: MIstatus::success - Functional succeeded.
524 // MIstatus::failure - Functional failed.
527 bool CMIDriver::StartWorkerThreads( void )
529 bool bOk = MIstatus::success;
531 // Grab the thread manager
532 CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance();
534 // Start the stdin thread
535 bOk &= m_rStdin.SetVisitor( *this );
536 if( bOk && !rThreadMgr.ThreadStart< CMICmnStreamStdin >( m_rStdin ))
538 const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() );
539 SetErrorDescriptionn( errMsg );
540 return MIstatus::failure;
543 // Start the event polling thread
544 if( bOk && !rThreadMgr.ThreadStart< CMICmnLLDBDebugger >( m_rLldbDebugger ) )
546 const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() );
547 SetErrorDescriptionn( errMsg );
548 return MIstatus::failure;
554 //++ ------------------------------------------------------------------------------------
555 // Details: Stop worker threads for the driver.
558 // Return: MIstatus::success - Functional succeeded.
559 // MIstatus::failure - Functional failed.
562 bool CMIDriver::StopWorkerThreads( void )
564 CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance();
565 return rThreadMgr.ThreadAllTerminate();
568 //++ ------------------------------------------------------------------------------------
569 // Details: Call this function puts *this driver to work.
570 // This function is used by the application's main thread.
573 // Return: MIstatus::success - Functional succeeded.
574 // MIstatus::failure - Functional failed.
577 bool CMIDriver::DoMainLoop( void )
579 if( !InitClientIDEToMIDriver() ) // Init Eclipse IDE
581 SetErrorDescriptionn( MIRSRC( IDS_MI_INIT_ERR_CLIENT_USING_DRIVER ) );
582 return MIstatus::failure;
585 if( !StartWorkerThreads() )
586 return MIstatus::failure;
588 // App is not quitting currently
591 // CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
592 #if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
593 if( HaveExecutableFileNamePathOnCmdLine() )
595 if( !LocalDebugSessionStartupInjectCommands() )
597 SetErrorDescription( MIRSRC( IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION ) );
598 return MIstatus::failure;
601 #endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
603 // While the app is active
606 // Poll stdin queue and dispatch
607 if( !ReadStdinLineQueue() )
609 // Something went wrong
614 // Signal that the application is shutting down
617 // Close and wait for the workers to stop
620 // Ensure that a new line is sent as the last act of the dying driver
621 m_rStdOut.WriteMIResponse( "\n", false );
623 return MIstatus::success;
626 //++ ------------------------------------------------------------------------------------
627 // Details: *this driver sits and waits for input to the stdin line queue shared by *this
628 // driver and the stdin monitor thread, it queues, *this reads, interprets and
630 // This function is used by the application's main thread.
633 // Return: MIstatus::success - Functional succeeded.
634 // MIstatus::failure - Functional failed.
637 bool CMIDriver::ReadStdinLineQueue( void )
639 // True when queue contains input
640 bool bHaveInput = false;
642 // Stores the current input line
643 CMIUtilString lineText;
645 // Lock while we access the queue
646 CMIUtilThreadLock lock( m_threadMutex );
647 if( !m_queueStdinLine.empty() )
649 lineText = m_queueStdinLine.front();
650 m_queueStdinLine.pop();
651 bHaveInput = !lineText.empty();
655 // Process while we have input
658 if( lineText == "quit" )
660 // We want to be exiting when receiving a quit command
662 return MIstatus::success;
665 // Process the command
666 const bool bOk = InterpretCommand( lineText );
668 // Draw prompt if desired
669 if( bOk && m_rStdin.GetEnablePrompt() )
670 m_rStdOut.WriteMIResponse( m_rStdin.GetPrompt() );
672 // Input has been processed
677 // Give resources back to the OS
678 const std::chrono::milliseconds time( 1 );
679 std::this_thread::sleep_for( time );
682 return MIstatus::success;
685 //++ ------------------------------------------------------------------------------------
686 // Details: Set things in motion, set state etc that brings *this driver (and the
687 // application) to a tidy shutdown.
688 // This function is used by the application's main thread.
691 // Return: MIstatus::success - Functional succeeded.
692 // MIstatus::failure - Functional failed.
695 bool CMIDriver::DoAppQuit( void )
697 bool bYesQuit = true;
699 // Shutdown stuff, ready app for exit
701 CMIUtilThreadLock lock( m_threadMutex );
702 m_bDriverIsExiting = true;
708 //++ ------------------------------------------------------------------------------------
709 // Details: *this driver passes text commands to a fall through driver is it does not
710 // understand them (the LLDB driver).
711 // This function is used by the application's main thread.
713 // Args: vTextLine - (R) Text data representing a possible command.
714 // vwbCmdYesValid - (W) True = Command valid, false = command not handled.
715 // Return: MIstatus::success - Functional succeeded.
716 // MIstatus::failure - Functional failed.
719 bool CMIDriver::InterpretCommandFallThruDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid )
721 MIunused( vTextLine );
722 MIunused( vwbCmdYesValid );
724 // ToDo: Implement when less urgent work to be done or decide remove as not required
725 //bool bOk = MIstatus::success;
726 //bool bCmdNotUnderstood = true;
727 //if( bCmdNotUnderstood && GetEnableFallThru() )
729 // CMIUtilString errMsg;
730 // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg );
733 // errMsg = errMsg.StripCREndOfLine();
734 // errMsg = errMsg.StripCRAll();
735 // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
736 // const MIchar * pName = pOtherDriver->GetDriverName().c_str();
737 // const MIchar * pId = pOtherDriver->GetDriverId().c_str();
738 // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() ) );
739 // m_pLog->WriteMsg( msg );
743 //vwbCmdYesValid = bOk;
744 //CMIUtilString strNot;
745 //if( vwbCmdYesValid)
746 // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) );
747 //const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) );
748 //m_pLog->WriteLog( msg );
750 return MIstatus::success;
753 //++ ------------------------------------------------------------------------------------
754 // Details: Retrieve the name for *this driver.
757 // Return: CMIUtilString & - Driver name.
760 const CMIUtilString & CMIDriver::GetDriverName( void ) const
765 //++ ------------------------------------------------------------------------------------
766 // Details: Get the unique ID for *this driver.
769 // Return: CMIUtilString & - Text description.
772 const CMIUtilString & CMIDriver::GetDriverId( void ) const
777 //++ ------------------------------------------------------------------------------------
778 // Details: This function allows *this driver to call on another driver to perform work
779 // should this driver not be able to handle the client data input.
780 // SetDriverToFallThruTo() specifies the fall through to driver.
781 // Check the error message if the function returns a failure.
783 // Args: vCmd - (R) Command instruction to interpret.
784 // vwErrMsg - (W) Error description on command failing.
785 // Return: MIstatus::success - Command succeeded.
786 // MIstatus::failure - Command failed.
789 bool CMIDriver::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg )
791 bool bOk = MIstatus::success;
793 CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
794 if( pOtherDriver == nullptr )
797 return pOtherDriver->DoFallThruToAnotherDriver( vCmd, vwErrMsg );
800 //++ ------------------------------------------------------------------------------------
801 // Details: *this driver provides a file stream to other drivers on which *this driver
802 // write's out to and they read as expected input. *this driver is passing
803 // through commands to the (child) pass through assigned driver.
804 // Type: Overrdidden.
806 // Return: FILE * - Pointer to stream.
809 FILE * CMIDriver::GetStdin( void ) const
811 // Note this fn is called on CMIDriverMgr register driver so stream has to be
812 // available before *this driver has been initialized! Flaw?
814 // This very likely to change later to a stream that the pass thru driver
815 // will read and we write to give it 'input'
819 //++ ------------------------------------------------------------------------------------
820 // Details: *this driver provides a file stream to other pass through assigned drivers
821 // so they know what to write to.
824 // Return: FILE * - Pointer to stream.
827 FILE * CMIDriver::GetStdout( void ) const
829 // Note this fn is called on CMIDriverMgr register driver so stream has to be
830 // available before *this driver has been initialized! Flaw?
832 // Do not want to pass through driver to write to stdout
836 //++ ------------------------------------------------------------------------------------
837 // Details: *this driver provides a error file stream to other pass through assigned drivers
838 // so they know what to write to.
841 // Return: FILE * - Pointer to stream.
844 FILE * CMIDriver::GetStderr( void ) const
846 // Note this fn is called on CMIDriverMgr register driver so stream has to be
847 // available before *this driver has been initialized! Flaw?
849 // This very likely to change later to a stream that the pass thru driver
850 // will write to and *this driver reads from to pass on the CMICmnLog object
854 //++ ------------------------------------------------------------------------------------
855 // Details: Set a unique ID for *this driver. It cannot be empty.
857 // Args: vId - (R) Text description.
858 // Return: MIstatus::success - Functional succeeded.
859 // MIstatus::failure - Functional failed.
862 bool CMIDriver::SetId( const CMIUtilString & vId )
866 SetErrorDescriptionn( MIRSRC( IDS_DRIVER_ERR_ID_INVALID ), GetName().c_str(), vId.c_str() );
867 return MIstatus::failure;
871 return MIstatus::success;
874 //++ ------------------------------------------------------------------------------------
875 // Details: Get the unique ID for *this driver.
878 // Return: CMIUtilString & - Text description.
881 const CMIUtilString & CMIDriver::GetId( void ) const
883 return m_strDriverId;
886 //++ ------------------------------------------------------------------------------------
887 // Details: Inject a command into the command processing system to be interpreted as a
888 // command read from stdin. The text representing the command is also written
889 // out to stdout as the command did not come from via stdin.
891 // Args: vMICmd - (R) Text data representing a possible command.
892 // Return: MIstatus::success - Functional succeeded.
893 // MIstatus::failure - Functional failed.
896 bool CMIDriver::InjectMICommand( const CMIUtilString & vMICmd )
898 const bool bOk = m_rStdOut.WriteMIResponse( vMICmd );
900 return bOk && QueueMICommand( vMICmd );
903 //++ ------------------------------------------------------------------------------------
904 // Details: Add a new command candidate to the command queue to be processed by the
907 // Args: vMICmd - (R) Text data representing a possible command.
908 // Return: MIstatus::success - Functional succeeded.
909 // MIstatus::failure - Functional failed.
912 bool CMIDriver::QueueMICommand( const CMIUtilString & vMICmd )
914 CMIUtilThreadLock lock( m_threadMutex );
915 m_queueStdinLine.push( vMICmd );
917 return MIstatus::success;
920 //++ ------------------------------------------------------------------------------------
921 // Details: Interpret the text data and match against current commands to see if there
922 // is a match. If a match then the command is issued and actioned on. The
923 // text data if not understood by *this driver is past on to the Fall Thru
925 // This function is used by the application's main thread.
927 // Args: vTextLine - (R) Text data representing a possible command.
928 // Return: MIstatus::success - Functional succeeded.
929 // MIstatus::failure - Functional failed.
932 bool CMIDriver::InterpretCommand( const CMIUtilString & vTextLine )
934 bool bCmdYesValid = false;
935 bool bOk = InterpretCommandThisDriver( vTextLine, bCmdYesValid );
936 if( bOk && !bCmdYesValid )
937 bOk = InterpretCommandFallThruDriver( vTextLine, bCmdYesValid );
942 //++ ------------------------------------------------------------------------------------
943 // Details: Interpret the text data and match against current commands to see if there
944 // is a match. If a match then the command is issued and actioned on. If a
945 // command cannot be found to match then vwbCmdYesValid is set to false and
946 // nothing else is done here.
947 // This function is used by the application's main thread.
949 // Args: vTextLine - (R) Text data representing a possible command.
950 // vwbCmdYesValid - (W) True = Command invalid, false = command acted on.
951 // Return: MIstatus::success - Functional succeeded.
952 // MIstatus::failure - Functional failed.
955 bool CMIDriver::InterpretCommandThisDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid )
957 vwbCmdYesValid = false;
959 bool bCmdNotInCmdFactor = false;
961 CMICmdMgr & rCmdMgr = CMICmdMgr::Instance();
962 if( !rCmdMgr.CmdInterpret( vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData ) )
963 return MIstatus::failure;
967 // For debugging only
968 //m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() );
970 return ExecuteCommand( cmdData );
973 // Check for escape character, may be cursor control characters
974 // This code is not necessary for application operation, just want to keep tabs on what
975 // is been given to the driver to try and intepret.
976 if( vTextLine.at( 0 ) == 27 )
978 CMIUtilString logInput( MIRSRC( IDS_STDIN_INPUT_CTRL_CHARS ) );
979 for( MIuint i = 0; i < vTextLine.length(); i++ )
981 logInput += CMIUtilString::Format( "%d ", vTextLine.at( i ) );
983 m_pLog->WriteLog( logInput );
984 return MIstatus::success;
987 // Write to the Log that a 'command' was not valid.
988 // Report back to the MI client via MI result record.
989 CMIUtilString strNotInCmdFactory;
990 if( bCmdNotInCmdFactor )
991 strNotInCmdFactory = CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_NOT_IN_FACTORY ), cmdData.strMiCmd.c_str() );
992 const CMIUtilString strNot( CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) ) );
993 const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str() ) );
994 const CMICmnMIValueConst vconst = CMICmnMIValueConst( msg );
995 const CMICmnMIValueResult valueResult( "msg", vconst );
996 const CMICmnMIResultRecord miResultRecord( cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult );
997 m_rStdOut.WriteMIResponse( miResultRecord.GetString() );
999 // Proceed to wait for or execute next command
1000 return MIstatus::success;
1003 //++ ------------------------------------------------------------------------------------
1004 // Details: Having previously had the potential command validated and found valid now
1005 // get the command executed.
1006 // This function is used by the application's main thread.
1008 // Args: vCmdData - (RW) Command meta data.
1009 // Return: MIstatus::success - Functional succeeded.
1010 // MIstatus::failure - Functional failed.
1013 bool CMIDriver::ExecuteCommand( const SMICmdData & vCmdData )
1015 CMICmdMgr & rCmdMgr = CMICmdMgr::Instance();
1016 return rCmdMgr.CmdExecute( vCmdData );
1019 //++ ------------------------------------------------------------------------------------
1020 // Details: Set the MI Driver's exit application flag. The application checks this flag
1021 // after every stdin line is read so the exit may not be instantaneous.
1022 // If vbForceExit is false the MI Driver queries its state and determines if is
1023 // should exit or continue operating depending on that running state.
1024 // This is related to the running state of the MI driver.
1025 // Type: Overridden.
1030 void CMIDriver::SetExitApplicationFlag( const bool vbForceExit )
1034 CMIUtilThreadLock lock( m_threadMutex );
1039 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1040 // Did we receive a SIGINT from the client during a running debug program, if
1041 // so then SIGINT is not to be taken as meaning kill the MI driver application
1042 // but halt the inferior program being debugged instead
1043 if( m_eCurrentDriverState == eDriverState_RunningDebugging )
1045 InjectMICommand( "-exec-interrupt" );
1052 //++ ------------------------------------------------------------------------------------
1053 // Details: Get the MI Driver's exit exit application flag.
1054 // This is related to the running state of the MI driver.
1057 // Return: bool - True = MI Driver is shutting down, false = MI driver is running.
1060 bool CMIDriver::GetExitApplicationFlag( void ) const
1065 //++ ------------------------------------------------------------------------------------
1066 // Details: Get the current running state of the MI Driver.
1069 // Return: DriverState_e - The current running state of the application.
1072 CMIDriver::DriverState_e CMIDriver::GetCurrentDriverState( void ) const
1074 return m_eCurrentDriverState;
1077 //++ ------------------------------------------------------------------------------------
1078 // Details: Set the current running state of the MI Driver to running and currently not in
1081 // Return: MIstatus::success - Functionality succeeded.
1082 // MIstatus::failure - Functionality failed.
1083 // Return: DriverState_e - The current running state of the application.
1086 bool CMIDriver::SetDriverStateRunningNotDebugging( void )
1088 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1090 if( m_eCurrentDriverState == eDriverState_RunningNotDebugging )
1091 return MIstatus::success;
1093 // Driver cannot be in the following states to set eDriverState_RunningNotDebugging
1094 switch( m_eCurrentDriverState )
1096 case eDriverState_NotRunning:
1097 case eDriverState_Initialising:
1098 case eDriverState_ShuttingDown:
1100 SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
1101 return MIstatus::failure;
1103 case eDriverState_RunningDebugging:
1104 case eDriverState_RunningNotDebugging:
1106 case eDriverState_count:
1108 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CODE_ERR_INVALID_ENUMERATION_VALUE ), "SetDriverStateRunningNotDebugging()" ) );
1109 return MIstatus::failure;
1112 // Driver must be in this state to set eDriverState_RunningNotDebugging
1113 if( m_eCurrentDriverState != eDriverState_RunningDebugging )
1115 SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
1116 return MIstatus::failure;
1119 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
1121 return MIstatus::success;
1124 //++ ------------------------------------------------------------------------------------
1125 // Details: Set the current running state of the MI Driver to running and currently not in
1126 // a debug session. The driver's state must in the state running and in a
1127 // debug session to set this new state.
1129 // Return: MIstatus::success - Functionality succeeded.
1130 // MIstatus::failure - Functionality failed.
1131 // Return: DriverState_e - The current running state of the application.
1134 bool CMIDriver::SetDriverStateRunningDebugging( void )
1136 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1138 if( m_eCurrentDriverState == eDriverState_RunningDebugging )
1139 return MIstatus::success;
1141 // Driver cannot be in the following states to set eDriverState_RunningDebugging
1142 switch( m_eCurrentDriverState )
1144 case eDriverState_NotRunning:
1145 case eDriverState_Initialising:
1146 case eDriverState_ShuttingDown:
1148 SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
1149 return MIstatus::failure;
1151 case eDriverState_RunningDebugging:
1152 case eDriverState_RunningNotDebugging:
1154 case eDriverState_count:
1156 SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CODE_ERR_INVALID_ENUMERATION_VALUE ), "SetDriverStateRunningDebugging()" ) );
1157 return MIstatus::failure;
1160 // Driver must be in this state to set eDriverState_RunningDebugging
1161 if( m_eCurrentDriverState != eDriverState_RunningNotDebugging )
1163 SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
1164 return MIstatus::failure;
1167 m_eCurrentDriverState = eDriverState_RunningDebugging;
1169 return MIstatus::success;
1172 //++ ------------------------------------------------------------------------------------
1173 // Details: Prepare the client IDE so it will start working/communicating with *this MI
1177 // Return: MIstatus::success - Functionality succeeded.
1178 // MIstatus::failure - Functionality failed.
1181 bool CMIDriver::InitClientIDEToMIDriver( void ) const
1183 // Put other IDE init functions here
1184 return InitClientIDEEclipse();
1187 //++ ------------------------------------------------------------------------------------
1188 // Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character
1189 // sequence otherwise it refuses to communicate and times out. This should be
1190 // sent to Eclipse before anything else.
1193 // Return: MIstatus::success - Functionality succeeded.
1194 // MIstatus::failure - Functionality failed.
1197 bool CMIDriver::InitClientIDEEclipse( void ) const
1199 std::cout << "(gdb)" << std::endl;
1201 return MIstatus::success;
1204 //++ ------------------------------------------------------------------------------------
1205 // Details: Ask *this driver whether it found an executable in the MI Driver's list of
1206 // arguments which to open and debug. If so instigate commands to set up a debug
1207 // session for that executable.
1210 // Return: bool - True = True = Yes executable given as one of the parameters to the MI
1212 // False = not found.
1215 bool CMIDriver::HaveExecutableFileNamePathOnCmdLine( void ) const
1217 return m_bHaveExecutableFileNamePathOnCmdLine;
1220 //++ ------------------------------------------------------------------------------------
1221 // Details: Retrieve from *this driver executable file name path to start a debug session
1222 // with (if present see HaveExecutableFileNamePathOnCmdLine()).
1225 // Return: CMIUtilString & - Executeable file name path or empty string.
1228 const CMIUtilString & CMIDriver::GetExecutableFileNamePathOnCmdLine( void ) const
1230 return m_strCmdLineArgExecuteableFileNamePath;
1233 //++ ------------------------------------------------------------------------------------
1234 // Details: Execute commands (by injecting them into the stdin line queue container) and
1235 // other code to set up the MI Driver such that is can take the executable
1236 // argument passed on the command and create a debug session for it.
1239 // Return: MIstatus::success - Functionality succeeded.
1240 // MIstatus::failure - Functionality failed.
1243 bool CMIDriver::LocalDebugSessionStartupInjectCommands( void )
1245 const CMIUtilString strCmd( CMIUtilString::Format( "-file-exec-and-symbols %s", m_strCmdLineArgExecuteableFileNamePath.c_str() ) );
1247 return InjectMICommand( strCmd );
1250 //++ ------------------------------------------------------------------------------------
1251 // Details: Set the MI Driver into "its debugging an executable passed as an argument"
1252 // mode as against running via a client like Eclipse.
1258 void CMIDriver::SetDriverDebuggingArgExecutable( void )
1260 m_bDriverDebuggingArgExecutable = true;
1263 //++ ------------------------------------------------------------------------------------
1264 // Details: Retrieve the MI Driver state indicating if it is operating in "its debugging
1265 // an executable passed as an argument" mode as against running via a client
1272 bool CMIDriver::IsDriverDebuggingArgExecutable( void ) const
1274 return m_bDriverDebuggingArgExecutable;