| //===-- MIDriver.cpp --------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // Third party headers: |
| #include "lldb/API/SBError.h" |
| #include <cassert> |
| #include <csignal> |
| #include <fstream> |
| |
| // In-house headers: |
| #include "MICmdArgValFile.h" |
| #include "MICmdArgValString.h" |
| #include "MICmdMgr.h" |
| #include "MICmnConfig.h" |
| #include "MICmnLLDBDebugSessionInfo.h" |
| #include "MICmnLLDBDebugger.h" |
| #include "MICmnLog.h" |
| #include "MICmnMIResultRecord.h" |
| #include "MICmnMIValueConst.h" |
| #include "MICmnResources.h" |
| #include "MICmnStreamStderr.h" |
| #include "MICmnStreamStdout.h" |
| #include "MICmnThreadMgrStd.h" |
| #include "MIDriver.h" |
| #include "MIUtilDebug.h" |
| #include "MIUtilSingletonHelper.h" |
| |
| // Instantiations: |
| #if _DEBUG |
| const CMIUtilString CMIDriver::ms_constMIVersion = |
| MIRSRC(IDS_MI_VERSION_DESCRIPTION_DEBUG); |
| #else |
| const CMIUtilString CMIDriver::ms_constMIVersion = |
| MIRSRC(IDS_MI_VERSION_DESCRIPTION); // Matches version in resources file |
| #endif // _DEBUG |
| const CMIUtilString |
| CMIDriver::ms_constAppNameShort(MIRSRC(IDS_MI_APPNAME_SHORT)); |
| const CMIUtilString CMIDriver::ms_constAppNameLong(MIRSRC(IDS_MI_APPNAME_LONG)); |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: CMIDriver constructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIDriver::CMIDriver() |
| : m_bFallThruToOtherDriverEnabled(false), m_bDriverIsExiting(false), |
| m_handleMainThread(0), m_rStdin(CMICmnStreamStdin::Instance()), |
| m_rLldbDebugger(CMICmnLLDBDebugger::Instance()), |
| m_rStdOut(CMICmnStreamStdout::Instance()), |
| m_eCurrentDriverState(eDriverState_NotRunning), |
| m_bHaveExecutableFileNamePathOnCmdLine(false), |
| m_bDriverDebuggingArgExecutable(false), |
| m_bHaveCommandFileNamePathOnCmdLine(false) {} |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: CMIDriver destructor. |
| // Type: Overridden. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIDriver::~CMIDriver() {} |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Set whether *this driver (the parent) is enabled to pass a command |
| // to its |
| // fall through (child) driver to interpret the command and do work |
| // instead |
| // (if *this driver decides it can't handle the command). |
| // Type: Method. |
| // Args: vbYes - (R) True = yes fall through, false = do not pass on |
| // command. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetEnableFallThru(const bool vbYes) { |
| m_bFallThruToOtherDriverEnabled = vbYes; |
| return MIstatus::success; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Get whether *this driver (the parent) is enabled to pass a command |
| // to its |
| // fall through (child) driver to interpret the command and do work |
| // instead |
| // (if *this driver decides it can't handle the command). |
| // Type: Method. |
| // Args: None. |
| // Return: bool - True = yes fall through, false = do not pass on command. |
| // Throws: None. |
| //-- |
| bool CMIDriver::GetEnableFallThru() const { |
| return m_bFallThruToOtherDriverEnabled; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve MI's application name of itself. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetAppNameShort() const { |
| return ms_constAppNameShort; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve MI's application name of itself. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetAppNameLong() const { |
| return ms_constAppNameLong; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve MI's version description of itself. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetVersionDescription() const { |
| return ms_constMIVersion; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Initialize setup *this driver ready for use. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::Initialize() { |
| m_eCurrentDriverState = eDriverState_Initialising; |
| m_clientUsageRefCnt++; |
| |
| ClrErrorDescription(); |
| |
| if (m_bInitialized) |
| return MIstatus::success; |
| |
| bool bOk = MIstatus::success; |
| CMIUtilString errMsg; |
| |
| // Initialize all of the modules we depend on |
| MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); |
| MI::ModuleInit<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, errMsg); |
| MI::ModuleInit<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, errMsg); |
| MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); |
| MI::ModuleInit<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk, |
| errMsg); |
| MI::ModuleInit<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, errMsg); |
| MI::ModuleInit<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg); |
| bOk &= m_rLldbDebugger.SetDriver(*this); |
| MI::ModuleInit<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, errMsg); |
| |
| m_bExitApp = false; |
| |
| m_bInitialized = bOk; |
| |
| if (!bOk) { |
| const CMIUtilString msg = |
| CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_DRIVER), errMsg.c_str()); |
| SetErrorDescription(msg); |
| return MIstatus::failure; |
| } |
| |
| m_eCurrentDriverState = eDriverState_RunningNotDebugging; |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Unbind detach or release resources used by *this driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::Shutdown() { |
| if (--m_clientUsageRefCnt > 0) |
| return MIstatus::success; |
| |
| if (!m_bInitialized) |
| return MIstatus::success; |
| |
| m_eCurrentDriverState = eDriverState_ShuttingDown; |
| |
| ClrErrorDescription(); |
| |
| bool bOk = MIstatus::success; |
| CMIUtilString errMsg; |
| |
| // Shutdown all of the modules we depend on |
| MI::ModuleShutdown<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, |
| errMsg); |
| MI::ModuleShutdown<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg); |
| MI::ModuleShutdown<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, |
| errMsg); |
| MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk, |
| errMsg); |
| MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); |
| MI::ModuleShutdown<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, |
| errMsg); |
| MI::ModuleShutdown<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, |
| errMsg); |
| MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); |
| |
| if (!bOk) { |
| SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str()); |
| } |
| |
| m_eCurrentDriverState = eDriverState_NotRunning; |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Work function. Client (the driver's user) is able to append their |
| // own message |
| // in to the MI's Log trace file. |
| // Type: Method. |
| // Args: vMessage - (R) Client's text message. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::WriteMessageToLog(const CMIUtilString &vMessage) { |
| CMIUtilString msg; |
| msg = CMIUtilString::Format(MIRSRC(IDS_MI_CLIENT_MSG), vMessage.c_str()); |
| return m_pLog->Write(msg, CMICmnLog::eLogVerbosity_ClientMsg); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: CDriverMgr calls *this driver initialize setup ready for use. |
| // Type: Overridden. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoInitialize() { return CMIDriver::Instance().Initialize(); } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: CDriverMgr calls *this driver to unbind detach or release resources |
| // used by |
| // *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoShutdown() { return CMIDriver::Instance().Shutdown(); } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve the name for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Driver name. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetName() const { |
| const CMIUtilString &rName = GetAppNameLong(); |
| const CMIUtilString &rVsn = GetVersionDescription(); |
| static CMIUtilString strName = |
| CMIUtilString::Format("%s %s", rName.c_str(), rVsn.c_str()); |
| |
| return strName; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve *this driver's last error condition. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString - Text description. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIDriver::GetError() const { return GetErrorDescription(); } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Call *this driver to return it's debugger. |
| // Type: Overridden. |
| // Args: None. |
| // Return: lldb::SBDebugger & - LLDB debugger object reference. |
| // Throws: None. |
| //-- |
| lldb::SBDebugger &CMIDriver::GetTheDebugger() { |
| return m_rLldbDebugger.GetTheDebugger(); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Specify another driver *this driver can call should this driver not |
| // be able |
| // to handle the client data input. DoFallThruToAnotherDriver() makes |
| // the call. |
| // Type: Overridden. |
| // Args: vrOtherDriver - (R) Reference to another driver object. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetDriverToFallThruTo(const CMIDriverBase &vrOtherDriver) { |
| m_pDriverFallThru = const_cast<CMIDriverBase *>(&vrOtherDriver); |
| |
| return m_pDriverFallThru->SetDriverParent(*this); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this |
| // driver's |
| // implementation called from here to match the existing function name |
| // of the |
| // original LLDB driver class (the extra indirection is not necessarily |
| // required). |
| // Check the arguments that were passed to this program to make sure |
| // they are |
| // valid and to get their argument values (if any). |
| // Type: Overridden. |
| // Args: argc - (R) An integer that contains the count of arguments |
| // that follow in |
| // argv. The argc parameter is always greater than |
| // or equal to 1. |
| // argv - (R) An array of null-terminated strings representing |
| // command-line |
| // arguments entered by the user of the program. By |
| // convention, |
| // argv[0] is the command with which the program is |
| // invoked. |
| // vpStdOut - (R) Pointer to a standard output stream. |
| // vwbExiting - (W) True = *this want to exit, Reasons: help, |
| // invalid arg(s), |
| // version information only. |
| // False = Continue to work, start debugger i.e. |
| // Command |
| // interpreter. |
| // Return: lldb::SBError - LLDB current error status. |
| // Throws: None. |
| //-- |
| lldb::SBError CMIDriver::DoParseArgs(const int argc, const char *argv[], |
| FILE *vpStdOut, bool &vwbExiting) { |
| return ParseArgs(argc, argv, vpStdOut, vwbExiting); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Check the arguments that were passed to this program to make sure |
| // they are |
| // valid and to get their argument values (if any). The following are |
| // options |
| // that are only handled by *this driver: |
| // --executable <file> |
| // --source <file> or -s <file> |
| // --synchronous |
| // The application's options --interpreter and --executable in code act |
| // very similar. |
| // The --executable is necessary to differentiate whether the MI Driver |
| // is being |
| // used by a client (e.g. Eclipse) or from the command line. Eclipse |
| // issues the option |
| // --interpreter and also passes additional arguments which can be |
| // interpreted as an |
| // executable if called from the command line. Using --executable tells |
| // the MI Driver |
| // it is being called from the command line and to prepare to launch |
| // the executable |
| // argument for a debug session. Using --interpreter on the command |
| // line does not |
| // issue additional commands to initialise a debug session. |
| // Option --synchronous disables an asynchronous mode in the lldb-mi driver. |
| // Type: Overridden. |
| // Args: argc - (R) An integer that contains the count of arguments |
| // that follow in |
| // argv. The argc parameter is always greater than |
| // or equal to 1. |
| // argv - (R) An array of null-terminated strings representing |
| // command-line |
| // arguments entered by the user of the program. By |
| // convention, |
| // argv[0] is the command with which the program is |
| // invoked. |
| // vpStdOut - (R) Pointer to a standard output stream. |
| // vwbExiting - (W) True = *this want to exit, Reasons: help, |
| // invalid arg(s), |
| // version information only. |
| // False = Continue to work, start debugger i.e. |
| // Command |
| // interpreter. |
| // Return: lldb::SBError - LLDB current error status. |
| // Throws: None. |
| //-- |
| lldb::SBError CMIDriver::ParseArgs(const int argc, const char *argv[], |
| FILE *vpStdOut, bool &vwbExiting) { |
| lldb::SBError errStatus; |
| const bool bHaveArgs(argc >= 2); |
| |
| // *** Add any args handled here to GetHelpOnCmdLineArgOptions() *** |
| |
| // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING |
| // Look for the command line options |
| bool bHaveExecutableFileNamePath = false; |
| bool bHaveExecutableLongOption = false; |
| |
| if (bHaveArgs) { |
| // Search right to left to look for filenames |
| for (MIint i = argc - 1; i > 0; i--) { |
| const CMIUtilString strArg(argv[i]); |
| const CMICmdArgValFile argFile; |
| |
| // Check for a filename |
| if (argFile.IsFilePath(strArg) || |
| CMICmdArgValString(true, false, true).IsStringArg(strArg)) { |
| // Is this the command file for the '-s' or '--source' options? |
| const CMIUtilString strPrevArg(argv[i - 1]); |
| if (strPrevArg.compare("-s") == 0 || |
| strPrevArg.compare("--source") == 0) { |
| m_strCmdLineArgCommandFileNamePath = strArg; |
| m_bHaveCommandFileNamePathOnCmdLine = true; |
| i--; // skip '-s' on the next loop |
| continue; |
| } |
| // Else, must be the executable |
| bHaveExecutableFileNamePath = true; |
| m_strCmdLineArgExecuteableFileNamePath = strArg; |
| m_bHaveExecutableFileNamePathOnCmdLine = true; |
| } |
| // Report error if no command file was specified for the '-s' or |
| // '--source' options |
| else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) { |
| vwbExiting = true; |
| const CMIUtilString errMsg = CMIUtilString::Format( |
| MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str()); |
| errStatus.SetErrorString(errMsg.c_str()); |
| break; |
| } |
| // This argument is also checked for in CMIDriverMgr::ParseArgs() |
| else if (strArg.compare("--executable") == 0) // Used to specify that |
| // there is executable |
| // argument also on the |
| // command line |
| { // See fn description. |
| bHaveExecutableLongOption = true; |
| } else if (strArg.compare("--synchronous") == 0) { |
| CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().SetAsync(false); |
| } |
| } |
| } |
| |
| if (bHaveExecutableFileNamePath && bHaveExecutableLongOption) { |
| SetDriverDebuggingArgExecutable(); |
| } |
| |
| return errStatus; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: A client can ask if *this driver is GDB/MI compatible. |
| // Type: Overridden. |
| // Args: None. |
| // Return: True - GBD/MI compatible LLDB front end. |
| // False - Not GBD/MI compatible LLDB front end. |
| // Throws: None. |
| //-- |
| bool CMIDriver::GetDriverIsGDBMICompatibleDriver() const { return true; } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Start worker threads for the driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::StartWorkerThreads() { |
| bool bOk = MIstatus::success; |
| |
| // Grab the thread manager |
| CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance(); |
| |
| // Start the event polling thread |
| if (bOk && !rThreadMgr.ThreadStart<CMICmnLLDBDebugger>(m_rLldbDebugger)) { |
| const CMIUtilString errMsg = CMIUtilString::Format( |
| MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE), |
| CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str()); |
| SetErrorDescription(errMsg); |
| return MIstatus::failure; |
| } |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Stop worker threads for the driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::StopWorkerThreads() { |
| CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance(); |
| return rThreadMgr.ThreadAllTerminate(); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Call this function puts *this driver to work. |
| // This function is used by the application's main thread. |
| // Type: Overridden. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoMainLoop() { |
| if (!InitClientIDEToMIDriver()) // Init Eclipse IDE |
| { |
| SetErrorDescriptionn(MIRSRC(IDS_MI_INIT_ERR_CLIENT_USING_DRIVER)); |
| return MIstatus::failure; |
| } |
| |
| if (!StartWorkerThreads()) |
| return MIstatus::failure; |
| |
| bool bOk = MIstatus::success; |
| |
| if (HaveExecutableFileNamePathOnCmdLine()) { |
| if (!LocalDebugSessionStartupExecuteCommands()) { |
| SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION)); |
| bOk = MIstatus::failure; |
| } |
| } |
| |
| // App is not quitting currently |
| m_bExitApp = false; |
| |
| // Handle source file |
| if (m_bHaveCommandFileNamePathOnCmdLine) { |
| const bool bAsyncMode = false; |
| ExecuteCommandFile(bAsyncMode); |
| } |
| |
| // While the app is active |
| while (bOk && !m_bExitApp) { |
| CMIUtilString errorText; |
| const char *pCmd = m_rStdin.ReadLine(errorText); |
| if (pCmd != nullptr) { |
| CMIUtilString lineText(pCmd); |
| if (!lineText.empty()) { |
| // Check that the handler thread is alive (otherwise we stuck here) |
| assert(CMICmnLLDBDebugger::Instance().ThreadIsActive()); |
| |
| { |
| // Lock Mutex before processing commands so that we don't disturb an |
| // event |
| // being processed |
| CMIUtilThreadLock lock( |
| CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex()); |
| bOk = InterpretCommand(lineText); |
| } |
| |
| // Draw prompt if desired |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| |
| // Wait while the handler thread handles incoming events |
| CMICmnLLDBDebugger::Instance().WaitForHandleEvent(); |
| } |
| } |
| } |
| |
| // Signal that the application is shutting down |
| DoAppQuit(); |
| |
| // Close and wait for the workers to stop |
| StopWorkerThreads(); |
| |
| return MIstatus::success; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Set things in motion, set state etc that brings *this driver (and |
| // the |
| // application) to a tidy shutdown. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoAppQuit() { |
| bool bYesQuit = true; |
| |
| // Shutdown stuff, ready app for exit |
| { |
| CMIUtilThreadLock lock(m_threadMutex); |
| m_bDriverIsExiting = true; |
| } |
| |
| return bYesQuit; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: *this driver passes text commands to a fall through driver is it |
| // does not |
| // understand them (the LLDB driver). |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vTextLine - (R) Text data representing a possible command. |
| // vwbCmdYesValid - (W) True = Command valid, false = command not |
| // handled. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InterpretCommandFallThruDriver(const CMIUtilString &vTextLine, |
| bool &vwbCmdYesValid) { |
| MIunused(vTextLine); |
| MIunused(vwbCmdYesValid); |
| |
| // ToDo: Implement when less urgent work to be done or decide remove as not |
| // required |
| // bool bOk = MIstatus::success; |
| // bool bCmdNotUnderstood = true; |
| // if( bCmdNotUnderstood && GetEnableFallThru() ) |
| //{ |
| // CMIUtilString errMsg; |
| // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg ); |
| // if( !bOk ) |
| // { |
| // errMsg = errMsg.StripCREndOfLine(); |
| // errMsg = errMsg.StripCRAll(); |
| // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo(); |
| // const char * pName = pOtherDriver->GetDriverName().c_str(); |
| // const char * pId = pOtherDriver->GetDriverId().c_str(); |
| // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( |
| // IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() ) |
| //); |
| // m_pLog->WriteMsg( msg ); |
| // } |
| //} |
| // |
| // vwbCmdYesValid = bOk; |
| // CMIUtilString strNot; |
| // if( vwbCmdYesValid) |
| // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) ); |
| // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( |
| // IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) ); |
| // m_pLog->WriteLog( msg ); |
| |
| return MIstatus::success; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve the name for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Driver name. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetDriverName() const { return GetName(); } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Get the unique ID for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetDriverId() const { return GetId(); } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: This function allows *this driver to call on another driver to |
| // perform work |
| // should this driver not be able to handle the client data input. |
| // SetDriverToFallThruTo() specifies the fall through to driver. |
| // Check the error message if the function returns a failure. |
| // Type: Overridden. |
| // Args: vCmd - (R) Command instruction to interpret. |
| // vwErrMsg - (W) Status description on command failing. |
| // Return: MIstatus::success - Command succeeded. |
| // MIstatus::failure - Command failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::DoFallThruToAnotherDriver(const CMIUtilString &vCmd, |
| CMIUtilString &vwErrMsg) { |
| bool bOk = MIstatus::success; |
| |
| CMIDriverBase *pOtherDriver = GetDriverToFallThruTo(); |
| if (pOtherDriver == nullptr) |
| return bOk; |
| |
| return pOtherDriver->DoFallThruToAnotherDriver(vCmd, vwErrMsg); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: *this driver provides a file stream to other drivers on which *this |
| // driver |
| // write's out to and they read as expected input. *this driver is |
| // passing |
| // through commands to the (child) pass through assigned driver. |
| // Type: Overrdidden. |
| // Args: None. |
| // Return: FILE * - Pointer to stream. |
| // Throws: None. |
| //-- |
| FILE *CMIDriver::GetStdin() const { |
| // Note this fn is called on CMIDriverMgr register driver so stream has to be |
| // available before *this driver has been initialized! Flaw? |
| |
| // This very likely to change later to a stream that the pass thru driver |
| // will read and we write to give it 'input' |
| return stdin; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: *this driver provides a file stream to other pass through assigned |
| // drivers |
| // so they know what to write to. |
| // Type: Overidden. |
| // Args: None. |
| // Return: FILE * - Pointer to stream. |
| // Throws: None. |
| //-- |
| FILE *CMIDriver::GetStdout() const { |
| // Note this fn is called on CMIDriverMgr register driver so stream has to be |
| // available before *this driver has been initialized! Flaw? |
| |
| // Do not want to pass through driver to write to stdout |
| return NULL; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: *this driver provides a error file stream to other pass through |
| // assigned drivers |
| // so they know what to write to. |
| // Type: Overidden. |
| // Args: None. |
| // Return: FILE * - Pointer to stream. |
| // Throws: None. |
| //-- |
| FILE *CMIDriver::GetStderr() const { |
| // Note this fn is called on CMIDriverMgr register driver so stream has to be |
| // available before *this driver has been initialized! Flaw? |
| |
| // This very likely to change later to a stream that the pass thru driver |
| // will write to and *this driver reads from to pass on the CMICmnLog object |
| return stderr; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Set a unique ID for *this driver. It cannot be empty. |
| // Type: Overridden. |
| // Args: vId - (R) Text description. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetId(const CMIUtilString &vId) { |
| if (vId.empty()) { |
| SetErrorDescriptionn(MIRSRC(IDS_DRIVER_ERR_ID_INVALID), GetName().c_str(), |
| vId.c_str()); |
| return MIstatus::failure; |
| } |
| |
| m_strDriverId = vId; |
| return MIstatus::success; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Get the unique ID for *this driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: CMIUtilString & - Text description. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetId() const { return m_strDriverId; } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Interpret the text data and match against current commands to see if |
| // there |
| // is a match. If a match then the command is issued and actioned on. |
| // The |
| // text data if not understood by *this driver is past on to the Fall |
| // Thru |
| // driver. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vTextLine - (R) Text data representing a possible command. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InterpretCommand(const CMIUtilString &vTextLine) { |
| const bool bNeedToRebroadcastStopEvent = |
| m_rLldbDebugger.CheckIfNeedToRebroadcastStopEvent(); |
| bool bCmdYesValid = false; |
| bool bOk = InterpretCommandThisDriver(vTextLine, bCmdYesValid); |
| if (bOk && !bCmdYesValid) |
| bOk = InterpretCommandFallThruDriver(vTextLine, bCmdYesValid); |
| |
| if (bNeedToRebroadcastStopEvent) |
| m_rLldbDebugger.RebroadcastStopEvent(); |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Helper function for CMIDriver::InterpretCommandThisDriver. |
| // Convert a CLI command to MI command (just wrap any CLI command |
| // into "<tokens>-interpreter-exec command \"<CLI command>\""). |
| // Type: Method. |
| // Args: vTextLine - (R) Text data representing a possible command. |
| // Return: CMIUtilString - The original MI command or converted CLI command. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| CMIUtilString |
| CMIDriver::WrapCLICommandIntoMICommand(const CMIUtilString &vTextLine) const { |
| // Tokens contain following digits |
| static const CMIUtilString digits("0123456789"); |
| |
| // Consider an algorithm on the following example: |
| // 001-file-exec-and-symbols "/path/to/file" |
| // |
| // 1. Skip a command token |
| // For example: |
| // 001-file-exec-and-symbols "/path/to/file" |
| // 001target create "/path/to/file" |
| // ^ -- command starts here (in both cases) |
| // Also possible case when command not found: |
| // 001 |
| // ^ -- i.e. only tokens are present (or empty string at all) |
| const size_t nCommandOffset = vTextLine.find_first_not_of(digits); |
| |
| // 2. Check if command is empty |
| // For example: |
| // 001-file-exec-and-symbols "/path/to/file" |
| // 001target create "/path/to/file" |
| // ^ -- command not empty (in both cases) |
| // or: |
| // 001 |
| // ^ -- command wasn't found |
| const bool bIsEmptyCommand = (nCommandOffset == CMIUtilString::npos); |
| |
| // 3. Check and exit if it isn't a CLI command |
| // For example: |
| // 001-file-exec-and-symbols "/path/to/file" |
| // 001 |
| // ^ -- it isn't CLI command (in both cases) |
| // or: |
| // 001target create "/path/to/file" |
| // ^ -- it's CLI command |
| const bool bIsCliCommand = |
| !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-'); |
| if (!bIsCliCommand) |
| return vTextLine; |
| |
| // 4. Wrap CLI command to make it MI-compatible |
| // |
| // 001target create "/path/to/file" |
| // ^^^ -- token |
| const std::string vToken(vTextLine.begin(), |
| vTextLine.begin() + nCommandOffset); |
| // 001target create "/path/to/file" |
| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- CLI command |
| const CMIUtilString vCliCommand(std::string(vTextLine, nCommandOffset)); |
| |
| // 5. Escape special characters and embed the command in a string |
| // Result: it looks like -- target create \"/path/to/file\". |
| const std::string vShieldedCliCommand(vCliCommand.AddSlashes()); |
| |
| // 6. Turn the CLI command into an MI command, as in: |
| // 001-interpreter-exec command "target create \"/path/to/file\"" |
| // ^^^ -- token |
| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ -- wrapper |
| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- shielded |
| // CLI command |
| return CMIUtilString::Format("%s-interpreter-exec command \"%s\"", |
| vToken.c_str(), vShieldedCliCommand.c_str()); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Interpret the text data and match against current commands to see if |
| // there |
| // is a match. If a match then the command is issued and actioned on. |
| // If a |
| // command cannot be found to match then vwbCmdYesValid is set to false |
| // and |
| // nothing else is done here. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vTextLine - (R) Text data representing a possible command. |
| // vwbCmdYesValid - (W) True = Command valid, false = command not |
| // handled. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, |
| bool &vwbCmdYesValid) { |
| // Convert any CLI commands into MI commands |
| const CMIUtilString vMITextLine(WrapCLICommandIntoMICommand(vTextLine)); |
| |
| vwbCmdYesValid = false; |
| bool bCmdNotInCmdFactor = false; |
| SMICmdData cmdData; |
| CMICmdMgr &rCmdMgr = CMICmdMgr::Instance(); |
| if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor, |
| cmdData)) |
| return MIstatus::failure; |
| |
| if (vwbCmdYesValid) { |
| // For debugging only |
| // m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() ); |
| |
| return ExecuteCommand(cmdData); |
| } |
| |
| // Check for escape character, may be cursor control characters |
| // This code is not necessary for application operation, just want to keep |
| // tabs on what |
| // has been given to the driver to try and interpret. |
| if (vMITextLine.at(0) == 27) { |
| CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS)); |
| for (MIuint i = 0; i < vMITextLine.length(); i++) { |
| logInput += CMIUtilString::Format("%d ", vMITextLine.at(i)); |
| } |
| m_pLog->WriteLog(logInput); |
| return MIstatus::success; |
| } |
| |
| // Write to the Log that a 'command' was not valid. |
| // Report back to the MI client via MI result record. |
| CMIUtilString strNotInCmdFactory; |
| if (bCmdNotInCmdFactor) |
| strNotInCmdFactory = CMIUtilString::Format( |
| MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str()); |
| const CMIUtilString strNot( |
| CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT))); |
| const CMIUtilString msg(CMIUtilString::Format( |
| MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(), |
| strNotInCmdFactory.c_str())); |
| const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg); |
| const CMICmnMIValueResult valueResult("msg", vconst); |
| const CMICmnMIResultRecord miResultRecord( |
| cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, |
| valueResult); |
| const bool bOk = m_rStdOut.WriteMIResponse(miResultRecord.GetString()); |
| |
| // Proceed to wait for or execute next command |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Having previously had the potential command validated and found |
| // valid now |
| // get the command executed. |
| // This function is used by the application's main thread. |
| // Type: Method. |
| // Args: vCmdData - (RW) Command meta data. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::ExecuteCommand(const SMICmdData &vCmdData) { |
| CMICmdMgr &rCmdMgr = CMICmdMgr::Instance(); |
| return rCmdMgr.CmdExecute(vCmdData); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Set the MI Driver's exit application flag. The application checks |
| // this flag |
| // after every stdin line is read so the exit may not be instantaneous. |
| // If vbForceExit is false the MI Driver queries its state and |
| // determines if is |
| // should exit or continue operating depending on that running state. |
| // This is related to the running state of the MI driver. |
| // Type: Overridden. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| void CMIDriver::SetExitApplicationFlag(const bool vbForceExit) { |
| if (vbForceExit) { |
| CMIUtilThreadLock lock(m_threadMutex); |
| m_bExitApp = true; |
| return; |
| } |
| |
| // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM |
| // Did we receive a SIGINT from the client during a running debug program, if |
| // so then SIGINT is not to be taken as meaning kill the MI driver application |
| // but halt the inferior program being debugged instead |
| if (m_eCurrentDriverState == eDriverState_RunningDebugging) { |
| InterpretCommand("-exec-interrupt"); |
| return; |
| } |
| |
| m_bExitApp = true; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Get the MI Driver's exit exit application flag. |
| // This is related to the running state of the MI driver. |
| // Type: Method. |
| // Args: None. |
| // Return: bool - True = MI Driver is shutting down, false = MI driver is |
| // running. |
| // Throws: None. |
| //-- |
| bool CMIDriver::GetExitApplicationFlag() const { return m_bExitApp; } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Get the current running state of the MI Driver. |
| // Type: Method. |
| // Args: None. |
| // Return: DriverState_e - The current running state of the application. |
| // Throws: None. |
| //-- |
| CMIDriver::DriverState_e CMIDriver::GetCurrentDriverState() const { |
| return m_eCurrentDriverState; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Set the current running state of the MI Driver to running and |
| // currently not in |
| // a debug session. |
| // Type: Method. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Return: DriverState_e - The current running state of the application. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetDriverStateRunningNotDebugging() { |
| // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM |
| |
| if (m_eCurrentDriverState == eDriverState_RunningNotDebugging) |
| return MIstatus::success; |
| |
| // Driver cannot be in the following states to set |
| // eDriverState_RunningNotDebugging |
| switch (m_eCurrentDriverState) { |
| case eDriverState_NotRunning: |
| case eDriverState_Initialising: |
| case eDriverState_ShuttingDown: { |
| SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR)); |
| return MIstatus::failure; |
| } |
| case eDriverState_RunningDebugging: |
| case eDriverState_RunningNotDebugging: |
| break; |
| case eDriverState_count: |
| SetErrorDescription( |
| CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE), |
| "SetDriverStateRunningNotDebugging()")); |
| return MIstatus::failure; |
| } |
| |
| // Driver must be in this state to set eDriverState_RunningNotDebugging |
| if (m_eCurrentDriverState != eDriverState_RunningDebugging) { |
| SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR)); |
| return MIstatus::failure; |
| } |
| |
| m_eCurrentDriverState = eDriverState_RunningNotDebugging; |
| |
| return MIstatus::success; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Set the current running state of the MI Driver to running and |
| // currently not in |
| // a debug session. The driver's state must in the state running and in |
| // a |
| // debug session to set this new state. |
| // Type: Method. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Return: DriverState_e - The current running state of the application. |
| // Throws: None. |
| //-- |
| bool CMIDriver::SetDriverStateRunningDebugging() { |
| // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM |
| |
| if (m_eCurrentDriverState == eDriverState_RunningDebugging) |
| return MIstatus::success; |
| |
| // Driver cannot be in the following states to set |
| // eDriverState_RunningDebugging |
| switch (m_eCurrentDriverState) { |
| case eDriverState_NotRunning: |
| case eDriverState_Initialising: |
| case eDriverState_ShuttingDown: { |
| SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR)); |
| return MIstatus::failure; |
| } |
| case eDriverState_RunningDebugging: |
| case eDriverState_RunningNotDebugging: |
| break; |
| case eDriverState_count: |
| SetErrorDescription( |
| CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE), |
| "SetDriverStateRunningDebugging()")); |
| return MIstatus::failure; |
| } |
| |
| // Driver must be in this state to set eDriverState_RunningDebugging |
| if (m_eCurrentDriverState != eDriverState_RunningNotDebugging) { |
| SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR)); |
| return MIstatus::failure; |
| } |
| |
| m_eCurrentDriverState = eDriverState_RunningDebugging; |
| |
| return MIstatus::success; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Prepare the client IDE so it will start working/communicating with |
| // *this MI |
| // driver. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InitClientIDEToMIDriver() const { |
| // Put other IDE init functions here |
| return InitClientIDEEclipse(); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character |
| // sequence otherwise it refuses to communicate and times out. This |
| // should be |
| // sent to Eclipse before anything else. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::InitClientIDEEclipse() const { |
| return CMICmnStreamStdout::WritePrompt(); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Ask *this driver whether it found an executable in the MI Driver's |
| // list of |
| // arguments which to open and debug. If so instigate commands to set |
| // up a debug |
| // session for that executable. |
| // Type: Method. |
| // Args: None. |
| // Return: bool - True = True = Yes executable given as one of the parameters |
| // to the MI |
| // Driver. |
| // False = not found. |
| // Throws: None. |
| //-- |
| bool CMIDriver::HaveExecutableFileNamePathOnCmdLine() const { |
| return m_bHaveExecutableFileNamePathOnCmdLine; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve from *this driver executable file name path to start a |
| // debug session |
| // with (if present see HaveExecutableFileNamePathOnCmdLine()). |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString & - Executeable file name path or empty string. |
| // Throws: None. |
| //-- |
| const CMIUtilString &CMIDriver::GetExecutableFileNamePathOnCmdLine() const { |
| return m_strCmdLineArgExecuteableFileNamePath; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Execute commands (by injecting them into the stdin line queue |
| // container) and |
| // other code to set up the MI Driver such that is can take the |
| // executable |
| // argument passed on the command and create a debug session for it. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::LocalDebugSessionStartupExecuteCommands() { |
| const CMIUtilString strCmd(CMIUtilString::Format( |
| "-file-exec-and-symbols \"%s\"", |
| m_strCmdLineArgExecuteableFileNamePath.AddSlashes().c_str())); |
| bool bOk = CMICmnStreamStdout::TextToStdout(strCmd); |
| bOk = bOk && InterpretCommand(strCmd); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Set the MI Driver into "its debugging an executable passed as an |
| // argument" |
| // mode as against running via a client like Eclipse. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| void CMIDriver::SetDriverDebuggingArgExecutable() { |
| m_bDriverDebuggingArgExecutable = true; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Retrieve the MI Driver state indicating if it is operating in "its |
| // debugging |
| // an executable passed as an argument" mode as against running via a |
| // client |
| // like Eclipse. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| bool CMIDriver::IsDriverDebuggingArgExecutable() const { |
| return m_bDriverDebuggingArgExecutable; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Execute commands from command source file in specified mode, and |
| // set exit-flag if needed. |
| // Type: Method. |
| // Args: vbAsyncMode - (R) True = execute commands in asynchronous |
| // mode, false = otherwise. |
| // Return: MIstatus::success - Function succeeded. |
| // MIstatus::failure - Function failed. |
| // Throws: None. |
| //-- |
| bool CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) { |
| std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str()); |
| if (!ifsStartScript.is_open()) { |
| const CMIUtilString errMsg( |
| CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN), |
| m_strCmdLineArgCommandFileNamePath.c_str())); |
| SetErrorDescription(errMsg.c_str()); |
| const bool bForceExit = true; |
| SetExitApplicationFlag(bForceExit); |
| return MIstatus::failure; |
| } |
| |
| // Switch lldb to synchronous mode |
| CMICmnLLDBDebugSessionInfo &rSessionInfo( |
| CMICmnLLDBDebugSessionInfo::Instance()); |
| const bool bAsyncSetting = rSessionInfo.GetDebugger().GetAsync(); |
| rSessionInfo.GetDebugger().SetAsync(vbAsyncMode); |
| |
| // Execute commands from file |
| bool bOk = MIstatus::success; |
| CMIUtilString strCommand; |
| while (!m_bExitApp && std::getline(ifsStartScript, strCommand)) { |
| // Print command |
| bOk = CMICmnStreamStdout::TextToStdout(strCommand); |
| |
| // Skip if it's a comment or empty line |
| if (strCommand.empty() || strCommand[0] == '#') |
| continue; |
| |
| // Execute if no error |
| if (bOk) { |
| CMIUtilThreadLock lock(rSessionInfo.GetSessionMutex()); |
| bOk = InterpretCommand(strCommand); |
| } |
| |
| // Draw the prompt after command will be executed (if enabled) |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| |
| // Exit if there is an error |
| if (!bOk) { |
| const bool bForceExit = true; |
| SetExitApplicationFlag(bForceExit); |
| break; |
| } |
| |
| // Wait while the handler thread handles incoming events |
| CMICmnLLDBDebugger::Instance().WaitForHandleEvent(); |
| } |
| |
| // Switch lldb back to initial mode |
| rSessionInfo.GetDebugger().SetAsync(bAsyncSetting); |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Gets called when lldb-mi gets a signal. Stops the process if it was |
| // SIGINT. |
| // |
| // Type: Method. |
| // Args: signal that was delivered |
| // Return: None. |
| // Throws: None. |
| //-- |
| void CMIDriver::DeliverSignal(int signal) { |
| if (signal == SIGINT && |
| (m_eCurrentDriverState == eDriverState_RunningDebugging)) |
| InterpretCommand("-exec-interrupt"); |
| } |