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.
96 CMIDriver::SetEnableFallThru(const bool vbYes)
98 m_bFallThruToOtherDriverEnabled = vbYes;
99 return MIstatus::success;
102 //++ ------------------------------------------------------------------------------------
103 // Details: Get whether *this driver (the parent) is enabled to pass a command to its
104 // fall through (child) driver to interpret the command and do work instead
105 // (if *this driver decides it can't hanled the command).
108 // Return: bool - True = yes fall through, false = do not pass on command.
112 CMIDriver::GetEnableFallThru(void) const
114 return m_bFallThruToOtherDriverEnabled;
117 //++ ------------------------------------------------------------------------------------
118 // Details: Retrieve MI's application name of itself.
121 // Return: CMIUtilString & - Text description.
124 const CMIUtilString &
125 CMIDriver::GetAppNameShort(void) const
127 return ms_constAppNameShort;
130 //++ ------------------------------------------------------------------------------------
131 // Details: Retrieve MI's application name of itself.
134 // Return: CMIUtilString & - Text description.
137 const CMIUtilString &
138 CMIDriver::GetAppNameLong(void) const
140 return ms_constAppNameLong;
143 //++ ------------------------------------------------------------------------------------
144 // Details: Retrieve MI's version description of itself.
147 // Return: CMIUtilString & - Text description.
150 const CMIUtilString &
151 CMIDriver::GetVersionDescription(void) const
153 return ms_constMIVersion;
156 //++ ------------------------------------------------------------------------------------
157 // Details: Initialize setup *this driver ready for use.
160 // Return: MIstatus::success - Functional succeeded.
161 // MIstatus::failure - Functional failed.
165 CMIDriver::Initialize(void)
167 m_eCurrentDriverState = eDriverState_Initialising;
168 m_clientUsageRefCnt++;
170 ClrErrorDescription();
173 return MIstatus::success;
175 bool bOk = MIstatus::success;
176 CMIUtilString errMsg;
178 // Initialize all of the modules we depend on
179 MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
180 MI::ModuleInit<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, errMsg);
181 MI::ModuleInit<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, errMsg);
182 MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
183 MI::ModuleInit<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg);
184 MI::ModuleInit<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, errMsg);
185 MI::ModuleInit<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
186 bOk &= m_rLldbDebugger.SetDriver(*this);
187 MI::ModuleInit<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, errMsg);
189 #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
190 CMIDriverMgr &rDrvMgr = CMIDriverMgr::Instance();
191 bOk = bOk && rDrvMgr.RegisterDriver(*g_driver, "LLDB driver"); // Will be pass thru driver
194 bOk = SetEnableFallThru(false); // This is intentional at this time - yet to be fully implemented
195 bOk = bOk && SetDriverToFallThruTo(*g_driver);
196 CMIUtilString strOtherDrvErrMsg;
197 if (bOk && GetEnableFallThru() && !g_driver->MISetup(strOtherDrvErrMsg))
200 errMsg = CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_FALLTHRUDRIVER), strOtherDrvErrMsg.c_str());
203 #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
207 m_bInitialized = bOk;
211 const CMIUtilString msg = CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_DRIVER), errMsg.c_str());
212 SetErrorDescription(msg);
213 return MIstatus::failure;
216 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
221 //++ ------------------------------------------------------------------------------------
222 // Details: Unbind detach or release resources used by *this driver.
225 // Return: MIstatus::success - Functional succeeded.
226 // MIstatus::failure - Functional failed.
230 CMIDriver::Shutdown(void)
232 if (--m_clientUsageRefCnt > 0)
233 return MIstatus::success;
236 return MIstatus::success;
238 m_eCurrentDriverState = eDriverState_ShuttingDown;
240 ClrErrorDescription();
242 bool bOk = MIstatus::success;
243 CMIUtilString errMsg;
245 // Shutdown all of the modules we depend on
246 MI::ModuleShutdown<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, errMsg);
247 MI::ModuleShutdown<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
248 MI::ModuleShutdown<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, errMsg);
249 MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg);
250 MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
251 MI::ModuleShutdown<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, errMsg);
252 MI::ModuleShutdown<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, errMsg);
253 MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
257 SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str());
260 m_eCurrentDriverState = eDriverState_NotRunning;
265 //++ ------------------------------------------------------------------------------------
266 // Details: Work function. Client (the driver's user) is able to append their own message
267 // in to the MI's Log trace file.
269 // Args: vMessage - (R) Client's text message.
270 // Return: MIstatus::success - Functional succeeded.
271 // MIstatus::failure - Functional failed.
275 CMIDriver::WriteMessageToLog(const CMIUtilString &vMessage)
278 msg = CMIUtilString::Format(MIRSRC(IDS_MI_CLIENT_MSG), vMessage.c_str());
279 return m_pLog->Write(msg, CMICmnLog::eLogVerbosity_ClientMsg);
282 //++ ------------------------------------------------------------------------------------
283 // Details: CDriverMgr calls *this driver initialize setup ready for use.
286 // Return: MIstatus::success - Functional succeeded.
287 // MIstatus::failure - Functional failed.
291 CMIDriver::DoInitialize(void)
293 return CMIDriver::Instance().Initialize();
296 //++ ------------------------------------------------------------------------------------
297 // Details: CDriverMgr calls *this driver to unbind detach or release resources used by
301 // Return: MIstatus::success - Functional succeeded.
302 // MIstatus::failure - Functional failed.
306 CMIDriver::DoShutdown(void)
308 return CMIDriver::Instance().Shutdown();
311 //++ ------------------------------------------------------------------------------------
312 // Details: Retrieve the name for *this driver.
315 // Return: CMIUtilString & - Driver name.
318 const CMIUtilString &
319 CMIDriver::GetName(void) const
321 const CMIUtilString &rName = GetAppNameLong();
322 const CMIUtilString &rVsn = GetVersionDescription();
323 static CMIUtilString strName = CMIUtilString::Format("%s %s", rName.c_str(), rVsn.c_str());
328 //++ ------------------------------------------------------------------------------------
329 // Details: Retrieve *this driver's last error condition.
332 // Return: CMIUtilString - Text description.
336 CMIDriver::GetError(void) const
338 return GetErrorDescription();
341 //++ ------------------------------------------------------------------------------------
342 // Details: Call *this driver to resize the console window.
344 // Args: vTermWidth - (R) New window column size.
345 // Return: MIstatus::success - Functional succeeded.
346 // MIstatus::failure - Functional failed.
350 CMIDriver::DoResizeWindow(const uint32_t vTermWidth)
352 GetTheDebugger().SetTerminalWidth(vTermWidth);
355 //++ ------------------------------------------------------------------------------------
356 // Details: Call *this driver to return it's debugger.
359 // Return: lldb::SBDebugger & - LLDB debugger object reference.
363 CMIDriver::GetTheDebugger(void)
365 return m_rLldbDebugger.GetTheDebugger();
368 //++ ------------------------------------------------------------------------------------
369 // Details: Specify another driver *this driver can call should this driver not be able
370 // to handle the client data input. DoFallThruToAnotherDriver() makes the call.
372 // Args: vrOtherDriver - (R) Reference to another driver object.
373 // Return: MIstatus::success - Functional succeeded.
374 // MIstatus::failure - Functional failed.
378 CMIDriver::SetDriverToFallThruTo(const CMIDriverBase &vrOtherDriver)
380 m_pDriverFallThru = const_cast<CMIDriverBase *>(&vrOtherDriver);
382 return m_pDriverFallThru->SetDriverParent(*this);
385 //++ ------------------------------------------------------------------------------------
386 // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this driver's
387 // implementation called from here to match the existing function name of the
388 // original LLDb driver class (the extra indirection is not necessarily required).
389 // Check the arguments that were passed to this program to make sure they are
390 // valid and to get their argument values (if any).
392 // Args: argc - (R) An integer that contains the count of arguments that follow in
393 // argv. The argc parameter is always greater than or equal to 1.
394 // argv - (R) An array of null-terminated strings representing command-line
395 // arguments entered by the user of the program. By convention,
396 // argv[0] is the command with which the program is invoked.
397 // vpStdOut - (R) Pointer to a standard output stream.
398 // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
399 // version information only.
400 // False = Continue to work, start debugger i.e. Command
402 // Return: lldb::SBError - LLDB current error status.
406 CMIDriver::DoParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool &vwbExiting)
408 return ParseArgs(argc, argv, vpStdOut, vwbExiting);
411 //++ ------------------------------------------------------------------------------------
412 // Details: Check the arguments that were passed to this program to make sure they are
413 // valid and to get their argument values (if any). The following are options
414 // that are only handled by *this driver:
416 // The application's options --interpreter and --executable in code act very similar.
417 // The --executable is necessary to differentiate whither the MI Driver is being
418 // using by a client i.e. Eclipse or from the command line. Eclipse issues the option
419 // --interpreter and also passes additional arguments which can be interpreted as an
420 // executable if called from the command line. Using --executable tells the MI
421 // Driver is being called the command line and that the executable argument is indeed
422 // a specified executable an so actions commands to set up the executable for a
423 // debug session. Using --interpreter on the commnd line does not action additional
424 // commands to initialise a debug session and so be able to launch the process.
426 // Args: argc - (R) An integer that contains the count of arguments that follow in
427 // argv. The argc parameter is always greater than or equal to 1.
428 // argv - (R) An array of null-terminated strings representing command-line
429 // arguments entered by the user of the program. By convention,
430 // argv[0] is the command with which the program is invoked.
431 // vpStdOut - (R) Pointer to a standard output stream.
432 // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
433 // version information only.
434 // False = Continue to work, start debugger i.e. Command
436 // Return: lldb::SBError - LLDB current error status.
440 CMIDriver::ParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool &vwbExiting)
442 lldb::SBError errStatus;
443 const bool bHaveArgs(argc >= 2);
445 // *** Add any args handled here to GetHelpOnCmdLineArgOptions() ***
447 // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
448 // Look for the command line options
449 bool bHaveExecutableFileNamePath = false;
450 bool bHaveExecutableLongOption = false;
454 // Search right to left to look for the executable
455 for (MIint i = argc - 1; i > 0; i--)
457 const CMIUtilString strArg(argv[i]);
458 const CMICmdArgValFile argFile;
459 if (argFile.IsFilePath(strArg) || CMICmdArgValString(true, false, true).IsStringArg(strArg))
461 bHaveExecutableFileNamePath = true;
462 m_strCmdLineArgExecuteableFileNamePath = argFile.GetFileNamePath(strArg);
463 m_bHaveExecutableFileNamePathOnCmdLine = true;
465 // This argument is also check for in CMIDriverMgr::ParseArgs()
466 if (0 == strArg.compare("--executable")) // Used to specify that there is executable argument also on the command line
467 { // See fn description.
468 bHaveExecutableLongOption = true;
473 if (bHaveExecutableFileNamePath && bHaveExecutableLongOption)
475 // CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
476 #if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
477 SetDriverDebuggingArgExecutable();
480 errStatus.SetErrorString(MIRSRC(IDS_DRIVER_ERR_LOCAL_DEBUG_NOT_IMPL));
481 #endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
487 //++ ------------------------------------------------------------------------------------
488 // Details: A client can ask if *this driver is GDB/MI compatible.
491 // Return: True - GBD/MI compatible LLDB front end.
492 // False - Not GBD/MI compatible LLDB front end.
496 CMIDriver::GetDriverIsGDBMICompatibleDriver(void) const
501 //++ ------------------------------------------------------------------------------------
502 // Details: Callback function for monitoring stream stdin object. Part of the visitor
504 // This function is called by the CMICmnStreamStdin::CThreadStdin
505 // "stdin monitor" thread (ID).
507 // Args: vStdInBuffer - (R) Copy of the current stdin line data.
508 // vrbYesExit - (RW) True = yes exit stdin monitoring, false = continue monitor.
509 // Return: MIstatus::success - Functional succeeded.
510 // MIstatus::failure - Functional failed.
514 CMIDriver::ReadLine(const CMIUtilString &vStdInBuffer, bool &vrwbYesExit)
516 // For debugging. Update prompt show stdin is working
517 // printf( "%s\n", vStdInBuffer.c_str() );
520 // Special case look for the quit command here so stop monitoring stdin stream
521 // So we do not go back to fgetc() and wait and hang thread on exit
522 if (vStdInBuffer == "quit")
525 // 1. Put new line in the queue container by stdin monitor thread
526 // 2. Then *this driver calls ReadStdinLineQueue() when ready to read the queue in its
528 const bool bOk = QueueMICommand(vStdInBuffer);
530 // Check to see if the *this driver is shutting down (exit application)
532 vrwbYesExit = m_bDriverIsExiting;
537 //++ ------------------------------------------------------------------------------------
538 // Details: Start worker threads for the driver.
541 // Return: MIstatus::success - Functional succeeded.
542 // MIstatus::failure - Functional failed.
546 CMIDriver::StartWorkerThreads(void)
548 bool bOk = MIstatus::success;
550 // Grab the thread manager
551 CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
553 // Start the stdin thread
554 bOk &= m_rStdin.SetVisitor(*this);
555 if (bOk && !rThreadMgr.ThreadStart<CMICmnStreamStdin>(m_rStdin))
557 const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE),
558 CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str());
559 SetErrorDescriptionn(errMsg);
560 return MIstatus::failure;
563 // Start the event polling thread
564 if (bOk && !rThreadMgr.ThreadStart<CMICmnLLDBDebugger>(m_rLldbDebugger))
566 const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE),
567 CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str());
568 SetErrorDescriptionn(errMsg);
569 return MIstatus::failure;
575 //++ ------------------------------------------------------------------------------------
576 // Details: Stop worker threads for the driver.
579 // Return: MIstatus::success - Functional succeeded.
580 // MIstatus::failure - Functional failed.
584 CMIDriver::StopWorkerThreads(void)
586 CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
587 return rThreadMgr.ThreadAllTerminate();
590 //++ ------------------------------------------------------------------------------------
591 // Details: Call this function puts *this driver to work.
592 // This function is used by the application's main thread.
595 // Return: MIstatus::success - Functional succeeded.
596 // MIstatus::failure - Functional failed.
600 CMIDriver::DoMainLoop(void)
602 if (!InitClientIDEToMIDriver()) // Init Eclipse IDE
604 SetErrorDescriptionn(MIRSRC(IDS_MI_INIT_ERR_CLIENT_USING_DRIVER));
605 return MIstatus::failure;
608 if (!StartWorkerThreads())
609 return MIstatus::failure;
611 // App is not quitting currently
614 // CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
615 #if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
616 if (HaveExecutableFileNamePathOnCmdLine())
618 if (!LocalDebugSessionStartupInjectCommands())
620 SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION));
621 return MIstatus::failure;
624 #endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
626 // While the app is active
629 // Poll stdin queue and dispatch
630 if (!ReadStdinLineQueue())
632 // Something went wrong
637 // Signal that the application is shutting down
640 // Close and wait for the workers to stop
643 // Ensure that a new line is sent as the last act of the dying driver
644 m_rStdOut.WriteMIResponse("\n", false);
646 return MIstatus::success;
649 //++ ------------------------------------------------------------------------------------
650 // Details: *this driver sits and waits for input to the stdin line queue shared by *this
651 // driver and the stdin monitor thread, it queues, *this reads, interprets and
653 // This function is used by the application's main thread.
656 // Return: MIstatus::success - Functional succeeded.
657 // MIstatus::failure - Functional failed.
661 CMIDriver::ReadStdinLineQueue(void)
663 // True when queue contains input
664 bool bHaveInput = false;
666 // Stores the current input line
667 CMIUtilString lineText;
669 // Lock while we access the queue
670 CMIUtilThreadLock lock(m_threadMutex);
671 if (!m_queueStdinLine.empty())
673 lineText = m_queueStdinLine.front();
674 m_queueStdinLine.pop();
675 bHaveInput = !lineText.empty();
679 // Process while we have input
682 if (lineText == "quit")
684 // We want to be exiting when receiving a quit command
686 return MIstatus::success;
689 // Process the command
690 const bool bOk = InterpretCommand(lineText);
692 // Draw prompt if desired
693 if (bOk && m_rStdin.GetEnablePrompt())
694 m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt());
696 // Input has been processed
701 // Give resources back to the OS
702 const std::chrono::milliseconds time(1);
703 std::this_thread::sleep_for(time);
706 return MIstatus::success;
709 //++ ------------------------------------------------------------------------------------
710 // Details: Set things in motion, set state etc that brings *this driver (and the
711 // application) to a tidy shutdown.
712 // This function is used by the application's main thread.
715 // Return: MIstatus::success - Functional succeeded.
716 // MIstatus::failure - Functional failed.
720 CMIDriver::DoAppQuit(void)
722 bool bYesQuit = true;
724 // Shutdown stuff, ready app for exit
726 CMIUtilThreadLock lock(m_threadMutex);
727 m_bDriverIsExiting = true;
733 //++ ------------------------------------------------------------------------------------
734 // Details: *this driver passes text commands to a fall through driver is it does not
735 // understand them (the LLDB driver).
736 // This function is used by the application's main thread.
738 // Args: vTextLine - (R) Text data representing a possible command.
739 // vwbCmdYesValid - (W) True = Command valid, false = command not handled.
740 // Return: MIstatus::success - Functional succeeded.
741 // MIstatus::failure - Functional failed.
745 CMIDriver::InterpretCommandFallThruDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid)
748 MIunused(vwbCmdYesValid);
750 // ToDo: Implement when less urgent work to be done or decide remove as not required
751 // bool bOk = MIstatus::success;
752 // bool bCmdNotUnderstood = true;
753 // if( bCmdNotUnderstood && GetEnableFallThru() )
755 // CMIUtilString errMsg;
756 // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg );
759 // errMsg = errMsg.StripCREndOfLine();
760 // errMsg = errMsg.StripCRAll();
761 // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
762 // const MIchar * pName = pOtherDriver->GetDriverName().c_str();
763 // const MIchar * pId = pOtherDriver->GetDriverId().c_str();
764 // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() )
766 // m_pLog->WriteMsg( msg );
770 // vwbCmdYesValid = bOk;
771 // CMIUtilString strNot;
772 // if( vwbCmdYesValid)
773 // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) );
774 // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) );
775 // m_pLog->WriteLog( msg );
777 return MIstatus::success;
780 //++ ------------------------------------------------------------------------------------
781 // Details: Retrieve the name for *this driver.
784 // Return: CMIUtilString & - Driver name.
787 const CMIUtilString &
788 CMIDriver::GetDriverName(void) const
793 //++ ------------------------------------------------------------------------------------
794 // Details: Get the unique ID for *this driver.
797 // Return: CMIUtilString & - Text description.
800 const CMIUtilString &
801 CMIDriver::GetDriverId(void) const
806 //++ ------------------------------------------------------------------------------------
807 // Details: This function allows *this driver to call on another driver to perform work
808 // should this driver not be able to handle the client data input.
809 // SetDriverToFallThruTo() specifies the fall through to driver.
810 // Check the error message if the function returns a failure.
812 // Args: vCmd - (R) Command instruction to interpret.
813 // vwErrMsg - (W) Error description on command failing.
814 // Return: MIstatus::success - Command succeeded.
815 // MIstatus::failure - Command failed.
819 CMIDriver::DoFallThruToAnotherDriver(const CMIUtilString &vCmd, CMIUtilString &vwErrMsg)
821 bool bOk = MIstatus::success;
823 CMIDriverBase *pOtherDriver = GetDriverToFallThruTo();
824 if (pOtherDriver == nullptr)
827 return pOtherDriver->DoFallThruToAnotherDriver(vCmd, vwErrMsg);
830 //++ ------------------------------------------------------------------------------------
831 // Details: *this driver provides a file stream to other drivers on which *this driver
832 // write's out to and they read as expected input. *this driver is passing
833 // through commands to the (child) pass through assigned driver.
834 // Type: Overrdidden.
836 // Return: FILE * - Pointer to stream.
840 CMIDriver::GetStdin(void) const
842 // Note this fn is called on CMIDriverMgr register driver so stream has to be
843 // available before *this driver has been initialized! Flaw?
845 // This very likely to change later to a stream that the pass thru driver
846 // will read and we write to give it 'input'
850 //++ ------------------------------------------------------------------------------------
851 // Details: *this driver provides a file stream to other pass through assigned drivers
852 // so they know what to write to.
855 // Return: FILE * - Pointer to stream.
859 CMIDriver::GetStdout(void) const
861 // Note this fn is called on CMIDriverMgr register driver so stream has to be
862 // available before *this driver has been initialized! Flaw?
864 // Do not want to pass through driver to write to stdout
868 //++ ------------------------------------------------------------------------------------
869 // Details: *this driver provides a error file stream to other pass through assigned drivers
870 // so they know what to write to.
873 // Return: FILE * - Pointer to stream.
877 CMIDriver::GetStderr(void) const
879 // Note this fn is called on CMIDriverMgr register driver so stream has to be
880 // available before *this driver has been initialized! Flaw?
882 // This very likely to change later to a stream that the pass thru driver
883 // will write to and *this driver reads from to pass on the CMICmnLog object
887 //++ ------------------------------------------------------------------------------------
888 // Details: Set a unique ID for *this driver. It cannot be empty.
890 // Args: vId - (R) Text description.
891 // Return: MIstatus::success - Functional succeeded.
892 // MIstatus::failure - Functional failed.
896 CMIDriver::SetId(const CMIUtilString &vId)
900 SetErrorDescriptionn(MIRSRC(IDS_DRIVER_ERR_ID_INVALID), GetName().c_str(), vId.c_str());
901 return MIstatus::failure;
905 return MIstatus::success;
908 //++ ------------------------------------------------------------------------------------
909 // Details: Get the unique ID for *this driver.
912 // Return: CMIUtilString & - Text description.
915 const CMIUtilString &
916 CMIDriver::GetId(void) const
918 return m_strDriverId;
921 //++ ------------------------------------------------------------------------------------
922 // Details: Inject a command into the command processing system to be interpreted as a
923 // command read from stdin. The text representing the command is also written
924 // out to stdout as the command did not come from via stdin.
926 // Args: vMICmd - (R) Text data representing a possible command.
927 // Return: MIstatus::success - Functional succeeded.
928 // MIstatus::failure - Functional failed.
932 CMIDriver::InjectMICommand(const CMIUtilString &vMICmd)
934 const bool bOk = m_rStdOut.WriteMIResponse(vMICmd);
936 return bOk && QueueMICommand(vMICmd);
939 //++ ------------------------------------------------------------------------------------
940 // Details: Add a new command candidate to the command queue to be processed by the
943 // Args: vMICmd - (R) Text data representing a possible command.
944 // Return: MIstatus::success - Functional succeeded.
945 // MIstatus::failure - Functional failed.
949 CMIDriver::QueueMICommand(const CMIUtilString &vMICmd)
951 CMIUtilThreadLock lock(m_threadMutex);
952 m_queueStdinLine.push(vMICmd);
954 return MIstatus::success;
957 //++ ------------------------------------------------------------------------------------
958 // Details: Interpret the text data and match against current commands to see if there
959 // is a match. If a match then the command is issued and actioned on. The
960 // text data if not understood by *this driver is past on to the Fall Thru
962 // This function is used by the application's main thread.
964 // Args: vTextLine - (R) Text data representing a possible command.
965 // Return: MIstatus::success - Functional succeeded.
966 // MIstatus::failure - Functional failed.
970 CMIDriver::InterpretCommand(const CMIUtilString &vTextLine)
972 bool bCmdYesValid = false;
973 bool bOk = InterpretCommandThisDriver(vTextLine, bCmdYesValid);
974 if (bOk && !bCmdYesValid)
975 bOk = InterpretCommandFallThruDriver(vTextLine, bCmdYesValid);
980 //++ ------------------------------------------------------------------------------------
981 // Details: Interpret the text data and match against current commands to see if there
982 // is a match. If a match then the command is issued and actioned on. If a
983 // command cannot be found to match then vwbCmdYesValid is set to false and
984 // nothing else is done here.
985 // This function is used by the application's main thread.
987 // Args: vTextLine - (R) Text data representing a possible command.
988 // vwbCmdYesValid - (W) True = Command invalid, false = command acted on.
989 // Return: MIstatus::success - Functional succeeded.
990 // MIstatus::failure - Functional failed.
994 CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid)
996 vwbCmdYesValid = false;
998 bool bCmdNotInCmdFactor = false;
1000 CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
1001 if (!rCmdMgr.CmdInterpret(vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData))
1002 return MIstatus::failure;
1006 // For debugging only
1007 // m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() );
1009 return ExecuteCommand(cmdData);
1012 // Check for escape character, may be cursor control characters
1013 // This code is not necessary for application operation, just want to keep tabs on what
1014 // is been given to the driver to try and intepret.
1015 if (vTextLine.at(0) == 27)
1017 CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS));
1018 for (MIuint i = 0; i < vTextLine.length(); i++)
1020 logInput += CMIUtilString::Format("%d ", vTextLine.at(i));
1022 m_pLog->WriteLog(logInput);
1023 return MIstatus::success;
1026 // Write to the Log that a 'command' was not valid.
1027 // Report back to the MI client via MI result record.
1028 CMIUtilString strNotInCmdFactory;
1029 if (bCmdNotInCmdFactor)
1030 strNotInCmdFactory = CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str());
1031 const CMIUtilString strNot(CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT)));
1032 const CMIUtilString msg(
1033 CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str()));
1034 const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg);
1035 const CMICmnMIValueResult valueResult("msg", vconst);
1036 const CMICmnMIResultRecord miResultRecord(cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult);
1037 m_rStdOut.WriteMIResponse(miResultRecord.GetString());
1039 // Proceed to wait for or execute next command
1040 return MIstatus::success;
1043 //++ ------------------------------------------------------------------------------------
1044 // Details: Having previously had the potential command validated and found valid now
1045 // get the command executed.
1046 // This function is used by the application's main thread.
1048 // Args: vCmdData - (RW) Command meta data.
1049 // Return: MIstatus::success - Functional succeeded.
1050 // MIstatus::failure - Functional failed.
1054 CMIDriver::ExecuteCommand(const SMICmdData &vCmdData)
1056 CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
1057 return rCmdMgr.CmdExecute(vCmdData);
1060 //++ ------------------------------------------------------------------------------------
1061 // Details: Set the MI Driver's exit application flag. The application checks this flag
1062 // after every stdin line is read so the exit may not be instantaneous.
1063 // If vbForceExit is false the MI Driver queries its state and determines if is
1064 // should exit or continue operating depending on that running state.
1065 // This is related to the running state of the MI driver.
1066 // Type: Overridden.
1072 CMIDriver::SetExitApplicationFlag(const bool vbForceExit)
1076 CMIUtilThreadLock lock(m_threadMutex);
1078 m_rStdin.OnExitHandler();
1082 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1083 // Did we receive a SIGINT from the client during a running debug program, if
1084 // so then SIGINT is not to be taken as meaning kill the MI driver application
1085 // but halt the inferior program being debugged instead
1086 if (m_eCurrentDriverState == eDriverState_RunningDebugging)
1088 InjectMICommand("-exec-interrupt");
1093 m_rStdin.OnExitHandler();
1096 //++ ------------------------------------------------------------------------------------
1097 // Details: Get the MI Driver's exit exit application flag.
1098 // This is related to the running state of the MI driver.
1101 // Return: bool - True = MI Driver is shutting down, false = MI driver is running.
1105 CMIDriver::GetExitApplicationFlag(void) const
1110 //++ ------------------------------------------------------------------------------------
1111 // Details: Get the current running state of the MI Driver.
1114 // Return: DriverState_e - The current running state of the application.
1117 CMIDriver::DriverState_e
1118 CMIDriver::GetCurrentDriverState(void) const
1120 return m_eCurrentDriverState;
1123 //++ ------------------------------------------------------------------------------------
1124 // Details: Set the current running state of the MI Driver to running and currently not in
1127 // Return: MIstatus::success - Functionality succeeded.
1128 // MIstatus::failure - Functionality failed.
1129 // Return: DriverState_e - The current running state of the application.
1133 CMIDriver::SetDriverStateRunningNotDebugging(void)
1135 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1137 if (m_eCurrentDriverState == eDriverState_RunningNotDebugging)
1138 return MIstatus::success;
1140 // Driver cannot be in the following states to set eDriverState_RunningNotDebugging
1141 switch (m_eCurrentDriverState)
1143 case eDriverState_NotRunning:
1144 case eDriverState_Initialising:
1145 case eDriverState_ShuttingDown:
1147 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1148 return MIstatus::failure;
1150 case eDriverState_RunningDebugging:
1151 case eDriverState_RunningNotDebugging:
1153 case eDriverState_count:
1154 SetErrorDescription(
1155 CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE), "SetDriverStateRunningNotDebugging()"));
1156 return MIstatus::failure;
1159 // Driver must be in this state to set eDriverState_RunningNotDebugging
1160 if (m_eCurrentDriverState != eDriverState_RunningDebugging)
1162 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1163 return MIstatus::failure;
1166 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
1168 return MIstatus::success;
1171 //++ ------------------------------------------------------------------------------------
1172 // Details: Set the current running state of the MI Driver to running and currently not in
1173 // a debug session. The driver's state must in the state running and in a
1174 // debug session to set this new state.
1176 // Return: MIstatus::success - Functionality succeeded.
1177 // MIstatus::failure - Functionality failed.
1178 // Return: DriverState_e - The current running state of the application.
1182 CMIDriver::SetDriverStateRunningDebugging(void)
1184 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1186 if (m_eCurrentDriverState == eDriverState_RunningDebugging)
1187 return MIstatus::success;
1189 // Driver cannot be in the following states to set eDriverState_RunningDebugging
1190 switch (m_eCurrentDriverState)
1192 case eDriverState_NotRunning:
1193 case eDriverState_Initialising:
1194 case eDriverState_ShuttingDown:
1196 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1197 return MIstatus::failure;
1199 case eDriverState_RunningDebugging:
1200 case eDriverState_RunningNotDebugging:
1202 case eDriverState_count:
1203 SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE), "SetDriverStateRunningDebugging()"));
1204 return MIstatus::failure;
1207 // Driver must be in this state to set eDriverState_RunningDebugging
1208 if (m_eCurrentDriverState != eDriverState_RunningNotDebugging)
1210 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1211 return MIstatus::failure;
1214 m_eCurrentDriverState = eDriverState_RunningDebugging;
1216 return MIstatus::success;
1219 //++ ------------------------------------------------------------------------------------
1220 // Details: Prepare the client IDE so it will start working/communicating with *this MI
1224 // Return: MIstatus::success - Functionality succeeded.
1225 // MIstatus::failure - Functionality failed.
1229 CMIDriver::InitClientIDEToMIDriver(void) const
1231 // Put other IDE init functions here
1232 return InitClientIDEEclipse();
1235 //++ ------------------------------------------------------------------------------------
1236 // Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character
1237 // sequence otherwise it refuses to communicate and times out. This should be
1238 // sent to Eclipse before anything else.
1241 // Return: MIstatus::success - Functionality succeeded.
1242 // MIstatus::failure - Functionality failed.
1246 CMIDriver::InitClientIDEEclipse(void) const
1248 std::cout << "(gdb)" << std::endl;
1250 return MIstatus::success;
1253 //++ ------------------------------------------------------------------------------------
1254 // Details: Ask *this driver whether it found an executable in the MI Driver's list of
1255 // arguments which to open and debug. If so instigate commands to set up a debug
1256 // session for that executable.
1259 // Return: bool - True = True = Yes executable given as one of the parameters to the MI
1261 // False = not found.
1265 CMIDriver::HaveExecutableFileNamePathOnCmdLine(void) const
1267 return m_bHaveExecutableFileNamePathOnCmdLine;
1270 //++ ------------------------------------------------------------------------------------
1271 // Details: Retrieve from *this driver executable file name path to start a debug session
1272 // with (if present see HaveExecutableFileNamePathOnCmdLine()).
1275 // Return: CMIUtilString & - Executeable file name path or empty string.
1278 const CMIUtilString &
1279 CMIDriver::GetExecutableFileNamePathOnCmdLine(void) const
1281 return m_strCmdLineArgExecuteableFileNamePath;
1284 //++ ------------------------------------------------------------------------------------
1285 // Details: Execute commands (by injecting them into the stdin line queue container) and
1286 // other code to set up the MI Driver such that is can take the executable
1287 // argument passed on the command and create a debug session for it.
1290 // Return: MIstatus::success - Functionality succeeded.
1291 // MIstatus::failure - Functionality failed.
1295 CMIDriver::LocalDebugSessionStartupInjectCommands(void)
1297 const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols %s", m_strCmdLineArgExecuteableFileNamePath.c_str()));
1299 return InjectMICommand(strCmd);
1302 //++ ------------------------------------------------------------------------------------
1303 // Details: Set the MI Driver into "its debugging an executable passed as an argument"
1304 // mode as against running via a client like Eclipse.
1311 CMIDriver::SetDriverDebuggingArgExecutable(void)
1313 m_bDriverDebuggingArgExecutable = true;
1316 //++ ------------------------------------------------------------------------------------
1317 // Details: Retrieve the MI Driver state indicating if it is operating in "its debugging
1318 // an executable passed as an argument" mode as against running via a client
1326 CMIDriver::IsDriverDebuggingArgExecutable(void) const
1328 return m_bDriverDebuggingArgExecutable;