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 //===----------------------------------------------------------------------===//
10 // Third party headers:
11 #include "lldb/API/SBError.h"
17 #include "MICmdArgValFile.h"
18 #include "MICmdArgValString.h"
20 #include "MICmnConfig.h"
21 #include "MICmnLLDBDebugSessionInfo.h"
22 #include "MICmnLLDBDebugger.h"
24 #include "MICmnMIResultRecord.h"
25 #include "MICmnMIValueConst.h"
26 #include "MICmnResources.h"
27 #include "MICmnStreamStderr.h"
28 #include "MICmnStreamStdout.h"
29 #include "MICmnThreadMgrStd.h"
31 #include "MIUtilDebug.h"
32 #include "MIUtilSingletonHelper.h"
36 const CMIUtilString CMIDriver::ms_constMIVersion =
37 MIRSRC(IDS_MI_VERSION_DESCRIPTION_DEBUG);
39 const CMIUtilString CMIDriver::ms_constMIVersion =
40 MIRSRC(IDS_MI_VERSION_DESCRIPTION); // Matches version in resources file
43 CMIDriver::ms_constAppNameShort(MIRSRC(IDS_MI_APPNAME_SHORT));
44 const CMIUtilString CMIDriver::ms_constAppNameLong(MIRSRC(IDS_MI_APPNAME_LONG));
47 //------------------------------------------------------------------------------------
48 // Details: CMIDriver constructor.
54 CMIDriver::CMIDriver()
55 : m_bFallThruToOtherDriverEnabled(false), m_bDriverIsExiting(false),
56 m_handleMainThread(0), m_rStdin(CMICmnStreamStdin::Instance()),
57 m_rLldbDebugger(CMICmnLLDBDebugger::Instance()),
58 m_rStdOut(CMICmnStreamStdout::Instance()),
59 m_eCurrentDriverState(eDriverState_NotRunning),
60 m_bHaveExecutableFileNamePathOnCmdLine(false),
61 m_bDriverDebuggingArgExecutable(false),
62 m_bHaveCommandFileNamePathOnCmdLine(false) {}
65 //------------------------------------------------------------------------------------
66 // Details: CMIDriver destructor.
72 CMIDriver::~CMIDriver() {}
75 //------------------------------------------------------------------------------------
76 // Details: Set whether *this driver (the parent) is enabled to pass a command
78 // fall through (child) driver to interpret the command and do work
80 // (if *this driver decides it can't handle the command).
82 // Args: vbYes - (R) True = yes fall through, false = do not pass on
84 // Return: MIstatus::success - Functional succeeded.
85 // MIstatus::failure - Functional failed.
88 bool CMIDriver::SetEnableFallThru(const bool vbYes) {
89 m_bFallThruToOtherDriverEnabled = vbYes;
90 return MIstatus::success;
94 //------------------------------------------------------------------------------------
95 // Details: Get whether *this driver (the parent) is enabled to pass a command
97 // fall through (child) driver to interpret the command and do work
99 // (if *this driver decides it can't handle the command).
102 // Return: bool - True = yes fall through, false = do not pass on command.
105 bool CMIDriver::GetEnableFallThru() const {
106 return m_bFallThruToOtherDriverEnabled;
110 //------------------------------------------------------------------------------------
111 // Details: Retrieve MI's application name of itself.
114 // Return: CMIUtilString & - Text description.
117 const CMIUtilString &CMIDriver::GetAppNameShort() const {
118 return ms_constAppNameShort;
122 //------------------------------------------------------------------------------------
123 // Details: Retrieve MI's application name of itself.
126 // Return: CMIUtilString & - Text description.
129 const CMIUtilString &CMIDriver::GetAppNameLong() const {
130 return ms_constAppNameLong;
134 //------------------------------------------------------------------------------------
135 // Details: Retrieve MI's version description of itself.
138 // Return: CMIUtilString & - Text description.
141 const CMIUtilString &CMIDriver::GetVersionDescription() const {
142 return ms_constMIVersion;
146 //------------------------------------------------------------------------------------
147 // Details: Initialize setup *this driver ready for use.
150 // Return: MIstatus::success - Functional succeeded.
151 // MIstatus::failure - Functional failed.
154 bool CMIDriver::Initialize() {
155 m_eCurrentDriverState = eDriverState_Initialising;
156 m_clientUsageRefCnt++;
158 ClrErrorDescription();
161 return MIstatus::success;
163 bool bOk = MIstatus::success;
164 CMIUtilString errMsg;
166 // Initialize all of the modules we depend on
167 MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
168 MI::ModuleInit<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, errMsg);
169 MI::ModuleInit<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, errMsg);
170 MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
171 MI::ModuleInit<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk,
173 MI::ModuleInit<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, errMsg);
174 MI::ModuleInit<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
175 bOk &= m_rLldbDebugger.SetDriver(*this);
176 MI::ModuleInit<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, errMsg);
180 m_bInitialized = bOk;
183 const CMIUtilString msg =
184 CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_DRIVER), errMsg.c_str());
185 SetErrorDescription(msg);
186 return MIstatus::failure;
189 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
195 //------------------------------------------------------------------------------------
196 // Details: Unbind detach or release resources used by *this driver.
199 // Return: MIstatus::success - Functional succeeded.
200 // MIstatus::failure - Functional failed.
203 bool CMIDriver::Shutdown() {
204 if (--m_clientUsageRefCnt > 0)
205 return MIstatus::success;
208 return MIstatus::success;
210 m_eCurrentDriverState = eDriverState_ShuttingDown;
212 ClrErrorDescription();
214 bool bOk = MIstatus::success;
215 CMIUtilString errMsg;
217 // Shutdown all of the modules we depend on
218 MI::ModuleShutdown<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk,
220 MI::ModuleShutdown<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
221 MI::ModuleShutdown<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk,
223 MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk,
225 MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
226 MI::ModuleShutdown<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk,
228 MI::ModuleShutdown<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk,
230 MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
233 SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str());
236 m_eCurrentDriverState = eDriverState_NotRunning;
242 //------------------------------------------------------------------------------------
243 // Details: Work function. Client (the driver's user) is able to append their
245 // in to the MI's Log trace file.
247 // Args: vMessage - (R) Client's text message.
248 // Return: MIstatus::success - Functional succeeded.
249 // MIstatus::failure - Functional failed.
252 bool CMIDriver::WriteMessageToLog(const CMIUtilString &vMessage) {
254 msg = CMIUtilString::Format(MIRSRC(IDS_MI_CLIENT_MSG), vMessage.c_str());
255 return m_pLog->Write(msg, CMICmnLog::eLogVerbosity_ClientMsg);
259 //------------------------------------------------------------------------------------
260 // Details: CDriverMgr calls *this driver initialize setup ready for use.
263 // Return: MIstatus::success - Functional succeeded.
264 // MIstatus::failure - Functional failed.
267 bool CMIDriver::DoInitialize() { return CMIDriver::Instance().Initialize(); }
270 //------------------------------------------------------------------------------------
271 // Details: CDriverMgr calls *this driver to unbind detach or release resources
276 // Return: MIstatus::success - Functional succeeded.
277 // MIstatus::failure - Functional failed.
280 bool CMIDriver::DoShutdown() { return CMIDriver::Instance().Shutdown(); }
283 //------------------------------------------------------------------------------------
284 // Details: Retrieve the name for *this driver.
287 // Return: CMIUtilString & - Driver name.
290 const CMIUtilString &CMIDriver::GetName() const {
291 const CMIUtilString &rName = GetAppNameLong();
292 const CMIUtilString &rVsn = GetVersionDescription();
293 static CMIUtilString strName =
294 CMIUtilString::Format("%s %s", rName.c_str(), rVsn.c_str());
300 //------------------------------------------------------------------------------------
301 // Details: Retrieve *this driver's last error condition.
304 // Return: CMIUtilString - Text description.
307 CMIUtilString CMIDriver::GetError() const { return GetErrorDescription(); }
310 //------------------------------------------------------------------------------------
311 // Details: Call *this driver to return it's debugger.
314 // Return: lldb::SBDebugger & - LLDB debugger object reference.
317 lldb::SBDebugger &CMIDriver::GetTheDebugger() {
318 return m_rLldbDebugger.GetTheDebugger();
322 //------------------------------------------------------------------------------------
323 // Details: Specify another driver *this driver can call should this driver not
325 // to handle the client data input. DoFallThruToAnotherDriver() makes
328 // Args: vrOtherDriver - (R) Reference to another driver object.
329 // Return: MIstatus::success - Functional succeeded.
330 // MIstatus::failure - Functional failed.
333 bool CMIDriver::SetDriverToFallThruTo(const CMIDriverBase &vrOtherDriver) {
334 m_pDriverFallThru = const_cast<CMIDriverBase *>(&vrOtherDriver);
336 return m_pDriverFallThru->SetDriverParent(*this);
340 //------------------------------------------------------------------------------------
341 // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this
343 // implementation called from here to match the existing function name
345 // original LLDB driver class (the extra indirection is not necessarily
347 // Check the arguments that were passed to this program to make sure
349 // valid and to get their argument values (if any).
351 // Args: argc - (R) An integer that contains the count of arguments
353 // argv. The argc parameter is always greater than
355 // argv - (R) An array of null-terminated strings representing
357 // arguments entered by the user of the program. By
359 // argv[0] is the command with which the program is
361 // vpStdOut - (R) Pointer to a standard output stream.
362 // vwbExiting - (W) True = *this want to exit, Reasons: help,
364 // version information only.
365 // False = Continue to work, start debugger i.e.
368 // Return: lldb::SBError - LLDB current error status.
371 lldb::SBError CMIDriver::DoParseArgs(const int argc, const char *argv[],
372 FILE *vpStdOut, bool &vwbExiting) {
373 return ParseArgs(argc, argv, vpStdOut, vwbExiting);
377 //------------------------------------------------------------------------------------
378 // Details: Check the arguments that were passed to this program to make sure
380 // valid and to get their argument values (if any). The following are
382 // that are only handled by *this driver:
383 // --executable <file>
384 // --source <file> or -s <file>
386 // The application's options --interpreter and --executable in code act
388 // The --executable is necessary to differentiate whether the MI Driver
390 // used by a client (e.g. Eclipse) or from the command line. Eclipse
392 // --interpreter and also passes additional arguments which can be
394 // executable if called from the command line. Using --executable tells
396 // it is being called from the command line and to prepare to launch
398 // argument for a debug session. Using --interpreter on the command
400 // issue additional commands to initialise a debug session.
401 // Option --synchronous disables an asynchronous mode in the lldb-mi driver.
403 // Args: argc - (R) An integer that contains the count of arguments
405 // argv. The argc parameter is always greater than
407 // argv - (R) An array of null-terminated strings representing
409 // arguments entered by the user of the program. By
411 // argv[0] is the command with which the program is
413 // vpStdOut - (R) Pointer to a standard output stream.
414 // vwbExiting - (W) True = *this want to exit, Reasons: help,
416 // version information only.
417 // False = Continue to work, start debugger i.e.
420 // Return: lldb::SBError - LLDB current error status.
423 lldb::SBError CMIDriver::ParseArgs(const int argc, const char *argv[],
424 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;
436 // Search right to left to look for filenames
437 for (MIint i = argc - 1; i > 0; i--) {
438 const CMIUtilString strArg(argv[i]);
439 const CMICmdArgValFile argFile;
441 // Check for a filename
442 if (argFile.IsFilePath(strArg) ||
443 CMICmdArgValString(true, false, true).IsStringArg(strArg)) {
444 // Is this the command file for the '-s' or '--source' options?
445 const CMIUtilString strPrevArg(argv[i - 1]);
446 if (strPrevArg.compare("-s") == 0 ||
447 strPrevArg.compare("--source") == 0) {
448 m_strCmdLineArgCommandFileNamePath = strArg;
449 m_bHaveCommandFileNamePathOnCmdLine = true;
450 i--; // skip '-s' on the next loop
453 // Else, must be the executable
454 bHaveExecutableFileNamePath = true;
455 m_strCmdLineArgExecuteableFileNamePath = strArg;
456 m_bHaveExecutableFileNamePathOnCmdLine = true;
458 // Report error if no command file was specified for the '-s' or
459 // '--source' options
460 else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) {
462 const CMIUtilString errMsg = CMIUtilString::Format(
463 MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str());
464 errStatus.SetErrorString(errMsg.c_str());
467 // This argument is also checked for in CMIDriverMgr::ParseArgs()
468 else if (strArg.compare("--executable") == 0) // Used to specify that
469 // there is executable
470 // argument also on the
472 { // See fn description.
473 bHaveExecutableLongOption = true;
474 } else if (strArg.compare("--synchronous") == 0) {
475 CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().SetAsync(false);
480 if (bHaveExecutableFileNamePath && bHaveExecutableLongOption) {
481 SetDriverDebuggingArgExecutable();
488 //------------------------------------------------------------------------------------
489 // Details: A client can ask if *this driver is GDB/MI compatible.
492 // Return: True - GBD/MI compatible LLDB front end.
493 // False - Not GBD/MI compatible LLDB front end.
496 bool CMIDriver::GetDriverIsGDBMICompatibleDriver() const { return true; }
499 //------------------------------------------------------------------------------------
500 // Details: Start worker threads for the driver.
503 // Return: MIstatus::success - Functional succeeded.
504 // MIstatus::failure - Functional failed.
507 bool CMIDriver::StartWorkerThreads() {
508 bool bOk = MIstatus::success;
510 // Grab the thread manager
511 CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
513 // Start the event polling thread
514 if (bOk && !rThreadMgr.ThreadStart<CMICmnLLDBDebugger>(m_rLldbDebugger)) {
515 const CMIUtilString errMsg = CMIUtilString::Format(
516 MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE),
517 CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str());
518 SetErrorDescription(errMsg);
519 return MIstatus::failure;
526 //------------------------------------------------------------------------------------
527 // Details: Stop worker threads for the driver.
530 // Return: MIstatus::success - Functional succeeded.
531 // MIstatus::failure - Functional failed.
534 bool CMIDriver::StopWorkerThreads() {
535 CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
536 return rThreadMgr.ThreadAllTerminate();
540 //------------------------------------------------------------------------------------
541 // Details: Call this function puts *this driver to work.
542 // This function is used by the application's main thread.
545 // Return: MIstatus::success - Functional succeeded.
546 // MIstatus::failure - Functional failed.
549 bool CMIDriver::DoMainLoop() {
550 if (!InitClientIDEToMIDriver()) // Init Eclipse IDE
552 SetErrorDescriptionn(MIRSRC(IDS_MI_INIT_ERR_CLIENT_USING_DRIVER));
553 return MIstatus::failure;
556 if (!StartWorkerThreads())
557 return MIstatus::failure;
559 bool bOk = MIstatus::success;
561 if (HaveExecutableFileNamePathOnCmdLine()) {
562 if (!LocalDebugSessionStartupExecuteCommands()) {
563 SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION));
564 bOk = MIstatus::failure;
568 // App is not quitting currently
571 // Handle source file
572 if (m_bHaveCommandFileNamePathOnCmdLine) {
573 const bool bAsyncMode = false;
574 ExecuteCommandFile(bAsyncMode);
577 // While the app is active
578 while (bOk && !m_bExitApp) {
579 CMIUtilString errorText;
580 const char *pCmd = m_rStdin.ReadLine(errorText);
581 if (pCmd != nullptr) {
582 CMIUtilString lineText(pCmd);
583 if (!lineText.empty()) {
584 // Check that the handler thread is alive (otherwise we stuck here)
585 assert(CMICmnLLDBDebugger::Instance().ThreadIsActive());
588 // Lock Mutex before processing commands so that we don't disturb an
591 CMIUtilThreadLock lock(
592 CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
593 bOk = InterpretCommand(lineText);
596 // Draw prompt if desired
597 bOk = bOk && CMICmnStreamStdout::WritePrompt();
599 // Wait while the handler thread handles incoming events
600 CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
605 // Signal that the application is shutting down
608 // Close and wait for the workers to stop
611 return MIstatus::success;
615 //------------------------------------------------------------------------------------
616 // Details: Set things in motion, set state etc that brings *this driver (and
618 // application) to a tidy shutdown.
619 // This function is used by the application's main thread.
622 // Return: MIstatus::success - Functional succeeded.
623 // MIstatus::failure - Functional failed.
626 bool CMIDriver::DoAppQuit() {
627 bool bYesQuit = true;
629 // Shutdown stuff, ready app for exit
631 CMIUtilThreadLock lock(m_threadMutex);
632 m_bDriverIsExiting = true;
639 //------------------------------------------------------------------------------------
640 // Details: *this driver passes text commands to a fall through driver is it
642 // understand them (the LLDB driver).
643 // This function is used by the application's main thread.
645 // Args: vTextLine - (R) Text data representing a possible command.
646 // vwbCmdYesValid - (W) True = Command valid, false = command not
648 // Return: MIstatus::success - Functional succeeded.
649 // MIstatus::failure - Functional failed.
652 bool CMIDriver::InterpretCommandFallThruDriver(const CMIUtilString &vTextLine,
653 bool &vwbCmdYesValid) {
655 MIunused(vwbCmdYesValid);
657 // ToDo: Implement when less urgent work to be done or decide remove as not
659 // bool bOk = MIstatus::success;
660 // bool bCmdNotUnderstood = true;
661 // if( bCmdNotUnderstood && GetEnableFallThru() )
663 // CMIUtilString errMsg;
664 // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg );
667 // errMsg = errMsg.StripCREndOfLine();
668 // errMsg = errMsg.StripCRAll();
669 // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
670 // const char * pName = pOtherDriver->GetDriverName().c_str();
671 // const char * pId = pOtherDriver->GetDriverId().c_str();
672 // const CMIUtilString msg( CMIUtilString::Format( MIRSRC(
673 // IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() )
675 // m_pLog->WriteMsg( msg );
679 // vwbCmdYesValid = bOk;
680 // CMIUtilString strNot;
681 // if( vwbCmdYesValid)
682 // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) );
683 // const CMIUtilString msg( CMIUtilString::Format( MIRSRC(
684 // IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) );
685 // m_pLog->WriteLog( msg );
687 return MIstatus::success;
691 //------------------------------------------------------------------------------------
692 // Details: Retrieve the name for *this driver.
695 // Return: CMIUtilString & - Driver name.
698 const CMIUtilString &CMIDriver::GetDriverName() const { return GetName(); }
701 //------------------------------------------------------------------------------------
702 // Details: Get the unique ID for *this driver.
705 // Return: CMIUtilString & - Text description.
708 const CMIUtilString &CMIDriver::GetDriverId() const { return GetId(); }
711 //------------------------------------------------------------------------------------
712 // Details: This function allows *this driver to call on another driver to
714 // should this driver not be able to handle the client data input.
715 // SetDriverToFallThruTo() specifies the fall through to driver.
716 // Check the error message if the function returns a failure.
718 // Args: vCmd - (R) Command instruction to interpret.
719 // vwErrMsg - (W) Status description on command failing.
720 // Return: MIstatus::success - Command succeeded.
721 // MIstatus::failure - Command failed.
724 bool CMIDriver::DoFallThruToAnotherDriver(const CMIUtilString &vCmd,
725 CMIUtilString &vwErrMsg) {
726 bool bOk = MIstatus::success;
728 CMIDriverBase *pOtherDriver = GetDriverToFallThruTo();
729 if (pOtherDriver == nullptr)
732 return pOtherDriver->DoFallThruToAnotherDriver(vCmd, vwErrMsg);
736 //------------------------------------------------------------------------------------
737 // Details: *this driver provides a file stream to other drivers on which *this
739 // write's out to and they read as expected input. *this driver is
741 // through commands to the (child) pass through assigned driver.
742 // Type: Overrdidden.
744 // Return: FILE * - Pointer to stream.
747 FILE *CMIDriver::GetStdin() const {
748 // Note this fn is called on CMIDriverMgr register driver so stream has to be
749 // available before *this driver has been initialized! Flaw?
751 // This very likely to change later to a stream that the pass thru driver
752 // will read and we write to give it 'input'
757 //------------------------------------------------------------------------------------
758 // Details: *this driver provides a file stream to other pass through assigned
760 // so they know what to write to.
763 // Return: FILE * - Pointer to stream.
766 FILE *CMIDriver::GetStdout() const {
767 // Note this fn is called on CMIDriverMgr register driver so stream has to be
768 // available before *this driver has been initialized! Flaw?
770 // Do not want to pass through driver to write to stdout
775 //------------------------------------------------------------------------------------
776 // Details: *this driver provides a error file stream to other pass through
778 // so they know what to write to.
781 // Return: FILE * - Pointer to stream.
784 FILE *CMIDriver::GetStderr() const {
785 // Note this fn is called on CMIDriverMgr register driver so stream has to be
786 // available before *this driver has been initialized! Flaw?
788 // This very likely to change later to a stream that the pass thru driver
789 // will write to and *this driver reads from to pass on the CMICmnLog object
794 //------------------------------------------------------------------------------------
795 // Details: Set a unique ID for *this driver. It cannot be empty.
797 // Args: vId - (R) Text description.
798 // Return: MIstatus::success - Functional succeeded.
799 // MIstatus::failure - Functional failed.
802 bool CMIDriver::SetId(const CMIUtilString &vId) {
804 SetErrorDescriptionn(MIRSRC(IDS_DRIVER_ERR_ID_INVALID), GetName().c_str(),
806 return MIstatus::failure;
810 return MIstatus::success;
814 //------------------------------------------------------------------------------------
815 // Details: Get the unique ID for *this driver.
818 // Return: CMIUtilString & - Text description.
821 const CMIUtilString &CMIDriver::GetId() const { return m_strDriverId; }
824 //------------------------------------------------------------------------------------
825 // Details: Interpret the text data and match against current commands to see if
827 // is a match. If a match then the command is issued and actioned on.
829 // text data if not understood by *this driver is past on to the Fall
832 // This function is used by the application's main thread.
834 // Args: vTextLine - (R) Text data representing a possible command.
835 // Return: MIstatus::success - Functional succeeded.
836 // MIstatus::failure - Functional failed.
839 bool CMIDriver::InterpretCommand(const CMIUtilString &vTextLine) {
840 const bool bNeedToRebroadcastStopEvent =
841 m_rLldbDebugger.CheckIfNeedToRebroadcastStopEvent();
842 bool bCmdYesValid = false;
843 bool bOk = InterpretCommandThisDriver(vTextLine, bCmdYesValid);
844 if (bOk && !bCmdYesValid)
845 bOk = InterpretCommandFallThruDriver(vTextLine, bCmdYesValid);
847 if (bNeedToRebroadcastStopEvent)
848 m_rLldbDebugger.RebroadcastStopEvent();
854 //------------------------------------------------------------------------------------
855 // Details: Helper function for CMIDriver::InterpretCommandThisDriver.
856 // Convert a CLI command to MI command (just wrap any CLI command
857 // into "<tokens>-interpreter-exec command \"<CLI command>\"").
859 // Args: vTextLine - (R) Text data representing a possible command.
860 // Return: CMIUtilString - The original MI command or converted CLI command.
861 // MIstatus::failure - Functional failed.
865 CMIDriver::WrapCLICommandIntoMICommand(const CMIUtilString &vTextLine) const {
866 // Tokens contain following digits
867 static const CMIUtilString digits("0123456789");
869 // Consider an algorithm on the following example:
870 // 001-file-exec-and-symbols "/path/to/file"
872 // 1. Skip a command token
874 // 001-file-exec-and-symbols "/path/to/file"
875 // 001target create "/path/to/file"
876 // ^ -- command starts here (in both cases)
877 // Also possible case when command not found:
879 // ^ -- i.e. only tokens are present (or empty string at all)
880 const size_t nCommandOffset = vTextLine.find_first_not_of(digits);
882 // 2. Check if command is empty
884 // 001-file-exec-and-symbols "/path/to/file"
885 // 001target create "/path/to/file"
886 // ^ -- command not empty (in both cases)
889 // ^ -- command wasn't found
890 const bool bIsEmptyCommand = (nCommandOffset == CMIUtilString::npos);
892 // 3. Check and exit if it isn't a CLI command
894 // 001-file-exec-and-symbols "/path/to/file"
896 // ^ -- it isn't CLI command (in both cases)
898 // 001target create "/path/to/file"
899 // ^ -- it's CLI command
900 const bool bIsCliCommand =
901 !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-');
905 // 4. Wrap CLI command to make it MI-compatible
907 // 001target create "/path/to/file"
909 const std::string vToken(vTextLine.begin(),
910 vTextLine.begin() + nCommandOffset);
911 // 001target create "/path/to/file"
912 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- CLI command
913 const CMIUtilString vCliCommand(std::string(vTextLine, nCommandOffset));
915 // 5. Escape special characters and embed the command in a string
916 // Result: it looks like -- target create \"/path/to/file\".
917 const std::string vShieldedCliCommand(vCliCommand.AddSlashes());
919 // 6. Turn the CLI command into an MI command, as in:
920 // 001-interpreter-exec command "target create \"/path/to/file\""
922 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ -- wrapper
923 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- shielded
925 return CMIUtilString::Format("%s-interpreter-exec command \"%s\"",
926 vToken.c_str(), vShieldedCliCommand.c_str());
930 //------------------------------------------------------------------------------------
931 // Details: Interpret the text data and match against current commands to see if
933 // is a match. If a match then the command is issued and actioned on.
935 // command cannot be found to match then vwbCmdYesValid is set to false
937 // nothing else is done here.
938 // This function is used by the application's main thread.
940 // Args: vTextLine - (R) Text data representing a possible command.
941 // vwbCmdYesValid - (W) True = Command valid, false = command not
943 // Return: MIstatus::success - Functional succeeded.
944 // MIstatus::failure - Functional failed.
947 bool CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine,
948 bool &vwbCmdYesValid) {
949 // Convert any CLI commands into MI commands
950 const CMIUtilString vMITextLine(WrapCLICommandIntoMICommand(vTextLine));
952 vwbCmdYesValid = false;
953 bool bCmdNotInCmdFactor = false;
955 CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
956 if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor,
958 return MIstatus::failure;
960 if (vwbCmdYesValid) {
961 // For debugging only
962 // m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() );
964 return ExecuteCommand(cmdData);
967 // Check for escape character, may be cursor control characters
968 // This code is not necessary for application operation, just want to keep
970 // has been given to the driver to try and interpret.
971 if (vMITextLine.at(0) == 27) {
972 CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS));
973 for (MIuint i = 0; i < vMITextLine.length(); i++) {
974 logInput += CMIUtilString::Format("%d ", vMITextLine.at(i));
976 m_pLog->WriteLog(logInput);
977 return MIstatus::success;
980 // Write to the Log that a 'command' was not valid.
981 // Report back to the MI client via MI result record.
982 CMIUtilString strNotInCmdFactory;
983 if (bCmdNotInCmdFactor)
984 strNotInCmdFactory = CMIUtilString::Format(
985 MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str());
986 const CMIUtilString strNot(
987 CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT)));
988 const CMIUtilString msg(CMIUtilString::Format(
989 MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(),
990 strNotInCmdFactory.c_str()));
991 const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg);
992 const CMICmnMIValueResult valueResult("msg", vconst);
993 const CMICmnMIResultRecord miResultRecord(
994 cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
996 const bool bOk = m_rStdOut.WriteMIResponse(miResultRecord.GetString());
998 // Proceed to wait for or execute next command
1003 //------------------------------------------------------------------------------------
1004 // Details: Having previously had the potential command validated and found
1006 // get the command executed.
1007 // This function is used by the application's main thread.
1009 // Args: vCmdData - (RW) Command meta data.
1010 // Return: MIstatus::success - Functional succeeded.
1011 // MIstatus::failure - Functional failed.
1014 bool CMIDriver::ExecuteCommand(const SMICmdData &vCmdData) {
1015 CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
1016 return rCmdMgr.CmdExecute(vCmdData);
1020 //------------------------------------------------------------------------------------
1021 // Details: Set the MI Driver's exit application flag. The application checks
1023 // after every stdin line is read so the exit may not be instantaneous.
1024 // If vbForceExit is false the MI Driver queries its state and
1026 // should exit or continue operating depending on that running state.
1027 // This is related to the running state of the MI driver.
1028 // Type: Overridden.
1033 void CMIDriver::SetExitApplicationFlag(const bool vbForceExit) {
1035 CMIUtilThreadLock lock(m_threadMutex);
1040 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1041 // Did we receive a SIGINT from the client during a running debug program, if
1042 // so then SIGINT is not to be taken as meaning kill the MI driver application
1043 // but halt the inferior program being debugged instead
1044 if (m_eCurrentDriverState == eDriverState_RunningDebugging) {
1045 InterpretCommand("-exec-interrupt");
1053 //------------------------------------------------------------------------------------
1054 // Details: Get the MI Driver's exit exit application flag.
1055 // This is related to the running state of the MI driver.
1058 // Return: bool - True = MI Driver is shutting down, false = MI driver is
1062 bool CMIDriver::GetExitApplicationFlag() const { return m_bExitApp; }
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() const {
1073 return m_eCurrentDriverState;
1077 //------------------------------------------------------------------------------------
1078 // Details: Set the current running state of the MI Driver to running and
1082 // Return: MIstatus::success - Functionality succeeded.
1083 // MIstatus::failure - Functionality failed.
1084 // Return: DriverState_e - The current running state of the application.
1087 bool CMIDriver::SetDriverStateRunningNotDebugging() {
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
1094 // eDriverState_RunningNotDebugging
1095 switch (m_eCurrentDriverState) {
1096 case eDriverState_NotRunning:
1097 case eDriverState_Initialising:
1098 case eDriverState_ShuttingDown: {
1099 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1100 return MIstatus::failure;
1102 case eDriverState_RunningDebugging:
1103 case eDriverState_RunningNotDebugging:
1105 case eDriverState_count:
1106 SetErrorDescription(
1107 CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE),
1108 "SetDriverStateRunningNotDebugging()"));
1109 return MIstatus::failure;
1112 // Driver must be in this state to set eDriverState_RunningNotDebugging
1113 if (m_eCurrentDriverState != eDriverState_RunningDebugging) {
1114 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1115 return MIstatus::failure;
1118 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
1120 return MIstatus::success;
1124 //------------------------------------------------------------------------------------
1125 // Details: Set the current running state of the MI Driver to running and
1127 // a debug session. The driver's state must in the state running and in
1129 // debug session to set this new state.
1131 // Return: MIstatus::success - Functionality succeeded.
1132 // MIstatus::failure - Functionality failed.
1133 // Return: DriverState_e - The current running state of the application.
1136 bool CMIDriver::SetDriverStateRunningDebugging() {
1137 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1139 if (m_eCurrentDriverState == eDriverState_RunningDebugging)
1140 return MIstatus::success;
1142 // Driver cannot be in the following states to set
1143 // eDriverState_RunningDebugging
1144 switch (m_eCurrentDriverState) {
1145 case eDriverState_NotRunning:
1146 case eDriverState_Initialising:
1147 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:
1155 SetErrorDescription(
1156 CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE),
1157 "SetDriverStateRunningDebugging()"));
1158 return MIstatus::failure;
1161 // Driver must be in this state to set eDriverState_RunningDebugging
1162 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;
1173 //------------------------------------------------------------------------------------
1174 // Details: Prepare the client IDE so it will start working/communicating with
1179 // Return: MIstatus::success - Functionality succeeded.
1180 // MIstatus::failure - Functionality failed.
1183 bool CMIDriver::InitClientIDEToMIDriver() const {
1184 // Put other IDE init functions here
1185 return InitClientIDEEclipse();
1189 //------------------------------------------------------------------------------------
1190 // Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character
1191 // sequence otherwise it refuses to communicate and times out. This
1193 // sent to Eclipse before anything else.
1196 // Return: MIstatus::success - Functionality succeeded.
1197 // MIstatus::failure - Functionality failed.
1200 bool CMIDriver::InitClientIDEEclipse() const {
1201 return CMICmnStreamStdout::WritePrompt();
1205 //------------------------------------------------------------------------------------
1206 // Details: Ask *this driver whether it found an executable in the MI Driver's
1208 // arguments which to open and debug. If so instigate commands to set
1210 // session for that executable.
1213 // Return: bool - True = True = Yes executable given as one of the parameters
1216 // False = not found.
1219 bool CMIDriver::HaveExecutableFileNamePathOnCmdLine() const {
1220 return m_bHaveExecutableFileNamePathOnCmdLine;
1224 //------------------------------------------------------------------------------------
1225 // Details: Retrieve from *this driver executable file name path to start a
1227 // with (if present see HaveExecutableFileNamePathOnCmdLine()).
1230 // Return: CMIUtilString & - Executeable file name path or empty string.
1233 const CMIUtilString &CMIDriver::GetExecutableFileNamePathOnCmdLine() const {
1234 return m_strCmdLineArgExecuteableFileNamePath;
1238 //------------------------------------------------------------------------------------
1239 // Details: Execute commands (by injecting them into the stdin line queue
1241 // other code to set up the MI Driver such that is can take the
1243 // argument passed on the command and create a debug session for it.
1246 // Return: MIstatus::success - Functionality succeeded.
1247 // MIstatus::failure - Functionality failed.
1250 bool CMIDriver::LocalDebugSessionStartupExecuteCommands() {
1251 const CMIUtilString strCmd(CMIUtilString::Format(
1252 "-file-exec-and-symbols \"%s\"",
1253 m_strCmdLineArgExecuteableFileNamePath.AddSlashes().c_str()));
1254 bool bOk = CMICmnStreamStdout::TextToStdout(strCmd);
1255 bOk = bOk && InterpretCommand(strCmd);
1256 bOk = bOk && CMICmnStreamStdout::WritePrompt();
1261 //------------------------------------------------------------------------------------
1262 // Details: Set the MI Driver into "its debugging an executable passed as an
1264 // mode as against running via a client like Eclipse.
1270 void CMIDriver::SetDriverDebuggingArgExecutable() {
1271 m_bDriverDebuggingArgExecutable = true;
1275 //------------------------------------------------------------------------------------
1276 // Details: Retrieve the MI Driver state indicating if it is operating in "its
1278 // an executable passed as an argument" mode as against running via a
1286 bool CMIDriver::IsDriverDebuggingArgExecutable() const {
1287 return m_bDriverDebuggingArgExecutable;
1291 //------------------------------------------------------------------------------------
1292 // Details: Execute commands from command source file in specified mode, and
1293 // set exit-flag if needed.
1295 // Args: vbAsyncMode - (R) True = execute commands in asynchronous
1296 // mode, false = otherwise.
1297 // Return: MIstatus::success - Function succeeded.
1298 // MIstatus::failure - Function failed.
1301 bool CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) {
1302 std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str());
1303 if (!ifsStartScript.is_open()) {
1304 const CMIUtilString errMsg(
1305 CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN),
1306 m_strCmdLineArgCommandFileNamePath.c_str()));
1307 SetErrorDescription(errMsg.c_str());
1308 const bool bForceExit = true;
1309 SetExitApplicationFlag(bForceExit);
1310 return MIstatus::failure;
1313 // Switch lldb to synchronous mode
1314 CMICmnLLDBDebugSessionInfo &rSessionInfo(
1315 CMICmnLLDBDebugSessionInfo::Instance());
1316 const bool bAsyncSetting = rSessionInfo.GetDebugger().GetAsync();
1317 rSessionInfo.GetDebugger().SetAsync(vbAsyncMode);
1319 // Execute commands from file
1320 bool bOk = MIstatus::success;
1321 CMIUtilString strCommand;
1322 while (!m_bExitApp && std::getline(ifsStartScript, strCommand)) {
1324 bOk = CMICmnStreamStdout::TextToStdout(strCommand);
1326 // Skip if it's a comment or empty line
1327 if (strCommand.empty() || strCommand[0] == '#')
1330 // Execute if no error
1332 CMIUtilThreadLock lock(rSessionInfo.GetSessionMutex());
1333 bOk = InterpretCommand(strCommand);
1336 // Draw the prompt after command will be executed (if enabled)
1337 bOk = bOk && CMICmnStreamStdout::WritePrompt();
1339 // Exit if there is an error
1341 const bool bForceExit = true;
1342 SetExitApplicationFlag(bForceExit);
1346 // Wait while the handler thread handles incoming events
1347 CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
1350 // Switch lldb back to initial mode
1351 rSessionInfo.GetDebugger().SetAsync(bAsyncSetting);
1357 //------------------------------------------------------------------------------------
1358 // Details: Gets called when lldb-mi gets a signal. Stops the process if it was
1362 // Args: signal that was delivered
1366 void CMIDriver::DeliverSignal(int signal) {
1367 if (signal == SIGINT &&
1368 (m_eCurrentDriverState == eDriverState_RunningDebugging))
1369 InterpretCommand("-exec-interrupt");