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"
15 #include "MICmdArgValFile.h"
16 #include "MICmdArgValString.h"
18 #include "MICmnConfig.h"
19 #include "MICmnLLDBDebugSessionInfo.h"
20 #include "MICmnLLDBDebugger.h"
22 #include "MICmnMIResultRecord.h"
23 #include "MICmnMIValueConst.h"
24 #include "MICmnResources.h"
25 #include "MICmnStreamStderr.h"
26 #include "MICmnStreamStdout.h"
27 #include "MICmnThreadMgrStd.h"
29 #include "MIUtilDebug.h"
30 #include "MIUtilSingletonHelper.h"
34 const CMIUtilString CMIDriver::ms_constMIVersion =
35 MIRSRC(IDS_MI_VERSION_DESCRIPTION_DEBUG);
37 const CMIUtilString CMIDriver::ms_constMIVersion =
38 MIRSRC(IDS_MI_VERSION_DESCRIPTION); // Matches version in resources file
41 CMIDriver::ms_constAppNameShort(MIRSRC(IDS_MI_APPNAME_SHORT));
42 const CMIUtilString CMIDriver::ms_constAppNameLong(MIRSRC(IDS_MI_APPNAME_LONG));
45 //------------------------------------------------------------------------------------
46 // Details: CMIDriver constructor.
52 CMIDriver::CMIDriver()
53 : m_bFallThruToOtherDriverEnabled(false), m_bDriverIsExiting(false),
54 m_handleMainThread(0), m_rStdin(CMICmnStreamStdin::Instance()),
55 m_rLldbDebugger(CMICmnLLDBDebugger::Instance()),
56 m_rStdOut(CMICmnStreamStdout::Instance()),
57 m_eCurrentDriverState(eDriverState_NotRunning),
58 m_bHaveExecutableFileNamePathOnCmdLine(false),
59 m_bDriverDebuggingArgExecutable(false),
60 m_bHaveCommandFileNamePathOnCmdLine(false) {}
63 //------------------------------------------------------------------------------------
64 // Details: CMIDriver destructor.
70 CMIDriver::~CMIDriver() {}
73 //------------------------------------------------------------------------------------
74 // Details: Set whether *this driver (the parent) is enabled to pass a command
76 // fall through (child) driver to interpret the command and do work
78 // (if *this driver decides it can't handle the command).
80 // Args: vbYes - (R) True = yes fall through, false = do not pass on
82 // Return: MIstatus::success - Functional succeeded.
83 // MIstatus::failure - Functional failed.
86 bool CMIDriver::SetEnableFallThru(const bool vbYes) {
87 m_bFallThruToOtherDriverEnabled = vbYes;
88 return MIstatus::success;
92 //------------------------------------------------------------------------------------
93 // Details: Get whether *this driver (the parent) is enabled to pass a command
95 // fall through (child) driver to interpret the command and do work
97 // (if *this driver decides it can't handle the command).
100 // Return: bool - True = yes fall through, false = do not pass on command.
103 bool CMIDriver::GetEnableFallThru() const {
104 return m_bFallThruToOtherDriverEnabled;
108 //------------------------------------------------------------------------------------
109 // Details: Retrieve MI's application name of itself.
112 // Return: CMIUtilString & - Text description.
115 const CMIUtilString &CMIDriver::GetAppNameShort() const {
116 return ms_constAppNameShort;
120 //------------------------------------------------------------------------------------
121 // Details: Retrieve MI's application name of itself.
124 // Return: CMIUtilString & - Text description.
127 const CMIUtilString &CMIDriver::GetAppNameLong() const {
128 return ms_constAppNameLong;
132 //------------------------------------------------------------------------------------
133 // Details: Retrieve MI's version description of itself.
136 // Return: CMIUtilString & - Text description.
139 const CMIUtilString &CMIDriver::GetVersionDescription() const {
140 return ms_constMIVersion;
144 //------------------------------------------------------------------------------------
145 // Details: Initialize setup *this driver ready for use.
148 // Return: MIstatus::success - Functional succeeded.
149 // MIstatus::failure - Functional failed.
152 bool CMIDriver::Initialize() {
153 m_eCurrentDriverState = eDriverState_Initialising;
154 m_clientUsageRefCnt++;
156 ClrErrorDescription();
159 return MIstatus::success;
161 bool bOk = MIstatus::success;
162 CMIUtilString errMsg;
164 // Initialize all of the modules we depend on
165 MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
166 MI::ModuleInit<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, errMsg);
167 MI::ModuleInit<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, errMsg);
168 MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
169 MI::ModuleInit<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk,
171 MI::ModuleInit<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, errMsg);
172 MI::ModuleInit<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
173 bOk &= m_rLldbDebugger.SetDriver(*this);
174 MI::ModuleInit<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, errMsg);
178 m_bInitialized = bOk;
181 const CMIUtilString msg =
182 CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_DRIVER), errMsg.c_str());
183 SetErrorDescription(msg);
184 return MIstatus::failure;
187 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
193 //------------------------------------------------------------------------------------
194 // Details: Unbind detach or release resources used by *this driver.
197 // Return: MIstatus::success - Functional succeeded.
198 // MIstatus::failure - Functional failed.
201 bool CMIDriver::Shutdown() {
202 if (--m_clientUsageRefCnt > 0)
203 return MIstatus::success;
206 return MIstatus::success;
208 m_eCurrentDriverState = eDriverState_ShuttingDown;
210 ClrErrorDescription();
212 bool bOk = MIstatus::success;
213 CMIUtilString errMsg;
215 // Shutdown all of the modules we depend on
216 MI::ModuleShutdown<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk,
218 MI::ModuleShutdown<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
219 MI::ModuleShutdown<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk,
221 MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk,
223 MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
224 MI::ModuleShutdown<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk,
226 MI::ModuleShutdown<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk,
228 MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
231 SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str());
234 m_eCurrentDriverState = eDriverState_NotRunning;
240 //------------------------------------------------------------------------------------
241 // Details: Work function. Client (the driver's user) is able to append their
243 // in to the MI's Log trace file.
245 // Args: vMessage - (R) Client's text message.
246 // Return: MIstatus::success - Functional succeeded.
247 // MIstatus::failure - Functional failed.
250 bool CMIDriver::WriteMessageToLog(const CMIUtilString &vMessage) {
252 msg = CMIUtilString::Format(MIRSRC(IDS_MI_CLIENT_MSG), vMessage.c_str());
253 return m_pLog->Write(msg, CMICmnLog::eLogVerbosity_ClientMsg);
257 //------------------------------------------------------------------------------------
258 // Details: CDriverMgr calls *this driver initialize setup ready for use.
261 // Return: MIstatus::success - Functional succeeded.
262 // MIstatus::failure - Functional failed.
265 bool CMIDriver::DoInitialize() { return CMIDriver::Instance().Initialize(); }
268 //------------------------------------------------------------------------------------
269 // Details: CDriverMgr calls *this driver to unbind detach or release resources
274 // Return: MIstatus::success - Functional succeeded.
275 // MIstatus::failure - Functional failed.
278 bool CMIDriver::DoShutdown() { return CMIDriver::Instance().Shutdown(); }
281 //------------------------------------------------------------------------------------
282 // Details: Retrieve the name for *this driver.
285 // Return: CMIUtilString & - Driver name.
288 const CMIUtilString &CMIDriver::GetName() const {
289 const CMIUtilString &rName = GetAppNameLong();
290 const CMIUtilString &rVsn = GetVersionDescription();
291 static CMIUtilString strName =
292 CMIUtilString::Format("%s %s", rName.c_str(), rVsn.c_str());
298 //------------------------------------------------------------------------------------
299 // Details: Retrieve *this driver's last error condition.
302 // Return: CMIUtilString - Text description.
305 CMIUtilString CMIDriver::GetError() const { return GetErrorDescription(); }
308 //------------------------------------------------------------------------------------
309 // Details: Call *this driver to return it's debugger.
312 // Return: lldb::SBDebugger & - LLDB debugger object reference.
315 lldb::SBDebugger &CMIDriver::GetTheDebugger() {
316 return m_rLldbDebugger.GetTheDebugger();
320 //------------------------------------------------------------------------------------
321 // Details: Specify another driver *this driver can call should this driver not
323 // to handle the client data input. DoFallThruToAnotherDriver() makes
326 // Args: vrOtherDriver - (R) Reference to another driver object.
327 // Return: MIstatus::success - Functional succeeded.
328 // MIstatus::failure - Functional failed.
331 bool CMIDriver::SetDriverToFallThruTo(const CMIDriverBase &vrOtherDriver) {
332 m_pDriverFallThru = const_cast<CMIDriverBase *>(&vrOtherDriver);
334 return m_pDriverFallThru->SetDriverParent(*this);
338 //------------------------------------------------------------------------------------
339 // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this
341 // implementation called from here to match the existing function name
343 // original LLDB driver class (the extra indirection is not necessarily
345 // Check the arguments that were passed to this program to make sure
347 // valid and to get their argument values (if any).
349 // Args: argc - (R) An integer that contains the count of arguments
351 // argv. The argc parameter is always greater than
353 // argv - (R) An array of null-terminated strings representing
355 // arguments entered by the user of the program. By
357 // argv[0] is the command with which the program is
359 // vpStdOut - (R) Pointer to a standard output stream.
360 // vwbExiting - (W) True = *this want to exit, Reasons: help,
362 // version information only.
363 // False = Continue to work, start debugger i.e.
366 // Return: lldb::SBError - LLDB current error status.
369 lldb::SBError CMIDriver::DoParseArgs(const int argc, const char *argv[],
370 FILE *vpStdOut, bool &vwbExiting) {
371 return ParseArgs(argc, argv, vpStdOut, vwbExiting);
375 //------------------------------------------------------------------------------------
376 // Details: Check the arguments that were passed to this program to make sure
378 // valid and to get their argument values (if any). The following are
380 // that are only handled by *this driver:
381 // --executable <file>
382 // --source <file> or -s <file>
383 // The application's options --interpreter and --executable in code act
385 // The --executable is necessary to differentiate whether the MI Driver
387 // used by a client (e.g. Eclipse) or from the command line. Eclipse
389 // --interpreter and also passes additional arguments which can be
391 // executable if called from the command line. Using --executable tells
393 // it is being called from the command line and to prepare to launch
395 // argument for a debug session. Using --interpreter on the command
397 // issue additional commands to initialise a debug session.
399 // Args: argc - (R) An integer that contains the count of arguments
401 // argv. The argc parameter is always greater than
403 // argv - (R) An array of null-terminated strings representing
405 // arguments entered by the user of the program. By
407 // argv[0] is the command with which the program is
409 // vpStdOut - (R) Pointer to a standard output stream.
410 // vwbExiting - (W) True = *this want to exit, Reasons: help,
412 // version information only.
413 // False = Continue to work, start debugger i.e.
416 // Return: lldb::SBError - LLDB current error status.
419 lldb::SBError CMIDriver::ParseArgs(const int argc, const char *argv[],
420 FILE *vpStdOut, bool &vwbExiting) {
421 lldb::SBError errStatus;
422 const bool bHaveArgs(argc >= 2);
424 // *** Add any args handled here to GetHelpOnCmdLineArgOptions() ***
426 // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
427 // Look for the command line options
428 bool bHaveExecutableFileNamePath = false;
429 bool bHaveExecutableLongOption = false;
432 // Search right to left to look for filenames
433 for (MIint i = argc - 1; i > 0; i--) {
434 const CMIUtilString strArg(argv[i]);
435 const CMICmdArgValFile argFile;
437 // Check for a filename
438 if (argFile.IsFilePath(strArg) ||
439 CMICmdArgValString(true, false, true).IsStringArg(strArg)) {
440 // Is this the command file for the '-s' or '--source' options?
441 const CMIUtilString strPrevArg(argv[i - 1]);
442 if (strPrevArg.compare("-s") == 0 ||
443 strPrevArg.compare("--source") == 0) {
444 m_strCmdLineArgCommandFileNamePath = strArg;
445 m_bHaveCommandFileNamePathOnCmdLine = true;
446 i--; // skip '-s' on the next loop
449 // Else, must be the executable
450 bHaveExecutableFileNamePath = true;
451 m_strCmdLineArgExecuteableFileNamePath = strArg;
452 m_bHaveExecutableFileNamePathOnCmdLine = true;
454 // Report error if no command file was specified for the '-s' or
455 // '--source' options
456 else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) {
458 const CMIUtilString errMsg = CMIUtilString::Format(
459 MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str());
460 errStatus.SetErrorString(errMsg.c_str());
463 // This argument is also checked for in CMIDriverMgr::ParseArgs()
464 else if (strArg.compare("--executable") == 0) // Used to specify that
465 // there is executable
466 // argument also on the
468 { // See fn description.
469 bHaveExecutableLongOption = true;
474 if (bHaveExecutableFileNamePath && bHaveExecutableLongOption) {
475 SetDriverDebuggingArgExecutable();
482 //------------------------------------------------------------------------------------
483 // Details: A client can ask if *this driver is GDB/MI compatible.
486 // Return: True - GBD/MI compatible LLDB front end.
487 // False - Not GBD/MI compatible LLDB front end.
490 bool CMIDriver::GetDriverIsGDBMICompatibleDriver() const { return true; }
493 //------------------------------------------------------------------------------------
494 // Details: Start worker threads for the driver.
497 // Return: MIstatus::success - Functional succeeded.
498 // MIstatus::failure - Functional failed.
501 bool CMIDriver::StartWorkerThreads() {
502 bool bOk = MIstatus::success;
504 // Grab the thread manager
505 CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
507 // Start the event polling thread
508 if (bOk && !rThreadMgr.ThreadStart<CMICmnLLDBDebugger>(m_rLldbDebugger)) {
509 const CMIUtilString errMsg = CMIUtilString::Format(
510 MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE),
511 CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str());
512 SetErrorDescriptionn(errMsg);
513 return MIstatus::failure;
520 //------------------------------------------------------------------------------------
521 // Details: Stop worker threads for the driver.
524 // Return: MIstatus::success - Functional succeeded.
525 // MIstatus::failure - Functional failed.
528 bool CMIDriver::StopWorkerThreads() {
529 CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
530 return rThreadMgr.ThreadAllTerminate();
534 //------------------------------------------------------------------------------------
535 // Details: Call this function puts *this driver to work.
536 // This function is used by the application's main thread.
539 // Return: MIstatus::success - Functional succeeded.
540 // MIstatus::failure - Functional failed.
543 bool CMIDriver::DoMainLoop() {
544 if (!InitClientIDEToMIDriver()) // Init Eclipse IDE
546 SetErrorDescriptionn(MIRSRC(IDS_MI_INIT_ERR_CLIENT_USING_DRIVER));
547 return MIstatus::failure;
550 if (!StartWorkerThreads())
551 return MIstatus::failure;
553 bool bOk = MIstatus::success;
555 if (HaveExecutableFileNamePathOnCmdLine()) {
556 if (!LocalDebugSessionStartupExecuteCommands()) {
557 SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION));
558 bOk = MIstatus::failure;
562 // App is not quitting currently
565 // Handle source file
566 if (m_bHaveCommandFileNamePathOnCmdLine) {
567 const bool bAsyncMode = false;
568 ExecuteCommandFile(bAsyncMode);
571 // While the app is active
572 while (bOk && !m_bExitApp) {
573 CMIUtilString errorText;
574 const char *pCmd = m_rStdin.ReadLine(errorText);
575 if (pCmd != nullptr) {
576 CMIUtilString lineText(pCmd);
577 if (!lineText.empty()) {
578 // Check that the handler thread is alive (otherwise we stuck here)
579 assert(CMICmnLLDBDebugger::Instance().ThreadIsActive());
582 // Lock Mutex before processing commands so that we don't disturb an
585 CMIUtilThreadLock lock(
586 CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
587 bOk = InterpretCommand(lineText);
590 // Draw prompt if desired
591 bOk = bOk && CMICmnStreamStdout::WritePrompt();
593 // Wait while the handler thread handles incoming events
594 CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
599 // Signal that the application is shutting down
602 // Close and wait for the workers to stop
605 return MIstatus::success;
609 //------------------------------------------------------------------------------------
610 // Details: Set things in motion, set state etc that brings *this driver (and
612 // application) to a tidy shutdown.
613 // This function is used by the application's main thread.
616 // Return: MIstatus::success - Functional succeeded.
617 // MIstatus::failure - Functional failed.
620 bool CMIDriver::DoAppQuit() {
621 bool bYesQuit = true;
623 // Shutdown stuff, ready app for exit
625 CMIUtilThreadLock lock(m_threadMutex);
626 m_bDriverIsExiting = true;
633 //------------------------------------------------------------------------------------
634 // Details: *this driver passes text commands to a fall through driver is it
636 // understand them (the LLDB driver).
637 // This function is used by the application's main thread.
639 // Args: vTextLine - (R) Text data representing a possible command.
640 // vwbCmdYesValid - (W) True = Command valid, false = command not
642 // Return: MIstatus::success - Functional succeeded.
643 // MIstatus::failure - Functional failed.
646 bool CMIDriver::InterpretCommandFallThruDriver(const CMIUtilString &vTextLine,
647 bool &vwbCmdYesValid) {
649 MIunused(vwbCmdYesValid);
651 // ToDo: Implement when less urgent work to be done or decide remove as not
653 // bool bOk = MIstatus::success;
654 // bool bCmdNotUnderstood = true;
655 // if( bCmdNotUnderstood && GetEnableFallThru() )
657 // CMIUtilString errMsg;
658 // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg );
661 // errMsg = errMsg.StripCREndOfLine();
662 // errMsg = errMsg.StripCRAll();
663 // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
664 // const char * pName = pOtherDriver->GetDriverName().c_str();
665 // const char * pId = pOtherDriver->GetDriverId().c_str();
666 // const CMIUtilString msg( CMIUtilString::Format( MIRSRC(
667 // IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() )
669 // m_pLog->WriteMsg( msg );
673 // vwbCmdYesValid = bOk;
674 // CMIUtilString strNot;
675 // if( vwbCmdYesValid)
676 // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) );
677 // const CMIUtilString msg( CMIUtilString::Format( MIRSRC(
678 // IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) );
679 // m_pLog->WriteLog( msg );
681 return MIstatus::success;
685 //------------------------------------------------------------------------------------
686 // Details: Retrieve the name for *this driver.
689 // Return: CMIUtilString & - Driver name.
692 const CMIUtilString &CMIDriver::GetDriverName() const { return GetName(); }
695 //------------------------------------------------------------------------------------
696 // Details: Get the unique ID for *this driver.
699 // Return: CMIUtilString & - Text description.
702 const CMIUtilString &CMIDriver::GetDriverId() const { return GetId(); }
705 //------------------------------------------------------------------------------------
706 // Details: This function allows *this driver to call on another driver to
708 // should this driver not be able to handle the client data input.
709 // SetDriverToFallThruTo() specifies the fall through to driver.
710 // Check the error message if the function returns a failure.
712 // Args: vCmd - (R) Command instruction to interpret.
713 // vwErrMsg - (W) Error description on command failing.
714 // Return: MIstatus::success - Command succeeded.
715 // MIstatus::failure - Command failed.
718 bool CMIDriver::DoFallThruToAnotherDriver(const CMIUtilString &vCmd,
719 CMIUtilString &vwErrMsg) {
720 bool bOk = MIstatus::success;
722 CMIDriverBase *pOtherDriver = GetDriverToFallThruTo();
723 if (pOtherDriver == nullptr)
726 return pOtherDriver->DoFallThruToAnotherDriver(vCmd, vwErrMsg);
730 //------------------------------------------------------------------------------------
731 // Details: *this driver provides a file stream to other drivers on which *this
733 // write's out to and they read as expected input. *this driver is
735 // through commands to the (child) pass through assigned driver.
736 // Type: Overrdidden.
738 // Return: FILE * - Pointer to stream.
741 FILE *CMIDriver::GetStdin() const {
742 // Note this fn is called on CMIDriverMgr register driver so stream has to be
743 // available before *this driver has been initialized! Flaw?
745 // This very likely to change later to a stream that the pass thru driver
746 // will read and we write to give it 'input'
751 //------------------------------------------------------------------------------------
752 // Details: *this driver provides a file stream to other pass through assigned
754 // so they know what to write to.
757 // Return: FILE * - Pointer to stream.
760 FILE *CMIDriver::GetStdout() const {
761 // Note this fn is called on CMIDriverMgr register driver so stream has to be
762 // available before *this driver has been initialized! Flaw?
764 // Do not want to pass through driver to write to stdout
769 //------------------------------------------------------------------------------------
770 // Details: *this driver provides a error file stream to other pass through
772 // so they know what to write to.
775 // Return: FILE * - Pointer to stream.
778 FILE *CMIDriver::GetStderr() const {
779 // Note this fn is called on CMIDriverMgr register driver so stream has to be
780 // available before *this driver has been initialized! Flaw?
782 // This very likely to change later to a stream that the pass thru driver
783 // will write to and *this driver reads from to pass on the CMICmnLog object
788 //------------------------------------------------------------------------------------
789 // Details: Set a unique ID for *this driver. It cannot be empty.
791 // Args: vId - (R) Text description.
792 // Return: MIstatus::success - Functional succeeded.
793 // MIstatus::failure - Functional failed.
796 bool CMIDriver::SetId(const CMIUtilString &vId) {
798 SetErrorDescriptionn(MIRSRC(IDS_DRIVER_ERR_ID_INVALID), GetName().c_str(),
800 return MIstatus::failure;
804 return MIstatus::success;
808 //------------------------------------------------------------------------------------
809 // Details: Get the unique ID for *this driver.
812 // Return: CMIUtilString & - Text description.
815 const CMIUtilString &CMIDriver::GetId() const { return m_strDriverId; }
818 //------------------------------------------------------------------------------------
819 // Details: Interpret the text data and match against current commands to see if
821 // is a match. If a match then the command is issued and actioned on.
823 // text data if not understood by *this driver is past on to the Fall
826 // This function is used by the application's main thread.
828 // Args: vTextLine - (R) Text data representing a possible command.
829 // Return: MIstatus::success - Functional succeeded.
830 // MIstatus::failure - Functional failed.
833 bool CMIDriver::InterpretCommand(const CMIUtilString &vTextLine) {
834 const bool bNeedToRebroadcastStopEvent =
835 m_rLldbDebugger.CheckIfNeedToRebroadcastStopEvent();
836 bool bCmdYesValid = false;
837 bool bOk = InterpretCommandThisDriver(vTextLine, bCmdYesValid);
838 if (bOk && !bCmdYesValid)
839 bOk = InterpretCommandFallThruDriver(vTextLine, bCmdYesValid);
841 if (bNeedToRebroadcastStopEvent)
842 m_rLldbDebugger.RebroadcastStopEvent();
848 //------------------------------------------------------------------------------------
849 // Details: Helper function for CMIDriver::InterpretCommandThisDriver.
850 // Convert a CLI command to MI command (just wrap any CLI command
851 // into "<tokens>-interpreter-exec command \"<CLI command>\"").
853 // Args: vTextLine - (R) Text data representing a possible command.
854 // Return: CMIUtilString - The original MI command or converted CLI command.
855 // MIstatus::failure - Functional failed.
859 CMIDriver::WrapCLICommandIntoMICommand(const CMIUtilString &vTextLine) const {
860 // Tokens contain following digits
861 static const CMIUtilString digits("0123456789");
863 // Consider an algorithm on the following example:
864 // 001-file-exec-and-symbols "/path/to/file"
866 // 1. Skip a command token
868 // 001-file-exec-and-symbols "/path/to/file"
869 // 001target create "/path/to/file"
870 // ^ -- command starts here (in both cases)
871 // Also possible case when command not found:
873 // ^ -- i.e. only tokens are present (or empty string at all)
874 const size_t nCommandOffset = vTextLine.find_first_not_of(digits);
876 // 2. Check if command is empty
878 // 001-file-exec-and-symbols "/path/to/file"
879 // 001target create "/path/to/file"
880 // ^ -- command not empty (in both cases)
883 // ^ -- command wasn't found
884 const bool bIsEmptyCommand = (nCommandOffset == CMIUtilString::npos);
886 // 3. Check and exit if it isn't a CLI command
888 // 001-file-exec-and-symbols "/path/to/file"
890 // ^ -- it isn't CLI command (in both cases)
892 // 001target create "/path/to/file"
893 // ^ -- it's CLI command
894 const bool bIsCliCommand =
895 !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-');
899 // 4. Wrap CLI command to make it MI-compatible
901 // 001target create "/path/to/file"
903 const std::string vToken(vTextLine.begin(),
904 vTextLine.begin() + nCommandOffset);
905 // 001target create "/path/to/file"
906 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- CLI command
907 const CMIUtilString vCliCommand(std::string(vTextLine, nCommandOffset));
909 // 5. Escape special characters and embed the command in a string
910 // Result: it looks like -- target create \"/path/to/file\".
911 const std::string vShieldedCliCommand(vCliCommand.AddSlashes());
913 // 6. Turn the CLI command into an MI command, as in:
914 // 001-interpreter-exec command "target create \"/path/to/file\""
916 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ -- wrapper
917 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- shielded
919 return CMIUtilString::Format("%s-interpreter-exec command \"%s\"",
920 vToken.c_str(), vShieldedCliCommand.c_str());
924 //------------------------------------------------------------------------------------
925 // Details: Interpret the text data and match against current commands to see if
927 // is a match. If a match then the command is issued and actioned on.
929 // command cannot be found to match then vwbCmdYesValid is set to false
931 // nothing else is done here.
932 // This function is used by the application's main thread.
934 // Args: vTextLine - (R) Text data representing a possible command.
935 // vwbCmdYesValid - (W) True = Command valid, false = command not
937 // Return: MIstatus::success - Functional succeeded.
938 // MIstatus::failure - Functional failed.
941 bool CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine,
942 bool &vwbCmdYesValid) {
943 // Convert any CLI commands into MI commands
944 const CMIUtilString vMITextLine(WrapCLICommandIntoMICommand(vTextLine));
946 vwbCmdYesValid = false;
947 bool bCmdNotInCmdFactor = false;
949 CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
950 if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor,
952 return MIstatus::failure;
954 if (vwbCmdYesValid) {
955 // For debugging only
956 // m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() );
958 return ExecuteCommand(cmdData);
961 // Check for escape character, may be cursor control characters
962 // This code is not necessary for application operation, just want to keep
964 // has been given to the driver to try and interpret.
965 if (vMITextLine.at(0) == 27) {
966 CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS));
967 for (MIuint i = 0; i < vMITextLine.length(); i++) {
968 logInput += CMIUtilString::Format("%d ", vMITextLine.at(i));
970 m_pLog->WriteLog(logInput);
971 return MIstatus::success;
974 // Write to the Log that a 'command' was not valid.
975 // Report back to the MI client via MI result record.
976 CMIUtilString strNotInCmdFactory;
977 if (bCmdNotInCmdFactor)
978 strNotInCmdFactory = CMIUtilString::Format(
979 MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str());
980 const CMIUtilString strNot(
981 CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT)));
982 const CMIUtilString msg(CMIUtilString::Format(
983 MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(),
984 strNotInCmdFactory.c_str()));
985 const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg);
986 const CMICmnMIValueResult valueResult("msg", vconst);
987 const CMICmnMIResultRecord miResultRecord(
988 cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
990 const bool bOk = m_rStdOut.WriteMIResponse(miResultRecord.GetString());
992 // Proceed to wait for or execute next command
997 //------------------------------------------------------------------------------------
998 // Details: Having previously had the potential command validated and found
1000 // get the command executed.
1001 // This function is used by the application's main thread.
1003 // Args: vCmdData - (RW) Command meta data.
1004 // Return: MIstatus::success - Functional succeeded.
1005 // MIstatus::failure - Functional failed.
1008 bool CMIDriver::ExecuteCommand(const SMICmdData &vCmdData) {
1009 CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
1010 return rCmdMgr.CmdExecute(vCmdData);
1014 //------------------------------------------------------------------------------------
1015 // Details: Set the MI Driver's exit application flag. The application checks
1017 // after every stdin line is read so the exit may not be instantaneous.
1018 // If vbForceExit is false the MI Driver queries its state and
1020 // should exit or continue operating depending on that running state.
1021 // This is related to the running state of the MI driver.
1022 // Type: Overridden.
1027 void CMIDriver::SetExitApplicationFlag(const bool vbForceExit) {
1029 CMIUtilThreadLock lock(m_threadMutex);
1034 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1035 // Did we receive a SIGINT from the client during a running debug program, if
1036 // so then SIGINT is not to be taken as meaning kill the MI driver application
1037 // but halt the inferior program being debugged instead
1038 if (m_eCurrentDriverState == eDriverState_RunningDebugging) {
1039 InterpretCommand("-exec-interrupt");
1047 //------------------------------------------------------------------------------------
1048 // Details: Get the MI Driver's exit exit application flag.
1049 // This is related to the running state of the MI driver.
1052 // Return: bool - True = MI Driver is shutting down, false = MI driver is
1056 bool CMIDriver::GetExitApplicationFlag() const { return m_bExitApp; }
1059 //------------------------------------------------------------------------------------
1060 // Details: Get the current running state of the MI Driver.
1063 // Return: DriverState_e - The current running state of the application.
1066 CMIDriver::DriverState_e CMIDriver::GetCurrentDriverState() const {
1067 return m_eCurrentDriverState;
1071 //------------------------------------------------------------------------------------
1072 // Details: Set the current running state of the MI Driver to running and
1076 // Return: MIstatus::success - Functionality succeeded.
1077 // MIstatus::failure - Functionality failed.
1078 // Return: DriverState_e - The current running state of the application.
1081 bool CMIDriver::SetDriverStateRunningNotDebugging() {
1082 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1084 if (m_eCurrentDriverState == eDriverState_RunningNotDebugging)
1085 return MIstatus::success;
1087 // Driver cannot be in the following states to set
1088 // eDriverState_RunningNotDebugging
1089 switch (m_eCurrentDriverState) {
1090 case eDriverState_NotRunning:
1091 case eDriverState_Initialising:
1092 case eDriverState_ShuttingDown: {
1093 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1094 return MIstatus::failure;
1096 case eDriverState_RunningDebugging:
1097 case eDriverState_RunningNotDebugging:
1099 case eDriverState_count:
1100 SetErrorDescription(
1101 CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE),
1102 "SetDriverStateRunningNotDebugging()"));
1103 return MIstatus::failure;
1106 // Driver must be in this state to set eDriverState_RunningNotDebugging
1107 if (m_eCurrentDriverState != eDriverState_RunningDebugging) {
1108 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1109 return MIstatus::failure;
1112 m_eCurrentDriverState = eDriverState_RunningNotDebugging;
1114 return MIstatus::success;
1118 //------------------------------------------------------------------------------------
1119 // Details: Set the current running state of the MI Driver to running and
1121 // a debug session. The driver's state must in the state running and in
1123 // debug session to set this new state.
1125 // Return: MIstatus::success - Functionality succeeded.
1126 // MIstatus::failure - Functionality failed.
1127 // Return: DriverState_e - The current running state of the application.
1130 bool CMIDriver::SetDriverStateRunningDebugging() {
1131 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1133 if (m_eCurrentDriverState == eDriverState_RunningDebugging)
1134 return MIstatus::success;
1136 // Driver cannot be in the following states to set
1137 // eDriverState_RunningDebugging
1138 switch (m_eCurrentDriverState) {
1139 case eDriverState_NotRunning:
1140 case eDriverState_Initialising:
1141 case eDriverState_ShuttingDown: {
1142 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1143 return MIstatus::failure;
1145 case eDriverState_RunningDebugging:
1146 case eDriverState_RunningNotDebugging:
1148 case eDriverState_count:
1149 SetErrorDescription(
1150 CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE),
1151 "SetDriverStateRunningDebugging()"));
1152 return MIstatus::failure;
1155 // Driver must be in this state to set eDriverState_RunningDebugging
1156 if (m_eCurrentDriverState != eDriverState_RunningNotDebugging) {
1157 SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1158 return MIstatus::failure;
1161 m_eCurrentDriverState = eDriverState_RunningDebugging;
1163 return MIstatus::success;
1167 //------------------------------------------------------------------------------------
1168 // Details: Prepare the client IDE so it will start working/communicating with
1173 // Return: MIstatus::success - Functionality succeeded.
1174 // MIstatus::failure - Functionality failed.
1177 bool CMIDriver::InitClientIDEToMIDriver() const {
1178 // Put other IDE init functions here
1179 return InitClientIDEEclipse();
1183 //------------------------------------------------------------------------------------
1184 // Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character
1185 // sequence otherwise it refuses to communicate and times out. This
1187 // sent to Eclipse before anything else.
1190 // Return: MIstatus::success - Functionality succeeded.
1191 // MIstatus::failure - Functionality failed.
1194 bool CMIDriver::InitClientIDEEclipse() const {
1195 return CMICmnStreamStdout::WritePrompt();
1199 //------------------------------------------------------------------------------------
1200 // Details: Ask *this driver whether it found an executable in the MI Driver's
1202 // arguments which to open and debug. If so instigate commands to set
1204 // session for that executable.
1207 // Return: bool - True = True = Yes executable given as one of the parameters
1210 // False = not found.
1213 bool CMIDriver::HaveExecutableFileNamePathOnCmdLine() const {
1214 return m_bHaveExecutableFileNamePathOnCmdLine;
1218 //------------------------------------------------------------------------------------
1219 // Details: Retrieve from *this driver executable file name path to start a
1221 // with (if present see HaveExecutableFileNamePathOnCmdLine()).
1224 // Return: CMIUtilString & - Executeable file name path or empty string.
1227 const CMIUtilString &CMIDriver::GetExecutableFileNamePathOnCmdLine() const {
1228 return m_strCmdLineArgExecuteableFileNamePath;
1232 //------------------------------------------------------------------------------------
1233 // Details: Execute commands (by injecting them into the stdin line queue
1235 // other code to set up the MI Driver such that is can take the
1237 // argument passed on the command and create a debug session for it.
1240 // Return: MIstatus::success - Functionality succeeded.
1241 // MIstatus::failure - Functionality failed.
1244 bool CMIDriver::LocalDebugSessionStartupExecuteCommands() {
1245 const CMIUtilString strCmd(CMIUtilString::Format(
1246 "-file-exec-and-symbols \"%s\"",
1247 m_strCmdLineArgExecuteableFileNamePath.AddSlashes().c_str()));
1248 bool bOk = CMICmnStreamStdout::TextToStdout(strCmd);
1249 bOk = bOk && InterpretCommand(strCmd);
1250 bOk = bOk && CMICmnStreamStdout::WritePrompt();
1255 //------------------------------------------------------------------------------------
1256 // Details: Set the MI Driver into "its debugging an executable passed as an
1258 // mode as against running via a client like Eclipse.
1264 void CMIDriver::SetDriverDebuggingArgExecutable() {
1265 m_bDriverDebuggingArgExecutable = true;
1269 //------------------------------------------------------------------------------------
1270 // Details: Retrieve the MI Driver state indicating if it is operating in "its
1272 // an executable passed as an argument" mode as against running via a
1280 bool CMIDriver::IsDriverDebuggingArgExecutable() const {
1281 return m_bDriverDebuggingArgExecutable;
1285 //------------------------------------------------------------------------------------
1286 // Details: Execute commands from command source file in specified mode, and
1287 // set exit-flag if needed.
1289 // Args: vbAsyncMode - (R) True = execute commands in asynchronous
1290 // mode, false = otherwise.
1291 // Return: MIstatus::success - Function succeeded.
1292 // MIstatus::failure - Function failed.
1295 bool CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) {
1296 std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str());
1297 if (!ifsStartScript.is_open()) {
1298 const CMIUtilString errMsg(
1299 CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN),
1300 m_strCmdLineArgCommandFileNamePath.c_str()));
1301 SetErrorDescription(errMsg.c_str());
1302 const bool bForceExit = true;
1303 SetExitApplicationFlag(bForceExit);
1304 return MIstatus::failure;
1307 // Switch lldb to synchronous mode
1308 CMICmnLLDBDebugSessionInfo &rSessionInfo(
1309 CMICmnLLDBDebugSessionInfo::Instance());
1310 const bool bAsyncSetting = rSessionInfo.GetDebugger().GetAsync();
1311 rSessionInfo.GetDebugger().SetAsync(vbAsyncMode);
1313 // Execute commands from file
1314 bool bOk = MIstatus::success;
1315 CMIUtilString strCommand;
1316 while (!m_bExitApp && std::getline(ifsStartScript, strCommand)) {
1318 bOk = CMICmnStreamStdout::TextToStdout(strCommand);
1320 // Skip if it's a comment or empty line
1321 if (strCommand.empty() || strCommand[0] == '#')
1324 // Execute if no error
1326 CMIUtilThreadLock lock(rSessionInfo.GetSessionMutex());
1327 bOk = InterpretCommand(strCommand);
1330 // Draw the prompt after command will be executed (if enabled)
1331 bOk = bOk && CMICmnStreamStdout::WritePrompt();
1333 // Exit if there is an error
1335 const bool bForceExit = true;
1336 SetExitApplicationFlag(bForceExit);
1340 // Wait while the handler thread handles incoming events
1341 CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
1344 // Switch lldb back to initial mode
1345 rSessionInfo.GetDebugger().SetAsync(bAsyncSetting);
1351 //------------------------------------------------------------------------------------
1352 // Details: Gets called when lldb-mi gets a signal. Stops the process if it was
1356 // Args: signal that was delivered
1360 void CMIDriver::DeliverSignal(int signal) {
1361 if (signal == SIGINT &&
1362 (m_eCurrentDriverState == eDriverState_RunningDebugging))
1363 InterpretCommand("-exec-interrupt");